@michael-joseph-miller/ant-bot 0.4.3 → 0.4.5
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/CHANGELOG.md +29 -0
- package/README.md +3 -3
- package/dist/server.js +53 -2
- package/dist/server.js.map +2 -2
- package/package.json +1 -1
- package/web/dist/assets/index-Cfy0hrM2.js +131 -0
- package/web/dist/index.html +1 -1
- package/web/dist/assets/index-De_wWYL1.js +0 -131
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,35 @@ All notable changes to ant-bot are recorded here. The format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions follow
|
|
5
5
|
[semantic versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.4.5] — 2026-08-24
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- **The built-in Gmail connector asks for the whole mailbox.** It requested `gmail.modify`; it now
|
|
12
|
+
requests `https://mail.google.com/` plus `gmail.settings.basic` and `gmail.settings.sharing` —
|
|
13
|
+
read, compose, send, permanent deletion, filters, forwarding and vacation settings. What keeps a
|
|
14
|
+
Bot in check is not the size of the token: `send_message` and `create_draft` carry seeded
|
|
15
|
+
`require` rules, so a human is asked every time regardless. Existing sign-ins keep the narrower
|
|
16
|
+
token until you sign in again.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- **A sign-in older than the scopes now asked for says so.** Widening what a connector requests
|
|
21
|
+
does nothing until the human re-consents, and until then everything reads as healthy while any
|
|
22
|
+
call needing the new permission is refused. `check` now compares the stored token's scopes
|
|
23
|
+
against what the connector asks for and reports `needs sign-in — signed in, but without N newer
|
|
24
|
+
permission(s)`.
|
|
25
|
+
|
|
26
|
+
## [0.4.4] — 2026-08-24
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- **The thread shows the answer, not the work.** A reply that took a dozen searches used to
|
|
31
|
+
arrive behind a dozen boxes. Tool calls now fold into one quiet line — `7 steps`, or
|
|
32
|
+
`Working… search_threads` while a turn is in flight, or `7 steps · 1 failed` — and clicking it
|
|
33
|
+
opens all of them, in order, exactly as before. Approvals, sign-in prompts, errors and files
|
|
34
|
+
still render in full: those are things to act on, not steps to scroll past.
|
|
35
|
+
|
|
7
36
|
## [0.4.3] — 2026-08-24
|
|
8
37
|
|
|
9
38
|
### Fixed
|
package/README.md
CHANGED
|
@@ -281,10 +281,10 @@ Current totals, as run against this checkout:
|
|
|
281
281
|
| Package | Test files | Tests |
|
|
282
282
|
|---|---|---|
|
|
283
283
|
| `@antbot/contract` | 1 | 34 |
|
|
284
|
-
| `@antbot/daemon` | 29 |
|
|
285
|
-
| `@antbot/ui` | 10 |
|
|
284
|
+
| `@antbot/daemon` | 29 | 624 |
|
|
285
|
+
| `@antbot/ui` | 10 | 114 |
|
|
286
286
|
| `@antbot/cli` | 8 | 142 |
|
|
287
|
-
| **Total** | **48** | **
|
|
287
|
+
| **Total** | **48** | **914** |
|
|
288
288
|
|
|
289
289
|
## Status / not built
|
|
290
290
|
|
package/dist/server.js
CHANGED
|
@@ -2455,6 +2455,25 @@ var ConnectorAuthService = class {
|
|
|
2455
2455
|
async write(connectorName, tokens) {
|
|
2456
2456
|
await this.secrets.set(tokenSecretName(connectorName), JSON.stringify(tokens));
|
|
2457
2457
|
}
|
|
2458
|
+
/**
|
|
2459
|
+
* The scopes a stored sign-in actually carries, or null when there is no sign-in.
|
|
2460
|
+
*
|
|
2461
|
+
* A token grants what was consented to when it was minted, not what the client is configured
|
|
2462
|
+
* to be allowed to ask for. Widening the requested list does nothing until the human signs in
|
|
2463
|
+
* again — and without checking, that shows up as a tool that keeps returning "insufficient
|
|
2464
|
+
* permission" with everything looking correctly connected.
|
|
2465
|
+
*/
|
|
2466
|
+
async grantedScopes(connectorName) {
|
|
2467
|
+
const key = tokenSecretName(connectorName);
|
|
2468
|
+
const raw = (await this.secrets.resolve([key])).get(key);
|
|
2469
|
+
if (!raw) return null;
|
|
2470
|
+
try {
|
|
2471
|
+
const parsed = JSON.parse(raw);
|
|
2472
|
+
return typeof parsed.scope === "string" ? parsed.scope.split(/\s+/).filter(Boolean) : [];
|
|
2473
|
+
} catch {
|
|
2474
|
+
return null;
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2458
2477
|
async signOut(connectorName) {
|
|
2459
2478
|
await this.secrets.remove(tokenSecretName(connectorName));
|
|
2460
2479
|
}
|
|
@@ -2844,8 +2863,18 @@ var BUILTIN_CATALOG = {
|
|
|
2844
2863
|
displayName: "Gmail",
|
|
2845
2864
|
description: "Read, search and draft email in the signed-in Gmail account.",
|
|
2846
2865
|
provider: GOOGLE,
|
|
2847
|
-
//
|
|
2848
|
-
scopes
|
|
2866
|
+
// The full mailbox, plus settings. `mail.google.com` subsumes read/compose/send/modify and
|
|
2867
|
+
// adds permanent deletion; the two settings scopes are separate and cover filters, forwarding
|
|
2868
|
+
// and vacation. Listing narrower scopes as well would only lengthen the consent screen.
|
|
2869
|
+
//
|
|
2870
|
+
// Breadth here is not what keeps a bot in check — `mcp__gmail__send_message` and
|
|
2871
|
+
// `mcp__gmail__create_draft` carry seeded `require` rules, so a human is asked every time
|
|
2872
|
+
// whatever the token allows.
|
|
2873
|
+
scopes: [
|
|
2874
|
+
"https://mail.google.com/",
|
|
2875
|
+
"https://www.googleapis.com/auth/gmail.settings.basic",
|
|
2876
|
+
"https://www.googleapis.com/auth/gmail.settings.sharing"
|
|
2877
|
+
],
|
|
2849
2878
|
tools: gmailTools
|
|
2850
2879
|
}
|
|
2851
2880
|
};
|
|
@@ -2889,6 +2918,18 @@ var BuiltinService = class {
|
|
|
2889
2918
|
authorized(name) {
|
|
2890
2919
|
return this.auth?.isAuthorized(name) ?? false;
|
|
2891
2920
|
}
|
|
2921
|
+
/**
|
|
2922
|
+
* Scopes this connector asks for that the stored sign-in does not carry. Empty when the token
|
|
2923
|
+
* covers everything — including when the provider granted a broader scope that subsumes one
|
|
2924
|
+
* asked for, which is why the comparison is by exact string and errs toward "sign in again".
|
|
2925
|
+
*/
|
|
2926
|
+
async missingScopes(name) {
|
|
2927
|
+
const def = this.get(name);
|
|
2928
|
+
if (!def || !this.auth) return [];
|
|
2929
|
+
const granted = await this.auth.grantedScopes(name);
|
|
2930
|
+
if (granted === null) return [];
|
|
2931
|
+
return def.scopes.filter((s) => !granted.includes(s));
|
|
2932
|
+
}
|
|
2892
2933
|
/** Constant-time compare so the bearer cannot be guessed a byte at a time. */
|
|
2893
2934
|
checkBearer(header) {
|
|
2894
2935
|
const given = (header ?? "").replace(/^Bearer\s+/i, "");
|
|
@@ -3097,6 +3138,15 @@ async function probeConnector(config, opts = {}) {
|
|
|
3097
3138
|
// daemon/src/connectors/check.ts
|
|
3098
3139
|
function decideCheck(signals) {
|
|
3099
3140
|
if (signals.builtinProvider) {
|
|
3141
|
+
if (signals.builtinSignedIn && signals.builtinMissingScopes?.length) {
|
|
3142
|
+
return {
|
|
3143
|
+
status: "needs-sign-in",
|
|
3144
|
+
selfRegistration: signals.builtinProvider.dynamicRegistration,
|
|
3145
|
+
provider: signals.builtinProvider.name,
|
|
3146
|
+
tools: signals.probe?.tools ?? [],
|
|
3147
|
+
detail: `signed in, but without ${signals.builtinMissingScopes.length} newer permission(s) \u2014 sign in again to grant them`
|
|
3148
|
+
};
|
|
3149
|
+
}
|
|
3100
3150
|
return signals.builtinSignedIn ? { status: "ready", tools: signals.probe?.tools ?? [], provider: signals.builtinProvider.name } : {
|
|
3101
3151
|
status: "needs-sign-in",
|
|
3102
3152
|
selfRegistration: signals.builtinProvider.dynamicRegistration,
|
|
@@ -3559,6 +3609,7 @@ async function createApp(opts = {}) {
|
|
|
3559
3609
|
challenge: "none",
|
|
3560
3610
|
missingSecrets: [],
|
|
3561
3611
|
builtinSignedIn: app.builtin?.authorized(connector.name) ?? false,
|
|
3612
|
+
builtinMissingScopes: await app.builtin?.missingScopes(connector.name) ?? [],
|
|
3562
3613
|
builtinProvider: def ? { name: def.provider.displayName, dynamicRegistration: def.provider.dynamicRegistration } : void 0
|
|
3563
3614
|
});
|
|
3564
3615
|
} else {
|