bridgerator 1.1.0 → 1.1.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 +176 -172
- package/install.ps1 +5 -4
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/src/bridge.mjs +14 -3
- package/src/extra-tools.mjs +2 -0
- package/src/notice.mjs +5 -0
- package/src/pc-text.mjs +27 -1
- package/src/queue.mjs +13 -5
- package/src/settings-tool.mjs +2 -2
- package/ui/app.js +1 -1
- package/ui/i18n/en.json +3 -1
- package/ui/i18n/ru.json +3 -1
package/README.md
CHANGED
|
@@ -1,172 +1,176 @@
|
|
|
1
|
-
# Bridgerator
|
|
2
|
-
|
|
3
|
-
Connect your Windows PC to ChatGPT. The assistant can read and edit files, search folders and run
|
|
4
|
-
PowerShell commands on **your** computer — through a bridge that only makes an **outbound**
|
|
5
|
-
connection. No inbound ports, no remote-desktop software.
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
ChatGPT ──OAuth 2.1 + MCP (HTTPS)──► relay (mcp.bridgerator.recondeck.com) ──WebSocket──► bridgerator on your PC ──stdio──► bundled MCP engine
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
This repository is the part that runs on your PC. It is small on purpose so you (or an AI agent
|
|
12
|
-
installing it for you) can read all of it: `src/bridge.mjs` (forwarder), `src/policy.mjs` (access
|
|
13
|
-
rules), `src/dc-isolate.mjs` (separate engine config), `src/cli.mjs` (setup/autostart), `src/pair.mjs` (browser pairing), `install.ps1` (installer).
|
|
14
|
-
|
|
15
|
-
## What people use it for
|
|
16
|
-
|
|
17
|
-
- "Sort my Downloads folder by type and month" — ChatGPT lists, plans and moves the files on your PC.
|
|
18
|
-
- "Find every invoice PDF in Documents and rename it by date" — search and rename in plain words.
|
|
19
|
-
- "Why is drive C almost full?" — disk usage, big folders, what is safe to delete.
|
|
20
|
-
- "Check the event log for errors since yesterday" / "Read the end of this log" — diagnostics.
|
|
21
|
-
- Work on code: "explain how D:\\Projects\\app is built and run its tests".
|
|
22
|
-
|
|
23
|
-
Everything runs as your Windows user and only inside the folders you allow.
|
|
24
|
-
|
|
25
|
-
## Plans
|
|
26
|
-
|
|
27
|
-
Free: 10,000 tool calls per month per account, any number of PCs. Pro: $10/month, unlimited.
|
|
28
|
-
Details: https://bridgerator.recondeck.com/pricing
|
|
29
|
-
|
|
30
|
-
## Install (Windows)
|
|
31
|
-
|
|
32
|
-
1.
|
|
33
|
-
2.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
|
58
|
-
|
|
59
|
-
| `
|
|
60
|
-
| `
|
|
61
|
-
| `
|
|
62
|
-
| `
|
|
63
|
-
| `
|
|
64
|
-
| `
|
|
65
|
-
| `
|
|
66
|
-
| `
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
and
|
|
80
|
-
|
|
81
|
-
`
|
|
82
|
-
|
|
83
|
-
The
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
|
119
|
-
|
|
120
|
-
| `
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
bridgerator.cmd
|
|
134
|
-
|
|
135
|
-
bridgerator.cmd
|
|
136
|
-
bridgerator.cmd
|
|
137
|
-
bridgerator.cmd
|
|
138
|
-
bridgerator.cmd
|
|
139
|
-
bridgerator.cmd
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
`
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
1
|
+
# Bridgerator
|
|
2
|
+
|
|
3
|
+
Connect your Windows PC to ChatGPT. The assistant can read and edit files, search folders and run
|
|
4
|
+
PowerShell commands on **your** computer — through a bridge that only makes an **outbound**
|
|
5
|
+
connection. No inbound ports, no remote-desktop software.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
ChatGPT ──OAuth 2.1 + MCP (HTTPS)──► relay (mcp.bridgerator.recondeck.com) ──WebSocket──► bridgerator on your PC ──stdio──► bundled MCP engine
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
This repository is the part that runs on your PC. It is small on purpose so you (or an AI agent
|
|
12
|
+
installing it for you) can read all of it: `src/bridge.mjs` (forwarder), `src/policy.mjs` (access
|
|
13
|
+
rules), `src/dc-isolate.mjs` (separate engine config), `src/cli.mjs` (setup/autostart), `src/pair.mjs` (browser pairing), `install.ps1` (installer). Version 1.1.0 ships as a signed Windows app (no Node.js needed); this repository is also published as the npm package for developers.
|
|
14
|
+
|
|
15
|
+
## What people use it for
|
|
16
|
+
|
|
17
|
+
- "Sort my Downloads folder by type and month" — ChatGPT lists, plans and moves the files on your PC.
|
|
18
|
+
- "Find every invoice PDF in Documents and rename it by date" — search and rename in plain words.
|
|
19
|
+
- "Why is drive C almost full?" — disk usage, big folders, what is safe to delete.
|
|
20
|
+
- "Check the event log for errors since yesterday" / "Read the end of this log" — diagnostics.
|
|
21
|
+
- Work on code: "explain how D:\\Projects\\app is built and run its tests".
|
|
22
|
+
|
|
23
|
+
Everything runs as your Windows user and only inside the folders you allow.
|
|
24
|
+
|
|
25
|
+
## Plans
|
|
26
|
+
|
|
27
|
+
Free: 10,000 tool calls per month per account, any number of PCs. Pro: $10/month, unlimited.
|
|
28
|
+
Details: https://bridgerator.recondeck.com/pricing
|
|
29
|
+
|
|
30
|
+
## Install (Windows)
|
|
31
|
+
|
|
32
|
+
1. Sign up at https://bridgerator.recondeck.com (or sign in with Google from ChatGPT or another AI app) and follow **Install** there: the site gives the download and the install steps for Windows.
|
|
33
|
+
2. A browser tab opens with a code: check that it matches the one shown by the installer and click **Connect this computer**. Done — no key to copy.
|
|
34
|
+
|
|
35
|
+
The installer downloads the signed Bridgerator app for Windows (`bridgerator.exe` with Node.js inside — nothing else to install; x64 and ARM64), checks it (SHA256 of the download and of every file), puts it into `%LOCALAPPDATA%\Bridgerator\app` and runs `bridgerator.cmd setup`. No admin rights needed. An older npm install is replaced, its key and settings kept. If the WebView2 runtime (used by the window) is missing, it is installed for your user only (Microsoft's installer, signature checked); without it the account page opens instead of the window. `-UseNpm` installs the npm package instead (your Node.js 22+, or a portable Node.js 24 LTS, checksum-verified; the package SHA256-checked, `--ignore-scripts`). Works under the default Restricted execution policy. `-NoTelemetry` turns off the usage counts (see Privacy).
|
|
36
|
+
|
|
37
|
+
<!-- install-oneliner -->
|
|
38
|
+
One-line install, in PowerShell:
|
|
39
|
+
```powershell
|
|
40
|
+
& ([scriptblock]::Create((irm https://bridgerator.recondeck.com/install.ps1)))
|
|
41
|
+
```
|
|
42
|
+
<!-- /install-oneliner -->
|
|
43
|
+
|
|
44
|
+
Update later the same way (the key and settings are kept). Prefer to read first? Download `install.ps1` from the site, read it, then run it.
|
|
45
|
+
Servers or PCs without a browser: create a device key in your account (Add a computer → Advanced) and pass `-Token <device key>` to the installer.
|
|
46
|
+
|
|
47
|
+
Manual install (PowerShell): `$env:PUPPETEER_SKIP_DOWNLOAD=1; npm.cmd install -g bridgerator --ignore-scripts`, then `bridgerator.cmd setup` (or `bridgerator.cmd setup --token <key>`). The variable skips a ~700 MB Chrome download that only PDF export needs; PDF export fetches a browser itself on first use.
|
|
48
|
+
|
|
49
|
+
Other MCP clients (Claude, Codex, Cursor, VS Code and others): server URL `https://mcp.bridgerator.recondeck.com/mcp`, OAuth sign-in. Apps that cannot do OAuth can use a personal access key from your account page (Authorization: Bearer).
|
|
50
|
+
|
|
51
|
+
## Access rules — what the assistant can and cannot touch
|
|
52
|
+
|
|
53
|
+
Config: `%APPDATA%\Bridgerator\config.json` (written by `setup` and the window; a running bridge picks up a hand edit within seconds — lowering protection waits for Apply in a notification on the PC). Every setting can also be read and changed by the assistant with `bridgerator_settings`; its changes apply at once, unless you turn on `askSettings` (below).
|
|
54
|
+
|
|
55
|
+
By default nothing is restricted (like the engine on its own), except that **deletions go to the Recycle Bin** and **file changes can be undone**.
|
|
56
|
+
|
|
57
|
+
| Key | Meaning | Default |
|
|
58
|
+
|---|---|---|
|
|
59
|
+
| `allowedDirectories` | File tools work only inside these folders. Empty = all folders except the always-blocked ones. | empty (all folders) |
|
|
60
|
+
| `deniedDirectories` | Folders excluded **inside** the allowed ones (enforced by Bridgerator, see below). Always excluded, can't be removed: Bridgerator itself — `%APPDATA%\Bridgerator`, `%LOCALAPPDATA%\Bridgerator` (snapshots too), the package in `%APPDATA%\npm`. | none |
|
|
61
|
+
| `protectSensitive` | "Protect sensitive folders": also excludes `%APPDATA%\npm`, Startup, `Documents\WindowsPowerShell`/`PowerShell`, `~\.ssh .aws .azure .kube .docker .gnupg .config .npmrc .git-credentials .gitconfig .claude`, `~\AppData`. | `false` |
|
|
62
|
+
| `recycleBin` | A plain delete command (`Remove-Item`, `del`, `erase`, `rd`/`rmdir`, `rm` with literal paths or a wildcard in the last part) moves the items to the Recycle Bin instead; no Recycle Bin on that drive (network, many USB sticks) → asked on the PC first. Scripts, pipelines and other programs that delete are not caught: a safety net, not a guarantee. | `true` |
|
|
63
|
+
| `snapshots` | `{enabled, days, maxMb, maxFileMb}`: a copy of a file before the assistant writes, edits, moves or (through the Recycle Bin path) deletes it, in `%LOCALAPPDATA%\Bridgerator\snapshots`; Undo in the window (Recent → Undo, "Undo AI changes…" per task / batch) and `bridgerator_undo`. A file changed after the assistant's action is never overwritten. Bigger files get no copy ("no undo"). | on, 7 days, 500 MB, 50 MB |
|
|
64
|
+
| `fuse` | `{enabled, limit}`: more than `limit` deletions / moves within a minute → Bridgerator pauses itself and asks on the PC whether to continue (no answer = stays paused). | off, 20 |
|
|
65
|
+
| `askSettings` | "Ask before the AI changes settings": when on, an AI change that lowers protection or widens access (`bridgerator_settings`, `bridgerator_setup`) waits for Apply on the PC; raising protection still applies at once. Off: every AI change applies at once. | `false` |
|
|
66
|
+
| `keepAwake` | The PC doesn't go to sleep while the assistant works or the task queue has work (mains power only; the screen can still turn off). | `true` |
|
|
67
|
+
| `readOnlyDirectories` | Readable, but `write_file`, `edit_block`, `move_file` (either side), `create_directory` are refused. The terminal is not bound by it. `bridgerator.cmd read-only add\|remove <dir>` | none |
|
|
68
|
+
| `confirm.ini` (next to config.json) | Off by default. When on, a Windows notification on the PC (Allow / Allow 10 min / Deny, "Allow always" in its `...` menu; no answer in 2 min = Deny) before **risky** calls: `delete` and `dangerous_commands` (pattern lists, a safety net — an obfuscated command can slip through), optionally `write_files`, `move`, `any_command`, plus your own `[patterns]`. Re-read on every call. A hand edit of the file that lowers protection waits for Apply / Keep on the PC; the last applied state is kept in `confirm.approved` next to it, so a deleted or broken `confirm.ini` comes back with that state. `bridgerator.cmd confirm on\|off [category]`; the assistant can only ask (`request_confirm_off`, approved on the PC). If notifications are off for Bridgerator, a small window in the bottom-right is used instead; with Do Not Disturb the request is denied after 2 minutes. | off |
|
|
69
|
+
| `blockedCommands` | A safety net of the engine: refuses commands by their first word. Not a security boundary. Leave it out to keep the built-in list. | built-in list (`format`, `diskpart`, `reg`, `net`, `sc`, `runas`, `netsh`, `takeown`, …) |
|
|
70
|
+
| `telemetryEnabled` | Anonymous usage counts (see Privacy). `bridgerator.cmd telemetry off\|on` | `true` |
|
|
71
|
+
| `disabledTools` | Tools the assistant can't use. The access presets set the terminal here: Read only (terminal off + every folder read-only), Files (terminal off), Full (default). `start_process`, `interact_with_process`, `kill_process` stay listed and are refused while the terminal is off. | none |
|
|
72
|
+
|
|
73
|
+
Full file, search and terminal toolset, including ChatGPT widgets (file preview,
|
|
74
|
+
config view). Hidden: `set_config_value` (would let the assistant change its own limits), feedback and
|
|
75
|
+
usage-stats tools, `write_pdf` and `get_recent_tool_calls`; `read_file` with `isUrl` and UNC / device
|
|
76
|
+
paths (`\\server\share`, `\\?\`, `\\.\`) are refused. Path arguments are checked at any depth.
|
|
77
|
+
|
|
78
|
+
How exclusions work (`src/policy.mjs`): every path argument is resolved (symlinks and junctions
|
|
79
|
+
included) and refused if it lies inside an excluded folder; result lines that mention an excluded
|
|
80
|
+
path (search hits, recursive listings) are removed. The file tools can't reach the settings folder; the
|
|
81
|
+
settings tool (`bridgerator_settings`) can't change those folders, and with `askSettings` on it lowers protection only after your OK on the PC.
|
|
82
|
+
|
|
83
|
+
⚠ **The terminal is not a folder sandbox.** A shell command runs with your Windows user's rights
|
|
84
|
+
and can read anything you can. Bridgerator refuses commands that literally name an excluded folder,
|
|
85
|
+
but that is a courtesy, not a boundary. If folder limits must be strict, add the terminal tools to
|
|
86
|
+
`disabledTools`.
|
|
87
|
+
|
|
88
|
+
The bridge runs as **your** Windows user (hidden scheduled task at logon), never as SYSTEM.
|
|
89
|
+
|
|
90
|
+
Bridgerator gives its bundled engine its **own** config folder (`%APPDATA%\Bridgerator\dc`, see `src/dc-isolate.mjs`): if you already run the same open-source MCP server for Claude or another app, its settings and folder limits are not touched. The engine keeps a local log of recent tool calls in that folder (the per-call argument log is turned off); it never leaves your PC.
|
|
91
|
+
|
|
92
|
+
## Tray, window and task queue
|
|
93
|
+
|
|
94
|
+
While the bridge runs, a tray icon shows its state (green online, grey offline, yellow paused; a
|
|
95
|
+
yellow / red badge when Pro is ending or the Free limit is near). Right-click: status line, **Open
|
|
96
|
+
Bridgerator**, **Task queue**, **Confirm on this PC** (on / off), **Pause** (15 min, 1 hour, until
|
|
97
|
+
resumed), **Open account**, **Help**, **Quit**. Double-click opens the window: Status, Task queue, Automations, Agents,
|
|
98
|
+
Agent tasks, Last actions, Safety (confirmations, folders, read-only folders), Notifications, Settings
|
|
99
|
+
(cards in pairs; theme System / Light / Dark for the window and our pop-ups, English / Russian, computer name,
|
|
100
|
+
start with Windows, usage stats, local history, ask before the AI changes settings, updates, uninstall), Help. Minimize hides the window to the tray. Notifications can also go to Telegram (@BridgeratorBot, linked in your account): counts and statuses only, never file contents.
|
|
101
|
+
The tray helper (`src/tray.ps1`, hidden PowerShell, stdin/stdout JSON lines, no network) also shows
|
|
102
|
+
the confirmation and setup notifications. The window is WebView2 (`ui/`; SDK DLLs in
|
|
103
|
+
`vendor/webview2`, official NuGet package Microsoft.Web.WebView2 1.0.4258.31, SHA256 in
|
|
104
|
+
`vendor/webview2/SHA256SUMS.txt`); without the runtime the account page opens instead.
|
|
105
|
+
Stored only on this PC: the task queue (`%APPDATA%\Bridgerator\queue.json`; tools `queue_list`,
|
|
106
|
+
`queue_next`, `queue_update`, `queue_add`, `queue_edit`, `queue_reorder`) and the recent calls with
|
|
107
|
+
their command / path (memory; `recent.jsonl` for 7 days only with "Keep a local history" on).
|
|
108
|
+
|
|
109
|
+
**Several chats at once.** Several ChatGPT chats can work on the same PC in parallel: calls run
|
|
110
|
+
concurrently (a slow command doesn't hold up other chats), `queue_next` never hands the same task to
|
|
111
|
+
two chats, and at most 8 actions run at a time — extra ones wait up to 30 s, then get a "busy" answer
|
|
112
|
+
that is not counted.
|
|
113
|
+
|
|
114
|
+
## Talk to ChatGPT
|
|
115
|
+
|
|
116
|
+
Say these in any ChatGPT chat with Bridgerator connected (several chats can work at once):
|
|
117
|
+
|
|
118
|
+
| Say | What happens |
|
|
119
|
+
|---|---|
|
|
120
|
+
| `Set up Bridgerator` | Nothing to configure: the defaults (all folders, terminal on, Recycle Bin, Undo) are the setup. ChatGPT limits access only if you ask for limits ("only this folder", "read only"), and that applies at once. |
|
|
121
|
+
| `Add these tasks to my Bridgerator queue: …` | The tasks go into the queue on this PC (up to 100 at a time). |
|
|
122
|
+
| `Work through my Bridgerator queue` | ChatGPT takes the tasks one by one and marks each done / failed with a note. |
|
|
123
|
+
| `Continue my Bridgerator queue` | In a new chat: picks up tasks another chat left unfinished for 30 min. |
|
|
124
|
+
| `Show my Bridgerator settings` | Folders, confirmations, notifications — what is set now (`bridgerator_settings`). |
|
|
125
|
+
| `Turn on confirmations for deletions` | Applies at once. With "Ask before the AI changes settings" on, lowering protection (e.g. turning confirmations off) needs your OK on the PC. |
|
|
126
|
+
|
|
127
|
+
Folders: with no list (the default) ChatGPT may work in all folders except the always-blocked ones;
|
|
128
|
+
with a list, only in those folders. The assistant's changes apply at once; with "Ask before the AI changes settings" on, widening access (adding a folder to the list, going back to all folders) needs your OK on the PC.
|
|
129
|
+
|
|
130
|
+
## Commands
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
bridgerator.cmd setup [--token <key> | --pair] [--allow <dir>]... [--deny <dir>]... [--read-only <dir>]... [--language en|ru] [--no-telemetry]
|
|
134
|
+
# pair in the browser (no key yet, key rejected, or --pair) + config + autostart + start
|
|
135
|
+
bridgerator.cmd run # foreground (what autostart runs)
|
|
136
|
+
bridgerator.cmd stop # stop it (starts again at the next logon)
|
|
137
|
+
bridgerator.cmd status [--json] # running / online / key rejected (+ config with --json)
|
|
138
|
+
bridgerator.cmd doctor [--json] # check the install, connection and settings
|
|
139
|
+
bridgerator.cmd confirm on|off [category] # confirmation on this PC (confirm.ini)
|
|
140
|
+
bridgerator.cmd read-only add|remove <dir> # read-only folders
|
|
141
|
+
bridgerator.cmd telemetry on|off # anonymous usage counts
|
|
142
|
+
bridgerator.cmd uninstall --all # THE uninstall: stop, remove autostart, settings + key, the program files (app folder or npm package) and the Node.js the installer added
|
|
143
|
+
bridgerator.cmd uninstall [--keep-config] # stop, remove autostart and %APPDATA%\Bridgerator (kept with --keep-config); program files stay
|
|
144
|
+
```
|
|
145
|
+
Log: `%APPDATA%\Bridgerator\bridge.log`. Stopping the bridge cuts access immediately. After uninstalling, also remove the computer on the account page: https://bridgerator.recondeck.com/app
|
|
146
|
+
|
|
147
|
+
## Privacy
|
|
148
|
+
|
|
149
|
+
File contents and command output go to ChatGPT (OpenAI) as tool results; the relay forwards them
|
|
150
|
+
in memory and does not store them. Engine telemetry, remote feature flags and any browser pop-ups are turned off by the bridge.
|
|
151
|
+
|
|
152
|
+
Bridgerator's own usage counts (`src/telemetry.mjs`, HTTPS to `https://bridgerator.recondeck.com/t`):
|
|
153
|
+
events install, update, uninstall and a daily heartbeat with a random install id, bridge version,
|
|
154
|
+
Windows version, OS language, Node.js version, and per-tool call / error counts of the last 24 h.
|
|
155
|
+
Never paths, file names, commands, arguments, outputs or your e-mail. Off: `bridgerator.cmd telemetry off`,
|
|
156
|
+
`"telemetryEnabled": false`, or the installer's `-NoTelemetry`.
|
|
157
|
+
Policy: https://bridgerator.recondeck.com/privacy
|
|
158
|
+
|
|
159
|
+
## Development
|
|
160
|
+
|
|
161
|
+
`npm test` — policy unit tests plus an end-to-end run against the real bundled engine
|
|
162
|
+
(throw-away folders; asserts that an existing config of the same engine stays byte-identical).
|
|
163
|
+
|
|
164
|
+
## License
|
|
165
|
+
|
|
166
|
+
MIT. The bundled open-source MCP engine is MIT-licensed as well; its copyright notice is kept in
|
|
167
|
+
`LICENSE` and the dependency is listed in `package.json`.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
### По-русски коротко
|
|
172
|
+
Bridgerator подключает ваш ПК к ChatGPT: файлы, поиск, терминал. Мост только исходящий, входящих
|
|
173
|
+
портов нет. Установка — одна строка PowerShell, затем подтверждение компьютера во вкладке браузера (см. выше).
|
|
174
|
+
Разрешённые папки — `allowedDirectories`, исключения внутри них — `deniedDirectories`
|
|
175
|
+
(исключения обеспечивает сам Bridgerator). Терминал папками не
|
|
176
|
+
ограничивается — для строгих границ выключите его через `disabledTools`.
|
package/install.ps1
CHANGED
|
@@ -26,16 +26,17 @@ param(
|
|
|
26
26
|
)
|
|
27
27
|
$ErrorActionPreference = 'Stop'
|
|
28
28
|
# SHA256 of the bridgerator.tgz published next to this script (written by release.sh).
|
|
29
|
-
$PackageSha256 = '
|
|
29
|
+
$PackageSha256 = '990b1a9754310fcf75530ac6365f149843037adcff88cf7e33b4bed7e03ce211'
|
|
30
30
|
# SHA256 of bridgerator-win.json, the Windows app download list published next to this script
|
|
31
31
|
# (written by scripts/build-exe.mjs / release.sh). It names the zip per architecture and its SHA256.
|
|
32
|
-
$WinManifestSha256 = '
|
|
32
|
+
$WinManifestSha256 = '5ba96127dc260e8469a0cf2432a11963c11b96417131432e563fa56092cc949d'
|
|
33
33
|
$Site = 'https://bridgerator.recondeck.com'
|
|
34
34
|
# The npm package comes from the same site as this script (a staging copy rewrites only $Site / $Relay).
|
|
35
35
|
$DefaultPackage = "$Site/bridgerator.tgz"
|
|
36
36
|
if (-not $Package) { $Package = $DefaultPackage }
|
|
37
|
-
# Relay for setup
|
|
38
|
-
|
|
37
|
+
# Relay for setup: always the relay of the site this script came from, so a PC paired elsewhere (staging)
|
|
38
|
+
# moves here (its old key is rejected -> pairing again). A staging build rewrites both lines.
|
|
39
|
+
$Relay = 'wss://mcp.bridgerator.recondeck.com/link'
|
|
39
40
|
$Root = Join-Path $env:LOCALAPPDATA 'Bridgerator'
|
|
40
41
|
$AppDir = Join-Path $Root 'app'
|
|
41
42
|
$NpmPkg = Join-Path $env:APPDATA 'npm\node_modules\bridgerator'
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bridgerator",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
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.2",
|
|
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.2",
|
|
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
|
@@ -19,7 +19,7 @@ import { shorten } from './tool-text.mjs';
|
|
|
19
19
|
import { parseDelete, recycle as recycleOnPc, purgeFromBin } from './recycle.mjs';
|
|
20
20
|
import { createSnapshots, changedPaths, undoGroups, SNAP_DEFAULTS, UNDO_TOOL_DEF } from './undo.mjs';
|
|
21
21
|
import { createFuse, wantAwake, FUSE_DEFAULTS } from './guard.mjs';
|
|
22
|
-
import { createQueue, queueTool, QUEUE_TOOL_DEFS, QUEUE_TOOL_NAMES } from './queue.mjs';
|
|
22
|
+
import { createQueue, queueTool, stalledItems, QUEUE_TOOL_DEFS, QUEUE_TOOL_NAMES } from './queue.mjs';
|
|
23
23
|
import { createRecent, outcomeOf } from './recent.mjs';
|
|
24
24
|
import { readSettingsStrict, setIni, writeAtomic, CATEGORIES, findMatch, clip } from './confirm.mjs';
|
|
25
25
|
import { readPlan, planBanner, bannerVisible, dismissFor, safeUrl, forecast, setSite, accountUrl } from './plan.mjs';
|
|
@@ -374,6 +374,14 @@ export async function startDesktopCommander(cfg, log = console.log, { ask: askAr
|
|
|
374
374
|
// --- Recycle Bin, mass-action fuse, Undo (LOGIC: critical-logic/bridge.md) ---------------------
|
|
375
375
|
const fuse = createFuse();
|
|
376
376
|
let fuseAsking = false, inFlight = 0, lastCall = 0, wasPaused = false;
|
|
377
|
+
// One notice per stalled "doing" item (id + updatedAt), on unless the person turned it off.
|
|
378
|
+
const stalledWarned = new Set(), started = Date.now();
|
|
379
|
+
if (queue) setInterval(() => {
|
|
380
|
+
if (cfg.notify?.queueStalled === false || inFlight) return;
|
|
381
|
+
const fresh = stalledItems(queue.list('doing'), { now: Date.now(), idleSince: Math.max(lastCall, started) }).filter((it) => !stalledWarned.has(`${it.id}@${it.updatedAt}`));
|
|
382
|
+
for (const it of fresh) stalledWarned.add(`${it.id}@${it.updatedAt}`);
|
|
383
|
+
if (fresh.length) showNotice({ kind: 'queue_stalled', title: fresh[0].title, more: fresh.length - 1 }, log); // one notice per check, not a burst
|
|
384
|
+
}, 60000).unref();
|
|
377
385
|
const fuseCfg = () => ({ ...FUSE_DEFAULTS, ...(cfg.fuse || {}) });
|
|
378
386
|
const setPaused = (v) => { if (out.setPaused) out.setPaused(v); else { out.paused = v; out.onMode(mode()); } };
|
|
379
387
|
const currentTask = () => { const d = queue ? queue.list('doing') : []; return d.length === 1 ? { id: d[0].id, title: d[0].title } : undefined; };
|
|
@@ -495,7 +503,7 @@ export async function startDesktopCommander(cfg, log = console.log, { ask: askAr
|
|
|
495
503
|
const bannerNow = () => { const b = planBanner(out.plan); return { ...b, visible: bannerVisible(b, cfg.planBannerDismissed) }; };
|
|
496
504
|
out.banner = bannerNow;
|
|
497
505
|
out.onPlanMsg = (m) => { out.plan = readPlan(m); out.onPlan?.(); };
|
|
498
|
-
const BOOL_NOTIFY = ['sound', 'offline', 'queueDone', 'limit'];
|
|
506
|
+
const BOOL_NOTIFY = ['sound', 'offline', 'queueDone', 'queueStalled', 'limit'];
|
|
499
507
|
|
|
500
508
|
// Requests of the Bridgerator window (tray helper). Made by the person at the PC: no extra prompt.
|
|
501
509
|
async function rpc(method, p = {}, paths = []) {
|
|
@@ -602,7 +610,7 @@ export async function startDesktopCommander(cfg, log = console.log, { ask: askAr
|
|
|
602
610
|
if (!/^https:\/\//.test(site)) throw new Error('no https site to update from');
|
|
603
611
|
patchConfig({ updatingFrom: VERSION });
|
|
604
612
|
showNotice({ kind: 'updating', version: String(p.version || '') }, log);
|
|
605
|
-
const ps = spawn(POWERSHELL, psArgs(
|
|
613
|
+
const ps = spawn(POWERSHELL, psArgs(`& ([scriptblock]::Create((Invoke-RestMethod '${site.replace(/'/g, "''")}/install.ps1')))`), { windowsHide: true, stdio: 'ignore', env: stripOurs(process.env) });
|
|
606
614
|
ps.on('error', (e) => log(`[bridgerator] update did not start: ${e.message}`));
|
|
607
615
|
ps.unref();
|
|
608
616
|
return true;
|
|
@@ -690,6 +698,9 @@ export function cleanEnv(env = process.env) {
|
|
|
690
698
|
export function engineEnv(env = process.env) {
|
|
691
699
|
const e = cleanEnv(env);
|
|
692
700
|
for (const k of Object.keys(e)) if (/^(BRIDGERATOR_|BR_)/i.test(k)) delete e[k];
|
|
701
|
+
// The terminal's PowerShell may run .ps1 (npm.ps1, npx.ps1…): Windows' default "Restricted" blocks them (26.10, a user's
|
|
702
|
+
// PC). Process scope only — the PC's own policy is never changed, a Group Policy still wins, a value the person set stays.
|
|
703
|
+
if (!Object.keys(e).some((k) => k.toLowerCase() === 'psexecutionpolicypreference')) e.PSExecutionPolicyPreference = 'Bypass';
|
|
693
704
|
return e;
|
|
694
705
|
}
|
|
695
706
|
export function engineCwd(cfg, home = os.homedir()) {
|
package/src/extra-tools.mjs
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
// ctx.policy is the CURRENT policy (folders can change at runtime); path checks: tool-lib.mjs guard().
|
|
20
20
|
// Format is fixed: other modules are added by appending to EXTRA_MODULES, nothing else changes.
|
|
21
21
|
import { errorText } from './tool-lib.mjs';
|
|
22
|
+
import { addRuLabels } from './pc-text.mjs';
|
|
22
23
|
import * as doctor from './doctor.mjs';
|
|
23
24
|
import * as docs from './docs-tool.mjs';
|
|
24
25
|
import * as search from './search-tool.mjs';
|
|
@@ -47,6 +48,7 @@ export function createExtra(mods = EXTRA_MODULES) {
|
|
|
47
48
|
for (const m of mods) for (const d of m.defs || []) { if (owner.has(d.name)) throw new Error(`extra tool ${d.name} registered twice`); owner.set(d.name, m); }
|
|
48
49
|
const settings = mods.flatMap((m) => m.settings || []);
|
|
49
50
|
const byKey = new Map(settings.map((s) => [s.key, s]));
|
|
51
|
+
addRuLabels(Object.fromEntries(settings.filter((s) => s.label?.en && s.label?.ru).map((s) => [s.label.en, s.label.ru])));
|
|
50
52
|
const get = (cfg, key) => { const [g, k] = key.split('.'); const v = cfg?.[g]?.[k]; return valid(byKey.get(key), v) ? v : byKey.get(key).default; };
|
|
51
53
|
return {
|
|
52
54
|
defs: mods.flatMap((m) => m.defs || []),
|
package/src/notice.mjs
CHANGED
|
@@ -30,6 +30,11 @@ export function noticeText(n) {
|
|
|
30
30
|
const title = typeof n.title === 'string' ? n.title.replace(/[\u0000-\u001f\u007f-\u009f]/g, ' ').trim().slice(0, 120) : '';
|
|
31
31
|
if (!title) return undefined;
|
|
32
32
|
t = ['Queue task done', title];
|
|
33
|
+
} else if (kind === 'queue_stalled') {
|
|
34
|
+
const title = typeof n.title === 'string' ? n.title.replace(/[\u0000-\u001f\u007f-\u009f]/g, ' ').trim().slice(0, 120) : '';
|
|
35
|
+
if (!title) return undefined;
|
|
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.`];
|
|
33
38
|
} else if (kind === 'protection_off') {
|
|
34
39
|
// Internal list only (the bridge's own labels), never relay text.
|
|
35
40
|
const ok = new Set(['confirmations', 'your own patterns', ...Object.values(LABEL).map((l) => `confirmations for ${l}`)]);
|
package/src/pc-text.mjs
CHANGED
|
@@ -54,6 +54,30 @@ const PLAN_OBJ_RU = { file: ['файл', 'файла', 'файлов'], folder:
|
|
|
54
54
|
const PLAN_LIST_RU = { move: ['перемещение', 'перемещения', 'перемещений'], write: ['запись', 'записи', 'записей'], edit: ['правка', 'правки', 'правок'], 'new folder': ['новая папка', 'новые папки', 'новых папок'], command: ['команда', 'команды', 'команд'] };
|
|
55
55
|
const planCount = (n, word, forms) => { const f = forms[word.replace(/s$/, '')]; return f ? `${n} ${ruPlural(Number(n), f)}` : null; };
|
|
56
56
|
|
|
57
|
+
// Settings change lines (settings-tool.mjs describe, "Label: value", joined by " · "): label and on/off in Russian.
|
|
58
|
+
const LINE_RU = {
|
|
59
|
+
Confirmations: 'Подтверждения', 'No answer = Deny after': 'Нет ответа = запрет через', Folders: 'Папки', 'Read-only': 'Только чтение',
|
|
60
|
+
'Excluded folders': 'Исключённые папки', 'Start with Windows': 'Запуск вместе с Windows', 'Usage stats': 'Статистика использования',
|
|
61
|
+
'Local history': 'Локальная история', Theme: 'Тема', Language: 'Язык', 'Pop-up style': 'Вид уведомлений', 'Computer name': 'Имя компьютера',
|
|
62
|
+
'Terminal (commands)': 'Терминал (команды)', Terminal: 'Терминал', 'Protect sensitive folders': 'Защищать важные папки', 'Recycle Bin instead of deleting': 'Корзина вместо удаления',
|
|
63
|
+
'Keep the PC awake while ChatGPT works': 'Не давать ПК засыпать, пока ChatGPT работает', 'Ask before AI changes settings': 'Спрашивать перед изменением настроек ИИ',
|
|
64
|
+
Access: 'Доступ', 'Snapshots and Undo': 'Снимки и отмена', 'Keep snapshots (days)': 'Хранить снимки (дней)', 'Snapshots up to (MB)': 'Снимки до (МБ)',
|
|
65
|
+
'Snapshot files up to (MB)': 'Файлы в снимках до (МБ)', 'Pause on mass deletes / moves': 'Пауза при массовом удалении / перемещении', 'Mass-action limit per minute': 'Лимит массовых действий в минуту',
|
|
66
|
+
};
|
|
67
|
+
// "Confirm <confirm.mjs LABEL>".
|
|
68
|
+
const CONFIRM_RU = { deletions: 'удаление', 'system commands': 'системные команды', 'file changes': 'изменение файлов', 'moves and renames': 'перемещения и переименования', commands: 'команды', 'installing programs': 'установку программ', 'scheduled scripts': 'сценарии на расписании' };
|
|
69
|
+
const VALUE_RU = { on: 'вкл', off: 'выкл', unchanged: 'без изменений', 'all (except always-blocked)': 'все (кроме всегда закрытых)' };
|
|
70
|
+
/** Extra tools (extra-tools.mjs) add their own setting labels: { en: ru }. */
|
|
71
|
+
export const addRuLabels = (map) => Object.assign(LINE_RU, map);
|
|
72
|
+
const ruLine = (l) => {
|
|
73
|
+
const m = /^(.+?): (.*)$/s.exec(l);
|
|
74
|
+
if (!m) return null;
|
|
75
|
+
const what = m[1].startsWith('Confirm ') && Object.hasOwn(CONFIRM_RU, m[1].slice(8)) && CONFIRM_RU[m[1].slice(8)];
|
|
76
|
+
const label = Object.hasOwn(LINE_RU, m[1]) ? LINE_RU[m[1]] : what ? `Подтверждать ${what}` : null;
|
|
77
|
+
return label && `${label}: ${Object.hasOwn(VALUE_RU, m[2]) ? VALUE_RU[m[2]] : m[1] === 'Folders' ? m[2].replace(/^only /, 'только ') : m[2]}`;
|
|
78
|
+
};
|
|
79
|
+
const ruLines = (t) => { const out = t.split(' · ').map(ruLine); return out.includes(null) ? null : out.join(' · '); };
|
|
80
|
+
|
|
57
81
|
/** One English text → Russian (unknown text stays English). */
|
|
58
82
|
export function ruText(t) {
|
|
59
83
|
if (typeof t !== 'string' || !t) return t;
|
|
@@ -87,7 +111,9 @@ export function localizeAsk(q, lang) {
|
|
|
87
111
|
return {
|
|
88
112
|
...q,
|
|
89
113
|
head: ruText(q.head),
|
|
90
|
-
|
|
114
|
+
// Change lines only in the settings question (never in a command or path the AI wrote).
|
|
115
|
+
text: q.head === 'ChatGPT wants to change Bridgerator settings' || q.head === 'ChatGPT suggests Bridgerator settings' ? ruLines(q.text) ?? ruText(q.text)
|
|
116
|
+
: q.head === 'Bridgerator settings file changed' && /^Apply: (.+)\?$/s.test(q.text) ? `Применить: ${ruLines(q.text.slice(7, -1)) ?? q.text.slice(7, -1)}?` : ruText(q.text),
|
|
91
117
|
buttons: (q.buttons || []).map(([k, label, kind]) => [k, ruText(label), kind]),
|
|
92
118
|
auto: q.auto ? AUTO_RU[q.auto] || q.auto : q.auto,
|
|
93
119
|
};
|
package/src/queue.mjs
CHANGED
|
@@ -9,7 +9,11 @@ export const STATUSES = ['todo', 'doing', 'done', 'failed', 'skipped'];
|
|
|
9
9
|
const MAX_ITEMS = 500, MAX_TITLE = 200, MAX_DETAILS = 4000, MAX_NOTE = 1000, MAX_PATHS = 20;
|
|
10
10
|
const RULE = 'The usual loop: queue_next, do the task, queue_update with done / failed / skipped and a short note, then the next one until the queue is empty or the person stops. resultPath set: write the result to that file. from set: another AI added it and reads queue_list.';
|
|
11
11
|
const MAX_FROM = 80, MAX_RESULT_PATH = 1000;
|
|
12
|
-
export const STALE_MS = 30 * 60 * 1000;
|
|
12
|
+
export const STALE_MS = 30 * 60 * 1000;
|
|
13
|
+
export const STALLED_MS = 10 * 60 * 1000; // "doing" + no tool call at all for this long: ChatGPT is likely waiting for the person
|
|
14
|
+
/** "doing" items with no update and no tool call on this PC for `ms` (owner 26.10: ChatGPT's own Allow dialog is invisible on the PC). */
|
|
15
|
+
// ponytail: one PC-wide idle clock — a second chat busy with other calls hides a stalled one; per-chat tracking would need the worker on every call.
|
|
16
|
+
export const stalledItems = (list, { now, idleSince, ms = STALLED_MS }) => (now - idleSince < ms ? [] : list.filter((x) => x.status === 'doing' && now - Date.parse(x.updatedAt) >= ms)); // "doing" with no update for this long: another chat gave up
|
|
13
17
|
const ID = { type: 'string', description: 'item id' };
|
|
14
18
|
const STR = (n) => ({ type: 'string', maxLength: n });
|
|
15
19
|
const PATHS = { type: 'array', maxItems: MAX_PATHS, items: STR(1000) };
|
|
@@ -18,7 +22,7 @@ const HANDOFF = { from: { type: 'string', maxLength: MAX_FROM, description: 'Who
|
|
|
18
22
|
|
|
19
23
|
export const QUEUE_TOOL_DEFS = [
|
|
20
24
|
{ name: 'queue_list', description: `List the task queue the person keeps on this PC (a checklist of things to do): counts and items (id, title, status, note, worker, updatedAt, from, resultPath), optionally only one status.`, inputSchema: { type: 'object', additionalProperties: false, properties: { status: { type: 'string', enum: STATUSES } } } },
|
|
21
|
-
{ name: 'queue_next', description: `Take the next item of the task queue: returns the first "todo" item and marks it "doing" (nothing when the queue is empty). An item left "doing" for 30 minutes without an update (another chat stopped) is returned first, with resumed: true. Several chats can work through one queue at once; each call gets a different item. Pass worker = a short name for this chat (e.g. its title) so the person sees who is on it. ${RULE}`, inputSchema: { type: 'object', additionalProperties: false, properties: { worker: STR(80) } } },
|
|
25
|
+
{ name: 'queue_next', description: `Take the next item of the task queue: returns the first "todo" item and marks it "doing" (nothing when the queue is empty). An item left "doing" for 30 minutes without an update (another chat stopped) is returned first, with resumed: true. Several chats can work through one queue at once; each call gets a different item. Pass worker = a short name for this chat (e.g. its title) so the person sees who is on it. ${RULE}`, inputSchema: { type: 'object', additionalProperties: false, properties: { worker: STR(80), id: { type: 'string', description: 'take this "todo" item instead of the first one' } } } },
|
|
22
26
|
{ name: 'queue_update', description: `Set an item's status (doing / done / failed / skipped / todo) with a short result note.`, inputSchema: { type: 'object', additionalProperties: false, required: ['id', 'status'], properties: { id: ID, status: { type: 'string', enum: STATUSES }, note: STR(MAX_NOTE) } } },
|
|
23
27
|
{ name: 'queue_add', description: `Add steps to the task queue (e.g. when planning a bigger job with the person): one { title, details?, paths?, from?, resultPath? } or items: [...] (1–100). Another AI handing work to ChatGPT sets from (its name) and resultPath (a file for the result), then reads the outcome with queue_list.`, inputSchema: { type: 'object', additionalProperties: false, properties: { title: STR(MAX_TITLE), details: STR(MAX_DETAILS), paths: PATHS, ...HANDOFF, items: { type: 'array', minItems: 1, maxItems: 100, items: { type: 'object', additionalProperties: false, required: ['title'], properties: { title: STR(MAX_TITLE), details: STR(MAX_DETAILS), paths: PATHS, ...HANDOFF } } } } } },
|
|
24
28
|
{ name: 'queue_clear', description: 'Remove finished items from the task queue: status done, failed or skipped. status "all" removes every item and needs the person\'s OK on the PC.', inputSchema: { type: 'object', additionalProperties: false, properties: { status: { type: 'string', enum: ['done', 'failed', 'skipped', 'all'] } } } },
|
|
@@ -99,11 +103,15 @@ export function createQueue(file, { now = () => new Date().toISOString(), onChan
|
|
|
99
103
|
items.push(it); save(); return it;
|
|
100
104
|
},
|
|
101
105
|
// Synchronous take: parallel chats calling queue_next never get the same item.
|
|
102
|
-
|
|
106
|
+
// id: that item only (a chat told to take certain tasks), if it is "todo" or stale "doing"; else an error.
|
|
107
|
+
next({ worker, id } = {}) { return commit(() => {
|
|
103
108
|
const w = str(worker, 80, 'worker');
|
|
104
109
|
const t = Date.parse(now());
|
|
105
|
-
const
|
|
106
|
-
const
|
|
110
|
+
const isStale = (x) => x.status === 'doing' && t - Date.parse(x.updatedAt) >= STALE_MS;
|
|
111
|
+
const pick = id === undefined ? null : get(str(id, 40, 'id', true));
|
|
112
|
+
if (pick && pick.status !== 'todo' && !isStale(pick)) throw new Error(`item ${pick.id} is "${pick.status}", not free to take`);
|
|
113
|
+
const stale = pick ? (isStale(pick) ? pick : null) : sorted().find(isStale);
|
|
114
|
+
const it = stale || pick || sorted().find((x) => x.status === 'todo');
|
|
107
115
|
if (!it) return null;
|
|
108
116
|
if (stale) it.resumedFrom = it.worker || 'another chat';
|
|
109
117
|
it.status = 'doing'; it.updatedAt = now();
|
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, limit: true },
|
|
24
|
+
theme: 'system', language: 'en', popupStyle: 'toast', notify: { sound: true, offline: true, queueDone: true, queueStalled: true, limit: true },
|
|
25
25
|
deviceName: '', autostart: true, localHistory: false, telemetryEnabled: true,
|
|
26
26
|
...EXTRA.defaults(),
|
|
27
27
|
};
|
|
28
|
-
const NOTIFY = ['sound', 'offline', 'queueDone', 'limit'];
|
|
28
|
+
const NOTIFY = ['sound', 'offline', 'queueDone', 'queueStalled', '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/ui/app.js
CHANGED
|
@@ -331,7 +331,7 @@ P.notifications = () => {
|
|
|
331
331
|
return `<main class="notifications">${bannerHtml()}
|
|
332
332
|
<div class="head"><h1>${esc(t('notify.title'))}</h1><div class="sub">${esc(t('notify.sub'))}</div></div>
|
|
333
333
|
<div class="styles" role="radiogroup" aria-label="${esc(t('aria.style'))}">${style('toast')}${style('popup')}</div>
|
|
334
|
-
<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('limit', 'notify.limit')}</section>
|
|
334
|
+
<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>
|
|
335
335
|
<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>
|
|
336
336
|
<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>
|
|
337
337
|
<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
|
@@ -274,6 +274,7 @@
|
|
|
274
274
|
"sound": "Play a sound",
|
|
275
275
|
"offline": "When the PC goes offline",
|
|
276
276
|
"queueDone": "When a queue task is done",
|
|
277
|
+
"queueStalled": "When a queue task stalls (ChatGPT may be waiting for your OK in the chat)",
|
|
277
278
|
"limit": "Monthly limit warnings",
|
|
278
279
|
"preview": "Preview",
|
|
279
280
|
"light": "Light",
|
|
@@ -364,7 +365,8 @@
|
|
|
364
365
|
"Add tasks here, or ask ChatGPT to plan the work and add the steps itself.",
|
|
365
366
|
"Attach files or folders to a task so ChatGPT knows where to look.",
|
|
366
367
|
"In ChatGPT, say “Work through my Bridgerator queue”. Watch the ticks appear here.",
|
|
367
|
-
"Edit, reorder or delete tasks any time. A failed task shows why it failed."
|
|
368
|
+
"Edit, reorder or delete tasks any time. A failed task shows why it failed.",
|
|
369
|
+
"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."
|
|
368
370
|
],
|
|
369
371
|
"tipLabel": "say",
|
|
370
372
|
"tip": "Work through my Bridgerator queue"
|
package/ui/i18n/ru.json
CHANGED
|
@@ -274,6 +274,7 @@
|
|
|
274
274
|
"sound": "Звук",
|
|
275
275
|
"offline": "Когда ПК уходит из сети",
|
|
276
276
|
"queueDone": "Когда задача из очереди готова",
|
|
277
|
+
"queueStalled": "Когда задача из очереди зависла (ChatGPT может ждать вашего «Разрешить» в чате)",
|
|
277
278
|
"limit": "Предупреждения о лимите",
|
|
278
279
|
"preview": "Пример",
|
|
279
280
|
"light": "Светлая",
|
|
@@ -364,7 +365,8 @@
|
|
|
364
365
|
"Добавляйте задачи здесь или попросите ChatGPT спланировать работу и добавить шаги самому.",
|
|
365
366
|
"Прикрепите к задаче файлы или папки, чтобы ChatGPT знал, где искать.",
|
|
366
367
|
"Скажите в ChatGPT «Work through my Bridgerator queue» и смотрите, как появляются галочки.",
|
|
367
|
-
"Меняйте, переставляйте и удаляйте задачи когда угодно. У невыполненной задачи видно, почему."
|
|
368
|
+
"Меняйте, переставляйте и удаляйте задачи когда угодно. У невыполненной задачи видно, почему.",
|
|
369
|
+
"ChatGPT может попросить в чате разрешить действие — задача ждёт вашего ответа. Если задача зависла, Bridgerator покажет уведомление."
|
|
368
370
|
],
|
|
369
371
|
"tipLabel": "say",
|
|
370
372
|
"tip": "Work through my Bridgerator queue"
|