Skip to content

Commit 5352635

Browse files
committed
fix(tlon): unify settings reconciliation semantics
1 parent a600c72 commit 5352635

2 files changed

Lines changed: 89 additions & 71 deletions

File tree

extensions/tlon/src/monitor/index.ts

Lines changed: 18 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535
isBotMentioned,
3636
stripBotMention,
3737
isDmAllowed,
38+
isGroupInviteAllowed,
3839
isSummarizationRequest,
3940
resolveAuthorizedMessageText,
4041
type ParsedCite,
@@ -1084,69 +1085,22 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
10841085
// during transitions. The authorization check handles access control.
10851086
}
10861087

1087-
// Update DM allowlist
1088-
if (newSettings.dmAllowlist !== undefined) {
1089-
effectiveDmAllowlist = newSettings.dmAllowlist;
1090-
runtime.log?.(`[tlon] Settings: dmAllowlist updated to ${effectiveDmAllowlist.join(", ")}`);
1091-
}
1092-
1093-
// Update model signature setting
1094-
if (newSettings.showModelSig !== undefined) {
1095-
effectiveShowModelSig = newSettings.showModelSig;
1096-
runtime.log?.(`[tlon] Settings: showModelSig = ${effectiveShowModelSig}`);
1097-
}
1098-
1099-
// Update auto-accept DM invites setting
1100-
if (newSettings.autoAcceptDmInvites !== undefined) {
1101-
effectiveAutoAcceptDmInvites = newSettings.autoAcceptDmInvites;
1102-
runtime.log?.(`[tlon] Settings: autoAcceptDmInvites = ${effectiveAutoAcceptDmInvites}`);
1103-
}
1104-
1105-
// Update auto-accept group invites setting
1106-
if (newSettings.autoAcceptGroupInvites !== undefined) {
1107-
effectiveAutoAcceptGroupInvites = newSettings.autoAcceptGroupInvites;
1108-
runtime.log?.(
1109-
`[tlon] Settings: autoAcceptGroupInvites = ${effectiveAutoAcceptGroupInvites}`,
1110-
);
1111-
}
1112-
1113-
// Update group invite allowlist
1114-
if (newSettings.groupInviteAllowlist !== undefined) {
1115-
effectiveGroupInviteAllowlist = newSettings.groupInviteAllowlist;
1116-
runtime.log?.(
1117-
`[tlon] Settings: groupInviteAllowlist updated to ${effectiveGroupInviteAllowlist.join(", ")}`,
1118-
);
1119-
}
1120-
1121-
if (newSettings.defaultAuthorizedShips !== undefined) {
1122-
runtime.log?.(
1123-
`[tlon] Settings: defaultAuthorizedShips updated to ${(newSettings.defaultAuthorizedShips || []).join(", ")}`,
1124-
);
1125-
}
1126-
1127-
// Update auto-discover channels
1128-
if (newSettings.autoDiscoverChannels !== undefined) {
1129-
effectiveAutoDiscoverChannels = newSettings.autoDiscoverChannels;
1130-
runtime.log?.(`[tlon] Settings: autoDiscoverChannels = ${effectiveAutoDiscoverChannels}`);
1131-
}
1132-
1133-
// Update owner ship
1134-
if (newSettings.ownerShip !== undefined) {
1135-
effectiveOwnerShip = newSettings.ownerShip
1136-
? normalizeShip(newSettings.ownerShip)
1137-
: account.ownerShip
1138-
? normalizeShip(account.ownerShip)
1139-
: null;
1140-
runtime.log?.(`[tlon] Settings: ownerShip = ${effectiveOwnerShip}`);
1141-
}
1142-
1143-
// Update pending approvals
1144-
if (newSettings.pendingApprovals !== undefined) {
1145-
pendingApprovals = newSettings.pendingApprovals;
1146-
runtime.log?.(
1147-
`[tlon] Settings: pendingApprovals updated (${pendingApprovals.length} items)`,
1148-
);
1149-
}
1088+
// Recompute effective settings from the latest snapshot so deletions
1089+
// cleanly fall back to file config and empty arrays remain authoritative.
1090+
({
1091+
effectiveDmAllowlist,
1092+
effectiveShowModelSig,
1093+
effectiveAutoAcceptDmInvites,
1094+
effectiveAutoAcceptGroupInvites,
1095+
effectiveGroupInviteAllowlist,
1096+
effectiveAutoDiscoverChannels,
1097+
effectiveOwnerShip,
1098+
pendingApprovals,
1099+
} = applyTlonSettingsOverrides({
1100+
account,
1101+
currentSettings: newSettings,
1102+
log: (message) => runtime.log?.(message),
1103+
}));
11501104
});
11511105

11521106
try {
@@ -1300,8 +1254,6 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
13001254
}
13011255

13021256
const inviterShip = validInvite.from;
1303-
const normalizedInviter = normalizeShip(inviterShip);
1304-
13051257
// Owner invites are always accepted
13061258
if (isOwner(inviterShip)) {
13071259
try {
@@ -1337,12 +1289,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
13371289
}
13381290

13391291
// Check if inviter is on allowlist
1340-
const isAllowed =
1341-
effectiveGroupInviteAllowlist.length > 0
1342-
? effectiveGroupInviteAllowlist
1343-
.map((s) => normalizeShip(s))
1344-
.some((s) => s === normalizedInviter)
1345-
: false; // Fail-safe: empty allowlist means deny
1292+
const isAllowed = isGroupInviteAllowed(inviterShip, effectiveGroupInviteAllowlist);
13461293

13471294
if (!isAllowed) {
13481295
// If owner is configured, queue approval
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { describe, expect, it } from "vitest";
2+
import type { TlonResolvedAccount } from "../types.js";
3+
import { applyTlonSettingsOverrides } from "./settings-helpers.js";
4+
5+
const baseAccount: TlonResolvedAccount = {
6+
accountId: "default",
7+
name: "Tlon",
8+
enabled: true,
9+
configured: true,
10+
ship: "~sampel-palnet",
11+
url: "https://example.com",
12+
code: "lidlut-tabwed-pillex-ridrup",
13+
allowPrivateNetwork: false,
14+
groupChannels: ["chat/~host/general"],
15+
dmAllowlist: ["~zod"],
16+
groupInviteAllowlist: ["~bus"],
17+
autoDiscoverChannels: true,
18+
showModelSignature: false,
19+
autoAcceptDmInvites: true,
20+
autoAcceptGroupInvites: true,
21+
defaultAuthorizedShips: ["~nec"],
22+
ownerShip: "~marzod",
23+
};
24+
25+
describe("applyTlonSettingsOverrides", () => {
26+
it("treats explicit empty settings allowlists as authoritative deny-all", () => {
27+
const result = applyTlonSettingsOverrides({
28+
account: baseAccount,
29+
currentSettings: {
30+
dmAllowlist: [],
31+
groupInviteAllowlist: [],
32+
},
33+
});
34+
35+
expect(result.effectiveDmAllowlist).toEqual([]);
36+
expect(result.effectiveGroupInviteAllowlist).toEqual([]);
37+
});
38+
39+
it("falls back to file config when settings fields are removed", () => {
40+
const result = applyTlonSettingsOverrides({
41+
account: baseAccount,
42+
currentSettings: {},
43+
});
44+
45+
expect(result.effectiveDmAllowlist).toEqual(baseAccount.dmAllowlist);
46+
expect(result.effectiveGroupInviteAllowlist).toEqual(baseAccount.groupInviteAllowlist);
47+
expect(result.effectiveAutoDiscoverChannels).toBe(baseAccount.autoDiscoverChannels);
48+
expect(result.effectiveOwnerShip).toBe(baseAccount.ownerShip);
49+
});
50+
51+
it("keeps other explicit settings overrides authoritative", () => {
52+
const result = applyTlonSettingsOverrides({
53+
account: baseAccount,
54+
currentSettings: {
55+
autoDiscoverChannels: false,
56+
autoAcceptDmInvites: false,
57+
autoAcceptGroupInvites: false,
58+
showModelSig: true,
59+
ownerShip: "~nec",
60+
pendingApprovals: [],
61+
},
62+
});
63+
64+
expect(result.effectiveAutoDiscoverChannels).toBe(false);
65+
expect(result.effectiveAutoAcceptDmInvites).toBe(false);
66+
expect(result.effectiveAutoAcceptGroupInvites).toBe(false);
67+
expect(result.effectiveShowModelSig).toBe(true);
68+
expect(result.effectiveOwnerShip).toBe("~nec");
69+
expect(result.pendingApprovals).toEqual([]);
70+
});
71+
});

0 commit comments

Comments
 (0)