@tloncorp/openclaw 0.4.3 → 0.6.1
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 +130 -141
- package/dist/index.js +703 -152
- package/dist/index.js.map +1 -1
- package/dist/setup-api.js +2 -2
- package/dist/setup-entry.js +2 -2
- package/dist/setup-entry.js.map +1 -1
- package/dist/src/account-fields.js +7 -3
- package/dist/src/account-fields.js.map +1 -1
- package/dist/src/actions.js +73 -52
- package/dist/src/actions.js.map +1 -1
- package/dist/src/channel.js +63 -39
- package/dist/src/channel.js.map +1 -1
- package/dist/src/channel.runtime.js +61 -32
- package/dist/src/channel.runtime.js.map +1 -1
- package/dist/src/config-schema.js +24 -4
- package/dist/src/config-schema.js.map +1 -1
- package/dist/src/diagnostic-subscriptions.js +49 -0
- package/dist/src/diagnostic-subscriptions.js.map +1 -0
- package/dist/src/effective-owner.js.map +1 -1
- package/dist/src/gateway-status.js +55 -7
- package/dist/src/gateway-status.js.map +1 -1
- package/dist/src/monitor/approval.js +71 -62
- package/dist/src/monitor/approval.js.map +1 -1
- package/dist/src/monitor/command-auth.js +7 -7
- package/dist/src/monitor/command-auth.js.map +1 -1
- package/dist/src/monitor/command-bridge.js +3 -2
- package/dist/src/monitor/command-bridge.js.map +1 -1
- package/dist/src/monitor/computing-presence.js +76 -12
- package/dist/src/monitor/computing-presence.js.map +1 -1
- package/dist/src/monitor/discovery.js +16 -9
- package/dist/src/monitor/discovery.js.map +1 -1
- package/dist/src/monitor/history.js +58 -26
- package/dist/src/monitor/history.js.map +1 -1
- package/dist/src/monitor/index.js +3018 -2496
- package/dist/src/monitor/index.js.map +1 -1
- package/dist/src/monitor/media.js +106 -78
- package/dist/src/monitor/media.js.map +1 -1
- package/dist/src/monitor/nudge-runner.js +36 -27
- package/dist/src/monitor/nudge-runner.js.map +1 -1
- package/dist/src/monitor/nudge-state.js +7 -11
- package/dist/src/monitor/nudge-state.js.map +1 -1
- package/dist/src/monitor/owner-reply-persistence.js +27 -26
- package/dist/src/monitor/owner-reply-persistence.js.map +1 -1
- package/dist/src/monitor/processed-messages.js.map +1 -1
- package/dist/src/monitor/session-routing.js +261 -0
- package/dist/src/monitor/session-routing.js.map +1 -0
- package/dist/src/monitor/settings-sync.js +1 -8
- package/dist/src/monitor/settings-sync.js.map +1 -1
- package/dist/src/monitor/utils.js +77 -71
- package/dist/src/monitor/utils.js.map +1 -1
- package/dist/src/nudge-decision.js +40 -43
- package/dist/src/nudge-decision.js.map +1 -1
- package/dist/src/nudge-messages.js +9 -9
- package/dist/src/nudge-scheduler.js.map +1 -1
- package/dist/src/owner-listen-command.js +38 -28
- package/dist/src/owner-listen-command.js.map +1 -1
- package/dist/src/pending-nudge.js.map +1 -1
- package/dist/src/runtime.js +10 -6
- package/dist/src/runtime.js.map +1 -1
- package/dist/src/session-roles.js +2 -1
- package/dist/src/session-roles.js.map +1 -1
- package/dist/src/session-route.js +44 -0
- package/dist/src/session-route.js.map +1 -0
- package/dist/src/settings.js +233 -102
- package/dist/src/settings.js.map +1 -1
- package/dist/src/setup-core.js +32 -32
- package/dist/src/setup-core.js.map +1 -1
- package/dist/src/setup-surface.js +19 -19
- package/dist/src/setup-surface.js.map +1 -1
- package/dist/src/shared-state.js +46 -0
- package/dist/src/shared-state.js.map +1 -0
- package/dist/src/targets.js +17 -10
- package/dist/src/targets.js.map +1 -1
- package/dist/src/telemetry.js +764 -34
- package/dist/src/telemetry.js.map +1 -1
- package/dist/src/tlon-binary.js +20 -12
- package/dist/src/tlon-binary.js.map +1 -1
- package/dist/src/tlon-tool-guard.js +5 -5
- package/dist/src/tool-trace.js +17 -13
- package/dist/src/tool-trace.js.map +1 -1
- package/dist/src/types.js +30 -12
- package/dist/src/types.js.map +1 -1
- package/dist/src/urbit/api-client.js +16 -12
- package/dist/src/urbit/api-client.js.map +1 -1
- package/dist/src/urbit/auth.js +9 -9
- package/dist/src/urbit/auth.js.map +1 -1
- package/dist/src/urbit/base-url.js +11 -11
- package/dist/src/urbit/base-url.js.map +1 -1
- package/dist/src/urbit/channel-ops.js +25 -19
- package/dist/src/urbit/channel-ops.js.map +1 -1
- package/dist/src/urbit/context.js +8 -8
- package/dist/src/urbit/context.js.map +1 -1
- package/dist/src/urbit/errors.js +33 -7
- package/dist/src/urbit/errors.js.map +1 -1
- package/dist/src/urbit/fetch.js +3 -3
- package/dist/src/urbit/fetch.js.map +1 -1
- package/dist/src/urbit/http-poke.js +10 -10
- package/dist/src/urbit/http-poke.js.map +1 -1
- package/dist/src/urbit/send.js +27 -23
- package/dist/src/urbit/send.js.map +1 -1
- package/dist/src/urbit/sse-client.js +45 -41
- package/dist/src/urbit/sse-client.js.map +1 -1
- package/dist/src/urbit/story.js +31 -30
- package/dist/src/urbit/story.js.map +1 -1
- package/dist/src/urbit/upload.js +8 -8
- package/dist/src/urbit/upload.js.map +1 -1
- package/dist/src/version.generated.js +2 -1
- package/dist/src/version.generated.js.map +1 -1
- package/dist/src/version.js +134 -0
- package/dist/src/version.js.map +1 -0
- package/openclaw.plugin.json +37 -0
- package/package.json +9 -15
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"processed-messages.js","sourceRoot":"","sources":["../../../src/monitor/processed-messages.ts"],"names":[],"mappings":"AAMA,MAAM,UAAU,6BAA6B,
|
|
1
|
+
{"version":3,"file":"processed-messages.js","sourceRoot":"","sources":["../../../src/monitor/processed-messages.ts"],"names":[],"mappings":"AAMA,MAAM,UAAU,6BAA6B,CAC3C,KAAK,GAAG,IAAI;IAEZ,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,MAAM,IAAI,GAAG,CAAC,EAAkB,EAAE,EAAE;QAClC,MAAM,OAAO,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC;QAC3B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YACtB,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAClB,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpB,IAAI,KAAK,CAAC,MAAM,GAAG,KAAK,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC;YACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;gBAC7B,IAAI,MAAM,EAAE,CAAC;oBACX,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBACtB,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;IAEF,MAAM,GAAG,GAAG,CAAC,EAAkB,EAAE,EAAE;QACjC,MAAM,OAAO,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC;QAC3B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC,CAAC;IAEF,OAAO;QACL,IAAI;QACJ,GAAG;QACH,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI;KACtB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { resolvePinnedMainDmOwnerFromAllowlist } from 'openclaw/plugin-sdk/conversation-runtime';
|
|
2
|
+
import { resolveInboundLastRouteSessionKey, } from 'openclaw/plugin-sdk/routing';
|
|
3
|
+
import { canonicalizeNest, normalizeShip } from '../targets.js';
|
|
4
|
+
/**
|
|
5
|
+
* Build the parameters for persisting a Tlon inbound turn's durable session
|
|
6
|
+
* route. Pure: no I/O, no SDK store access. The caller passes the result to
|
|
7
|
+
* `recordInboundSession` (see `recordTlonInboundRoute`).
|
|
8
|
+
*
|
|
9
|
+
* Routing rules:
|
|
10
|
+
* - DM: persist `tlon:<senderShip>`. When the last-route session is the agent
|
|
11
|
+
* main session and a single owner is pinned, attach `mainDmOwnerPin` so a
|
|
12
|
+
* non-owner DM cannot silently overwrite the owner/main route.
|
|
13
|
+
* - Group/channel: persist `tlon:<groupChannel>` only when the last-route
|
|
14
|
+
* session is NOT the main session (avoid clobbering a broad shared session).
|
|
15
|
+
* Skip — but still record origin metadata — when `groupChannel` is missing.
|
|
16
|
+
*/
|
|
17
|
+
export function buildTlonInboundRouteRecord(input) {
|
|
18
|
+
const { cfg, route, ctxSessionKey, isGroup, groupChannel, senderShip, parentId, deliverParentId, effectiveOwnerShip, effectiveDmAllowlist, } = input;
|
|
19
|
+
const recordSessionKey = ctxSessionKey ?? route.sessionKey;
|
|
20
|
+
const lastRouteSessionKey = resolveInboundLastRouteSessionKey({
|
|
21
|
+
route,
|
|
22
|
+
sessionKey: recordSessionKey,
|
|
23
|
+
});
|
|
24
|
+
const rawThread = deliverParentId ?? parentId;
|
|
25
|
+
const threadId = rawThread != null && rawThread !== '' ? String(rawThread) : undefined;
|
|
26
|
+
const base = { recordSessionKey, lastRouteSessionKey };
|
|
27
|
+
if (isGroup) {
|
|
28
|
+
const nest = groupChannel?.trim();
|
|
29
|
+
if (!nest) {
|
|
30
|
+
return { ...base, target: null, skippedReason: 'group-missing-channel' };
|
|
31
|
+
}
|
|
32
|
+
// Validate/canonicalize the nest before storing. Firehose nests are already
|
|
33
|
+
// canonical, but config/settings-watched values can be malformed; a bad
|
|
34
|
+
// nest would otherwise persist an unusable `lastTo`.
|
|
35
|
+
const canonicalNest = canonicalizeNest(nest);
|
|
36
|
+
if (!canonicalNest) {
|
|
37
|
+
return { ...base, target: null, skippedReason: 'group-invalid-channel' };
|
|
38
|
+
}
|
|
39
|
+
const target = `tlon:${canonicalNest}`;
|
|
40
|
+
// Don't overwrite a broad shared main session with a per-group route.
|
|
41
|
+
if (lastRouteSessionKey === route.mainSessionKey) {
|
|
42
|
+
return {
|
|
43
|
+
...base,
|
|
44
|
+
target,
|
|
45
|
+
skippedReason: 'group-route-targets-main-session',
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
...base,
|
|
50
|
+
target,
|
|
51
|
+
updateLastRoute: {
|
|
52
|
+
sessionKey: lastRouteSessionKey,
|
|
53
|
+
channel: 'tlon',
|
|
54
|
+
to: target,
|
|
55
|
+
...(route.accountId ? { accountId: route.accountId } : {}),
|
|
56
|
+
...(threadId !== undefined ? { threadId } : {}),
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
// DM
|
|
61
|
+
const target = `tlon:${senderShip}`;
|
|
62
|
+
const mainDmOwnerPin = resolveMainDmOwnerPin({
|
|
63
|
+
cfg,
|
|
64
|
+
route,
|
|
65
|
+
lastRouteSessionKey,
|
|
66
|
+
senderShip,
|
|
67
|
+
effectiveOwnerShip,
|
|
68
|
+
effectiveDmAllowlist,
|
|
69
|
+
});
|
|
70
|
+
return {
|
|
71
|
+
...base,
|
|
72
|
+
target,
|
|
73
|
+
updateLastRoute: {
|
|
74
|
+
sessionKey: lastRouteSessionKey,
|
|
75
|
+
channel: 'tlon',
|
|
76
|
+
to: target,
|
|
77
|
+
...(route.accountId ? { accountId: route.accountId } : {}),
|
|
78
|
+
...(threadId !== undefined ? { threadId } : {}),
|
|
79
|
+
...(mainDmOwnerPin ? { mainDmOwnerPin } : {}),
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function resolveMainDmOwnerPin(params) {
|
|
84
|
+
const { cfg, route, lastRouteSessionKey, senderShip, effectiveOwnerShip, effectiveDmAllowlist, } = params;
|
|
85
|
+
// Only the main session can be clobbered by another DM sender; isolated
|
|
86
|
+
// per-peer sessions need no pin.
|
|
87
|
+
if (lastRouteSessionKey !== route.mainSessionKey) {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
const sender = senderShip.trim();
|
|
91
|
+
if (!sender) {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
// Tlon's configured owner (`ownerShip`) is separate from `dmAllowlist`, and
|
|
95
|
+
// owner DMs are valid even when the owner isn't allowlisted. Prefer pinning
|
|
96
|
+
// the configured owner; otherwise fall back to the SDK's allowlist semantics
|
|
97
|
+
// (which only pin when there is exactly one allowed sender).
|
|
98
|
+
const pinnedOwner = resolvePinnedMainDmOwnerFromAllowlist({
|
|
99
|
+
dmScope: cfg.session?.dmScope,
|
|
100
|
+
allowFrom: effectiveOwnerShip ? [effectiveOwnerShip] : effectiveDmAllowlist,
|
|
101
|
+
normalizeEntry: normalizeShip,
|
|
102
|
+
});
|
|
103
|
+
if (!pinnedOwner) {
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
ownerRecipient: pinnedOwner,
|
|
108
|
+
senderRecipient: normalizeShip(sender),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Persist a Tlon inbound turn's session route. Always records origin metadata
|
|
113
|
+
* (even when `record.updateLastRoute` is omitted) and fails open: a persistence
|
|
114
|
+
* failure is logged but never blocks the live reply.
|
|
115
|
+
*/
|
|
116
|
+
export async function recordTlonInboundRoute(deps) {
|
|
117
|
+
const { session, storePath, ctxPayload, record, messageId, accountId } = deps;
|
|
118
|
+
if (record.skippedReason === 'group-missing-channel' ||
|
|
119
|
+
record.skippedReason === 'group-invalid-channel') {
|
|
120
|
+
// Anomalous (a group turn with no/malformed channel nest); surface outside
|
|
121
|
+
// debug too.
|
|
122
|
+
deps.logError?.(`[tlon] route persistence skipped (${record.skippedReason}): ` +
|
|
123
|
+
`messageId=${messageId ?? '?'} lastRouteSessionKey=${record.lastRouteSessionKey}`);
|
|
124
|
+
}
|
|
125
|
+
else if (record.skippedReason) {
|
|
126
|
+
// Normal policy outcome (e.g. a group route that targets the shared main
|
|
127
|
+
// session); debug-only to avoid high-volume logs for an expected case.
|
|
128
|
+
deps.logDebug?.(`[tlon] route persistence skipped (${record.skippedReason}): ` +
|
|
129
|
+
`messageId=${messageId ?? '?'} lastRouteSessionKey=${record.lastRouteSessionKey} ` +
|
|
130
|
+
`target=${record.target ?? '(none)'}`);
|
|
131
|
+
}
|
|
132
|
+
// When a main-session DM is pinned to an owner, the SDK skips the durable
|
|
133
|
+
// route update for a non-owner sender. Wire an onSkip so that decision is
|
|
134
|
+
// observable instead of silently looking like a successful write.
|
|
135
|
+
const pin = record.updateLastRoute?.mainDmOwnerPin;
|
|
136
|
+
const updateLastRoute = record.updateLastRoute
|
|
137
|
+
? {
|
|
138
|
+
...record.updateLastRoute,
|
|
139
|
+
...(pin
|
|
140
|
+
? {
|
|
141
|
+
mainDmOwnerPin: {
|
|
142
|
+
...pin,
|
|
143
|
+
onSkip: ({ ownerRecipient, senderRecipient }) => deps.logDebug?.(`[tlon] durable route update skipped by owner pin: ` +
|
|
144
|
+
`messageId=${messageId ?? '?'} owner=${ownerRecipient} ` +
|
|
145
|
+
`sender=${senderRecipient} lastRouteSessionKey=${record.lastRouteSessionKey}`),
|
|
146
|
+
},
|
|
147
|
+
}
|
|
148
|
+
: {}),
|
|
149
|
+
}
|
|
150
|
+
: undefined;
|
|
151
|
+
try {
|
|
152
|
+
await session.recordInboundSession({
|
|
153
|
+
storePath,
|
|
154
|
+
sessionKey: record.recordSessionKey,
|
|
155
|
+
ctx: ctxPayload,
|
|
156
|
+
updateLastRoute,
|
|
157
|
+
onRecordError: (err) => {
|
|
158
|
+
deps.logError?.(`[tlon] failed updating session meta: ${String(err)}`);
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
deps.logError?.(`[tlon] failed recording inbound session route: ${String(err)} ` +
|
|
164
|
+
`(messageId=${messageId ?? '?'} storePath=${storePath} ` +
|
|
165
|
+
`recordSessionKey=${record.recordSessionKey} ` +
|
|
166
|
+
`lastRouteSessionKey=${record.lastRouteSessionKey} ` +
|
|
167
|
+
`target=${record.target ?? '(none)'} accountId=${accountId ?? '(none)'} ` +
|
|
168
|
+
`hadUpdateLastRoute=${Boolean(record.updateLastRoute)})`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Whether the SDK will skip the durable route update because a main-session DM
|
|
173
|
+
* is pinned to an owner different from the sender. A built `updateLastRoute`
|
|
174
|
+
* does not guarantee a write, so diagnostics should report this rather than
|
|
175
|
+
* imply the route was persisted.
|
|
176
|
+
*/
|
|
177
|
+
export function routeUpdateWillSkipByPin(update) {
|
|
178
|
+
const pin = update?.mainDmOwnerPin;
|
|
179
|
+
if (!pin) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
return pin.ownerRecipient !== pin.senderRecipient;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Run the durable route-record step before reply dispatch. The bug this fixes
|
|
186
|
+
* lives at exactly this boundary: route-dependent sends that happen during
|
|
187
|
+
* dispatch must observe the persisted route, so recording must complete first.
|
|
188
|
+
* Keeping this ordering in one place gives the monitor a testable guard.
|
|
189
|
+
*/
|
|
190
|
+
export async function recordRouteThenDispatch(steps) {
|
|
191
|
+
await steps.record();
|
|
192
|
+
return steps.dispatch();
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* The monitor's "build ctx → record route → dispatch" boundary, as a single
|
|
196
|
+
* testable unit (this is where the original webchat-leak bug lived). Builds the
|
|
197
|
+
* Tlon route record, persists it, and only then runs `dispatch`. The monitor
|
|
198
|
+
* delegates its entire record+dispatch to this so the ordering is covered by a
|
|
199
|
+
* unit test rather than only by the monitor's structure.
|
|
200
|
+
*/
|
|
201
|
+
export async function recordTlonRouteAndDispatch(params) {
|
|
202
|
+
const record = buildTlonInboundRouteRecord({
|
|
203
|
+
cfg: params.cfg,
|
|
204
|
+
route: params.route,
|
|
205
|
+
ctxSessionKey: params.ctxSessionKey,
|
|
206
|
+
isGroup: params.isGroup,
|
|
207
|
+
groupChannel: params.groupChannel,
|
|
208
|
+
senderShip: params.senderShip,
|
|
209
|
+
parentId: params.parentId,
|
|
210
|
+
deliverParentId: params.deliverParentId,
|
|
211
|
+
effectiveOwnerShip: params.effectiveOwnerShip,
|
|
212
|
+
effectiveDmAllowlist: params.effectiveDmAllowlist,
|
|
213
|
+
});
|
|
214
|
+
params.onRecord?.(record);
|
|
215
|
+
return recordRouteThenDispatch({
|
|
216
|
+
// Fail open across the *entire* persistence step — including
|
|
217
|
+
// resolveStorePath, which can throw on bad session-store config — so a
|
|
218
|
+
// persistence failure never suppresses the live Tlon reply.
|
|
219
|
+
record: async () => {
|
|
220
|
+
let storePath;
|
|
221
|
+
try {
|
|
222
|
+
storePath = params.session.resolveStorePath(params.sessionStore, {
|
|
223
|
+
agentId: params.route.agentId,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
params.logError?.(`[tlon] failed resolving session store path: ${String(err)} ` +
|
|
228
|
+
`(messageId=${params.messageId ?? '?'})`);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
await recordTlonInboundRoute({
|
|
232
|
+
session: params.session,
|
|
233
|
+
storePath,
|
|
234
|
+
ctxPayload: params.ctxPayload,
|
|
235
|
+
record,
|
|
236
|
+
messageId: params.messageId,
|
|
237
|
+
accountId: params.route.accountId,
|
|
238
|
+
logError: params.logError,
|
|
239
|
+
logDebug: params.logDebug,
|
|
240
|
+
});
|
|
241
|
+
},
|
|
242
|
+
dispatch: params.dispatch,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Build a Tlon `deliveryContext` for an enqueued system event (reactions,
|
|
247
|
+
* group-join notices). System-event turns resolve delivery from the event's
|
|
248
|
+
* `deliveryContext` or the session store; attaching this ensures a later
|
|
249
|
+
* system/heartbeat turn driven by the event routes to Tlon instead of falling
|
|
250
|
+
* back to webchat, even on a session that hasn't persisted an inbound route yet.
|
|
251
|
+
* `to` is the provider-qualified target (`tlon:~ship` for DMs, `tlon:<nest>` for
|
|
252
|
+
* channels), matching `OriginatingTo` and the durable route.
|
|
253
|
+
*/
|
|
254
|
+
export function tlonDeliveryContext(to, accountId) {
|
|
255
|
+
return { channel: 'tlon', to, ...(accountId ? { accountId } : {}) };
|
|
256
|
+
}
|
|
257
|
+
/** Route-debug gate: enabled via `TLON_OPENCLAW_ROUTE_DEBUG=1`. */
|
|
258
|
+
export function isRouteDebugEnabled() {
|
|
259
|
+
return process.env.TLON_OPENCLAW_ROUTE_DEBUG === '1';
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=session-routing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-routing.js","sourceRoot":"","sources":["../../../src/monitor/session-routing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qCAAqC,EAAE,MAAM,0CAA0C,CAAC;AAEjG,OAAO,EAEL,iCAAiC,GAClC,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AA+DhE;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,2BAA2B,CACzC,KAA4B;IAE5B,MAAM,EACJ,GAAG,EACH,KAAK,EACL,aAAa,EACb,OAAO,EACP,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,eAAe,EACf,kBAAkB,EAClB,oBAAoB,GACrB,GAAG,KAAK,CAAC;IAEV,MAAM,gBAAgB,GAAG,aAAa,IAAI,KAAK,CAAC,UAAU,CAAC;IAC3D,MAAM,mBAAmB,GAAG,iCAAiC,CAAC;QAC5D,KAAK;QACL,UAAU,EAAE,gBAAgB;KAC7B,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,eAAe,IAAI,QAAQ,CAAC;IAC9C,MAAM,QAAQ,GACZ,SAAS,IAAI,IAAI,IAAI,SAAS,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAExE,MAAM,IAAI,GAAG,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,CAAC;IAEvD,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,YAAY,EAAE,IAAI,EAAE,CAAC;QAClC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,uBAAuB,EAAE,CAAC;QAC3E,CAAC;QACD,4EAA4E;QAC5E,wEAAwE;QACxE,qDAAqD;QACrD,MAAM,aAAa,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,OAAO,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,uBAAuB,EAAE,CAAC;QAC3E,CAAC;QACD,MAAM,MAAM,GAAG,QAAQ,aAAa,EAAE,CAAC;QACvC,sEAAsE;QACtE,IAAI,mBAAmB,KAAK,KAAK,CAAC,cAAc,EAAE,CAAC;YACjD,OAAO;gBACL,GAAG,IAAI;gBACP,MAAM;gBACN,aAAa,EAAE,kCAAkC;aAClD,CAAC;QACJ,CAAC;QACD,OAAO;YACL,GAAG,IAAI;YACP,MAAM;YACN,eAAe,EAAE;gBACf,UAAU,EAAE,mBAAmB;gBAC/B,OAAO,EAAE,MAAM;gBACf,EAAE,EAAE,MAAM;gBACV,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC1D,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAChD;SACF,CAAC;IACJ,CAAC;IAED,KAAK;IACL,MAAM,MAAM,GAAG,QAAQ,UAAU,EAAE,CAAC;IACpC,MAAM,cAAc,GAAG,qBAAqB,CAAC;QAC3C,GAAG;QACH,KAAK;QACL,mBAAmB;QACnB,UAAU;QACV,kBAAkB;QAClB,oBAAoB;KACrB,CAAC,CAAC;IAEH,OAAO;QACL,GAAG,IAAI;QACP,MAAM;QACN,eAAe,EAAE;YACf,UAAU,EAAE,mBAAmB;YAC/B,OAAO,EAAE,MAAM;YACf,EAAE,EAAE,MAAM;YACV,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1D,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/C,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9C;KACF,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB,CAAC,MAO9B;IACC,MAAM,EACJ,GAAG,EACH,KAAK,EACL,mBAAmB,EACnB,UAAU,EACV,kBAAkB,EAClB,oBAAoB,GACrB,GAAG,MAAM,CAAC;IAEX,wEAAwE;IACxE,iCAAiC;IACjC,IAAI,mBAAmB,KAAK,KAAK,CAAC,cAAc,EAAE,CAAC;QACjD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC;IACjC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,4EAA4E;IAC5E,4EAA4E;IAC5E,6EAA6E;IAC7E,6DAA6D;IAC7D,MAAM,WAAW,GAAG,qCAAqC,CAAC;QACxD,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,OAAO;QAC7B,SAAS,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,oBAAoB;QAC3E,cAAc,EAAE,aAAa;KAC9B,CAAC,CAAC;IACH,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO;QACL,cAAc,EAAE,WAAW;QAC3B,eAAe,EAAE,aAAa,CAAC,MAAM,CAAC;KACvC,CAAC;AACJ,CAAC;AAgBD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,IAS5C;IACC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;IAE9E,IACE,MAAM,CAAC,aAAa,KAAK,uBAAuB;QAChD,MAAM,CAAC,aAAa,KAAK,uBAAuB,EAChD,CAAC;QACD,2EAA2E;QAC3E,aAAa;QACb,IAAI,CAAC,QAAQ,EAAE,CACb,qCAAqC,MAAM,CAAC,aAAa,KAAK;YAC5D,aAAa,SAAS,IAAI,GAAG,wBAAwB,MAAM,CAAC,mBAAmB,EAAE,CACpF,CAAC;IACJ,CAAC;SAAM,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;QAChC,yEAAyE;QACzE,uEAAuE;QACvE,IAAI,CAAC,QAAQ,EAAE,CACb,qCAAqC,MAAM,CAAC,aAAa,KAAK;YAC5D,aAAa,SAAS,IAAI,GAAG,wBAAwB,MAAM,CAAC,mBAAmB,GAAG;YAClF,UAAU,MAAM,CAAC,MAAM,IAAI,QAAQ,EAAE,CACxC,CAAC;IACJ,CAAC;IAED,0EAA0E;IAC1E,0EAA0E;IAC1E,kEAAkE;IAClE,MAAM,GAAG,GAAG,MAAM,CAAC,eAAe,EAAE,cAAc,CAAC;IACnD,MAAM,eAAe,GACnB,MAAM,CAAC,eAAe;QACpB,CAAC,CAAC;YACE,GAAG,MAAM,CAAC,eAAe;YACzB,GAAG,CAAC,GAAG;gBACL,CAAC,CAAC;oBACE,cAAc,EAAE;wBACd,GAAG,GAAG;wBACN,MAAM,EAAE,CAAC,EAAE,cAAc,EAAE,eAAe,EAAE,EAAE,EAAE,CAC9C,IAAI,CAAC,QAAQ,EAAE,CACb,oDAAoD;4BAClD,aAAa,SAAS,IAAI,GAAG,UAAU,cAAc,GAAG;4BACxD,UAAU,eAAe,wBAAwB,MAAM,CAAC,mBAAmB,EAAE,CAChF;qBACJ;iBACF;gBACH,CAAC,CAAC,EAAE,CAAC;SACR;QACH,CAAC,CAAC,SAAS,CAAC;IAEhB,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,oBAAoB,CAAC;YACjC,SAAS;YACT,UAAU,EAAE,MAAM,CAAC,gBAAgB;YACnC,GAAG,EAAE,UAAU;YACf,eAAe;YACf,aAAa,EAAE,CAAC,GAAG,EAAE,EAAE;gBACrB,IAAI,CAAC,QAAQ,EAAE,CAAC,wCAAwC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACzE,CAAC;SACF,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,QAAQ,EAAE,CACb,kDAAkD,MAAM,CAAC,GAAG,CAAC,GAAG;YAC9D,cAAc,SAAS,IAAI,GAAG,cAAc,SAAS,GAAG;YACxD,oBAAoB,MAAM,CAAC,gBAAgB,GAAG;YAC9C,uBAAuB,MAAM,CAAC,mBAAmB,GAAG;YACpD,UAAU,MAAM,CAAC,MAAM,IAAI,QAAQ,cAAc,SAAS,IAAI,QAAQ,GAAG;YACzE,sBAAsB,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,GAAG,CAC3D,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CACtC,MAA4B;IAE5B,MAAM,GAAG,GAAG,MAAM,EAAE,cAAc,CAAC;IACnC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,GAAG,CAAC,cAAc,KAAK,GAAG,CAAC,eAAe,CAAC;AACpD,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAI,KAGhD;IACC,MAAM,KAAK,CAAC,MAAM,EAAE,CAAC;IACrB,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC;AAC1B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAI,MAuBnD;IACC,MAAM,MAAM,GAAG,2BAA2B,CAAC;QACzC,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;QAC7C,oBAAoB,EAAE,MAAM,CAAC,oBAAoB;KAClD,CAAC,CAAC;IACH,MAAM,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC;IAE1B,OAAO,uBAAuB,CAAC;QAC7B,6DAA6D;QAC7D,uEAAuE;QACvE,4DAA4D;QAC5D,MAAM,EAAE,KAAK,IAAI,EAAE;YACjB,IAAI,SAAiB,CAAC;YACtB,IAAI,CAAC;gBACH,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC,YAAY,EAAE;oBAC/D,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO;iBAC9B,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,QAAQ,EAAE,CACf,+CAA+C,MAAM,CAAC,GAAG,CAAC,GAAG;oBAC3D,cAAc,MAAM,CAAC,SAAS,IAAI,GAAG,GAAG,CAC3C,CAAC;gBACF,OAAO;YACT,CAAC;YACD,MAAM,sBAAsB,CAAC;gBAC3B,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,SAAS;gBACT,UAAU,EAAE,MAAM,CAAC,UAAU;gBAC7B,MAAM;gBACN,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS;gBACjC,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;aAC1B,CAAC,CAAC;QACL,CAAC;QACD,QAAQ,EAAE,MAAM,CAAC,QAAQ;KAC1B,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CACjC,EAAU,EACV,SAAkB;IAElB,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AACtE,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,mBAAmB;IACjC,OAAO,OAAO,CAAC,GAAG,CAAC,yBAAyB,KAAK,GAAG,CAAC;AACvD,CAAC"}
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Pure helper for settings mirror synchronization.
|
|
3
|
-
*
|
|
4
|
-
* Detects ownerShip and pendingNudge transitions from the settings mirror.
|
|
5
|
-
* The scheduler no longer routes through this helper for lastNudgeStage —
|
|
6
|
-
* the authoritative stage lives in a fresh scry plus a local shadow.
|
|
7
|
-
*/
|
|
8
|
-
import { normalizeShip } from "../targets.js";
|
|
1
|
+
import { normalizeShip } from '../targets.js';
|
|
9
2
|
export function resolveSettingsMirrorSync(params) {
|
|
10
3
|
const { prevSettings, newSettings, fileConfigOwnerShip } = params;
|
|
11
4
|
// ownerShip: compare string values (normalize for comparison)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-sync.js","sourceRoot":"","sources":["../../../src/monitor/settings-sync.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"settings-sync.js","sourceRoot":"","sources":["../../../src/monitor/settings-sync.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAS9C,MAAM,UAAU,yBAAyB,CAAC,MAIzC;IACC,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,mBAAmB,EAAE,GAAG,MAAM,CAAC;IAElE,8DAA8D;IAC9D,MAAM,SAAS,GAAG,YAAY,CAAC,SAAS,CAAC;IACzC,MAAM,QAAQ,GAAG,WAAW,CAAC,SAAS,CAAC;IACvC,MAAM,mBAAmB,GAAG,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACxE,MAAM,kBAAkB,GAAG,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACrE,MAAM,gBAAgB,GAAG,mBAAmB,KAAK,kBAAkB,CAAC;IACpE,MAAM,kBAAkB,GACtB,kBAAkB,IAAI,mBAAmB,CAAC;IAE5C,iFAAiF;IACjF,MAAM,mBAAmB,GACvB,YAAY,CAAC,YAAY,KAAK,WAAW,CAAC,YAAY,CAAC;IACzD,MAAM,YAAY,GAAwB,WAAW,CAAC,YAAY,IAAI,IAAI,CAAC;IAE3E,OAAO;QACL,gBAAgB;QAChB,kBAAkB;QAClB,mBAAmB;QACnB,YAAY;KACb,CAAC;AACJ,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { normalizeShip } from
|
|
1
|
+
import { normalizeShip } from '../targets.js';
|
|
2
2
|
// Extract all cites from message content
|
|
3
3
|
export function extractCites(content) {
|
|
4
4
|
if (!content || !Array.isArray(content)) {
|
|
@@ -6,32 +6,32 @@ export function extractCites(content) {
|
|
|
6
6
|
}
|
|
7
7
|
const cites = [];
|
|
8
8
|
for (const verse of content) {
|
|
9
|
-
if (verse?.block?.cite && typeof verse.block.cite ===
|
|
9
|
+
if (verse?.block?.cite && typeof verse.block.cite === 'object') {
|
|
10
10
|
const cite = verse.block.cite;
|
|
11
|
-
if (cite.chan && typeof cite.chan ===
|
|
11
|
+
if (cite.chan && typeof cite.chan === 'object') {
|
|
12
12
|
const { nest, where } = cite.chan;
|
|
13
13
|
const whereMatch = where?.match(/\/msg\/(~[a-z-]+)\/(.+)/);
|
|
14
14
|
cites.push({
|
|
15
|
-
type:
|
|
15
|
+
type: 'chan',
|
|
16
16
|
nest,
|
|
17
17
|
where,
|
|
18
18
|
author: whereMatch?.[1],
|
|
19
19
|
postId: whereMatch?.[2],
|
|
20
20
|
});
|
|
21
21
|
}
|
|
22
|
-
else if (cite.group && typeof cite.group ===
|
|
23
|
-
cites.push({ type:
|
|
22
|
+
else if (cite.group && typeof cite.group === 'string') {
|
|
23
|
+
cites.push({ type: 'group', group: cite.group });
|
|
24
24
|
}
|
|
25
|
-
else if (cite.desk && typeof cite.desk ===
|
|
25
|
+
else if (cite.desk && typeof cite.desk === 'object') {
|
|
26
26
|
cites.push({
|
|
27
|
-
type:
|
|
27
|
+
type: 'desk',
|
|
28
28
|
flag: cite.desk.flag,
|
|
29
29
|
where: cite.desk.where,
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
|
-
else if (cite.bait && typeof cite.bait ===
|
|
32
|
+
else if (cite.bait && typeof cite.bait === 'object') {
|
|
33
33
|
cites.push({
|
|
34
|
-
type:
|
|
34
|
+
type: 'bait',
|
|
35
35
|
group: cite.bait.group,
|
|
36
36
|
nest: cite.bait.graph,
|
|
37
37
|
where: cite.bait.where,
|
|
@@ -43,27 +43,29 @@ export function extractCites(content) {
|
|
|
43
43
|
}
|
|
44
44
|
export function formatModelName(modelString) {
|
|
45
45
|
if (!modelString) {
|
|
46
|
-
return
|
|
46
|
+
return 'AI';
|
|
47
47
|
}
|
|
48
|
-
const modelName = modelString.includes(
|
|
48
|
+
const modelName = modelString.includes('/')
|
|
49
|
+
? modelString.split('/')[1]
|
|
50
|
+
: modelString;
|
|
49
51
|
const modelMappings = {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
'claude-opus-4-5': 'Claude Opus 4.5',
|
|
53
|
+
'claude-sonnet-4-5': 'Claude Sonnet 4.5',
|
|
54
|
+
'claude-sonnet-3-5': 'Claude Sonnet 3.5',
|
|
55
|
+
'gpt-4o': 'GPT-4o',
|
|
56
|
+
'gpt-4-turbo': 'GPT-4 Turbo',
|
|
57
|
+
'gpt-4': 'GPT-4',
|
|
58
|
+
'gemini-2.0-flash': 'Gemini 2.0 Flash',
|
|
59
|
+
'gemini-pro': 'Gemini Pro',
|
|
58
60
|
};
|
|
59
61
|
if (modelMappings[modelName]) {
|
|
60
62
|
return modelMappings[modelName];
|
|
61
63
|
}
|
|
62
64
|
return modelName
|
|
63
|
-
.replace(/-/g,
|
|
64
|
-
.split(
|
|
65
|
+
.replace(/-/g, ' ')
|
|
66
|
+
.split(' ')
|
|
65
67
|
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
66
|
-
.join(
|
|
68
|
+
.join(' ');
|
|
67
69
|
}
|
|
68
70
|
export function isBotMentioned(messageText, botShipName, nickname) {
|
|
69
71
|
if (!messageText || !botShipName) {
|
|
@@ -71,15 +73,15 @@ export function isBotMentioned(messageText, botShipName, nickname) {
|
|
|
71
73
|
}
|
|
72
74
|
// Check for ship mention
|
|
73
75
|
const normalizedBotShip = normalizeShip(botShipName);
|
|
74
|
-
const escapedShip = normalizedBotShip.replace(/[.*+?^${}()|[\]\\]/g,
|
|
75
|
-
const mentionPattern = new RegExp(`(^|\\s)${escapedShip}(?=\\s|$)`,
|
|
76
|
+
const escapedShip = normalizedBotShip.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
77
|
+
const mentionPattern = new RegExp(`(^|\\s)${escapedShip}(?=\\s|$)`, 'i');
|
|
76
78
|
if (mentionPattern.test(messageText)) {
|
|
77
79
|
return true;
|
|
78
80
|
}
|
|
79
81
|
// Check for nickname mention (case-insensitive, word boundary)
|
|
80
82
|
if (nickname) {
|
|
81
|
-
const escapedNickname = nickname.replace(/[.*+?^${}()|[\]\\]/g,
|
|
82
|
-
const nicknamePattern = new RegExp(`(^|\\s)${escapedNickname}(?=\\s|$|[,!?.])`,
|
|
83
|
+
const escapedNickname = nickname.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
84
|
+
const nicknamePattern = new RegExp(`(^|\\s)${escapedNickname}(?=\\s|$|[,!?.])`, 'i');
|
|
83
85
|
if (nicknamePattern.test(messageText)) {
|
|
84
86
|
return true;
|
|
85
87
|
}
|
|
@@ -98,25 +100,25 @@ export function isBotMentioned(messageText, botShipName, nickname) {
|
|
|
98
100
|
*/
|
|
99
101
|
export function shouldEngageInGroup(opts) {
|
|
100
102
|
if (opts.mentioned) {
|
|
101
|
-
return { engage: true, reason:
|
|
103
|
+
return { engage: true, reason: 'mention' };
|
|
102
104
|
}
|
|
103
105
|
if (opts.inParticipatedThread) {
|
|
104
|
-
return { engage: true, reason:
|
|
106
|
+
return { engage: true, reason: 'thread' };
|
|
105
107
|
}
|
|
106
108
|
if (opts.isOwnerBlob) {
|
|
107
|
-
return { engage: true, reason:
|
|
109
|
+
return { engage: true, reason: 'owner-blob' };
|
|
108
110
|
}
|
|
109
111
|
if (!opts.ownerListenEnabled) {
|
|
110
|
-
return { engage: false, reason:
|
|
112
|
+
return { engage: false, reason: 'skip' };
|
|
111
113
|
}
|
|
112
114
|
const isOwner = opts.ownerShip !== null && opts.senderShip === opts.ownerShip;
|
|
113
115
|
const isOwned = opts.groupHost !== null &&
|
|
114
116
|
(opts.groupHost === opts.ownerShip || opts.groupHost === opts.botShipName);
|
|
115
117
|
const disabled = opts.ownerListenDisabledChannels.has(opts.channelNest);
|
|
116
118
|
if (isOwner && isOwned && !disabled) {
|
|
117
|
-
return { engage: true, reason:
|
|
119
|
+
return { engage: true, reason: 'owner-owned' };
|
|
118
120
|
}
|
|
119
|
-
return { engage: false, reason:
|
|
121
|
+
return { engage: false, reason: 'skip' };
|
|
120
122
|
}
|
|
121
123
|
/** Parse "tlon:group:<nest>" → "<nest>", else null. */
|
|
122
124
|
export function nestFromCtxFrom(from) {
|
|
@@ -138,14 +140,16 @@ export function stripBotMention(messageText, botShipName) {
|
|
|
138
140
|
if (!messageText || !botShipName) {
|
|
139
141
|
return messageText;
|
|
140
142
|
}
|
|
141
|
-
return messageText.replace(normalizeShip(botShipName),
|
|
143
|
+
return messageText.replace(normalizeShip(botShipName), '').trim();
|
|
142
144
|
}
|
|
143
145
|
export function isDmAllowed(senderShip, allowlist) {
|
|
144
146
|
if (!allowlist || allowlist.length === 0) {
|
|
145
147
|
return false;
|
|
146
148
|
}
|
|
147
149
|
const normalizedSender = normalizeShip(senderShip);
|
|
148
|
-
return allowlist
|
|
150
|
+
return allowlist
|
|
151
|
+
.map((ship) => normalizeShip(ship))
|
|
152
|
+
.some((ship) => ship === normalizedSender);
|
|
149
153
|
}
|
|
150
154
|
/**
|
|
151
155
|
* Check if a group invite from a ship should be auto-accepted.
|
|
@@ -160,24 +164,26 @@ export function isGroupInviteAllowed(inviterShip, allowlist) {
|
|
|
160
164
|
return false;
|
|
161
165
|
}
|
|
162
166
|
const normalizedInviter = normalizeShip(inviterShip);
|
|
163
|
-
return allowlist
|
|
167
|
+
return allowlist
|
|
168
|
+
.map((ship) => normalizeShip(ship))
|
|
169
|
+
.some((ship) => ship === normalizedInviter);
|
|
164
170
|
}
|
|
165
171
|
// Helper to recursively extract text from inline content
|
|
166
172
|
function extractInlineText(items) {
|
|
167
173
|
return items
|
|
168
174
|
.map((item) => {
|
|
169
|
-
if (typeof item ===
|
|
175
|
+
if (typeof item === 'string') {
|
|
170
176
|
return item;
|
|
171
177
|
}
|
|
172
|
-
if (item && typeof item ===
|
|
178
|
+
if (item && typeof item === 'object') {
|
|
173
179
|
if (item.ship) {
|
|
174
180
|
return item.ship;
|
|
175
181
|
}
|
|
176
|
-
if (
|
|
177
|
-
return `@${item.sect ||
|
|
182
|
+
if ('sect' in item) {
|
|
183
|
+
return `@${item.sect || 'all'}`;
|
|
178
184
|
}
|
|
179
|
-
if (item[
|
|
180
|
-
return `\`${item[
|
|
185
|
+
if (item['inline-code']) {
|
|
186
|
+
return `\`${item['inline-code']}\``;
|
|
181
187
|
}
|
|
182
188
|
if (item.code) {
|
|
183
189
|
return `\`${item.code}\``;
|
|
@@ -195,13 +201,13 @@ function extractInlineText(items) {
|
|
|
195
201
|
return `~~${extractInlineText(item.strike)}~~`;
|
|
196
202
|
}
|
|
197
203
|
}
|
|
198
|
-
return
|
|
204
|
+
return '';
|
|
199
205
|
})
|
|
200
|
-
.join(
|
|
206
|
+
.join('');
|
|
201
207
|
}
|
|
202
208
|
export function extractMessageText(content) {
|
|
203
209
|
if (!content || !Array.isArray(content)) {
|
|
204
|
-
return
|
|
210
|
+
return '';
|
|
205
211
|
}
|
|
206
212
|
return content
|
|
207
213
|
.map((verse) => {
|
|
@@ -209,26 +215,26 @@ export function extractMessageText(content) {
|
|
|
209
215
|
if (verse.inline && Array.isArray(verse.inline)) {
|
|
210
216
|
return verse.inline
|
|
211
217
|
.map((item) => {
|
|
212
|
-
if (typeof item ===
|
|
218
|
+
if (typeof item === 'string') {
|
|
213
219
|
return item;
|
|
214
220
|
}
|
|
215
|
-
if (item && typeof item ===
|
|
221
|
+
if (item && typeof item === 'object') {
|
|
216
222
|
if (item.ship) {
|
|
217
223
|
return item.ship;
|
|
218
224
|
}
|
|
219
225
|
// Handle sect (role mentions like @all)
|
|
220
|
-
if (
|
|
221
|
-
return `@${item.sect ||
|
|
226
|
+
if ('sect' in item) {
|
|
227
|
+
return `@${item.sect || 'all'}`;
|
|
222
228
|
}
|
|
223
229
|
if (item.break !== undefined) {
|
|
224
|
-
return
|
|
230
|
+
return '\n';
|
|
225
231
|
}
|
|
226
232
|
if (item.link && item.link.href) {
|
|
227
233
|
return item.link.href;
|
|
228
234
|
}
|
|
229
235
|
// Handle inline code (Tlon uses "inline-code" key)
|
|
230
|
-
if (item[
|
|
231
|
-
return `\`${item[
|
|
236
|
+
if (item['inline-code']) {
|
|
237
|
+
return `\`${item['inline-code']}\``;
|
|
232
238
|
}
|
|
233
239
|
if (item.code) {
|
|
234
240
|
return `\`${item.code}\``;
|
|
@@ -248,36 +254,36 @@ export function extractMessageText(content) {
|
|
|
248
254
|
return `> ${extractInlineText(item.blockquote)}`;
|
|
249
255
|
}
|
|
250
256
|
}
|
|
251
|
-
return
|
|
257
|
+
return '';
|
|
252
258
|
})
|
|
253
|
-
.join(
|
|
259
|
+
.join('');
|
|
254
260
|
}
|
|
255
261
|
// Handle block content (images, code blocks, etc.)
|
|
256
|
-
if (verse.block && typeof verse.block ===
|
|
262
|
+
if (verse.block && typeof verse.block === 'object') {
|
|
257
263
|
const block = verse.block;
|
|
258
264
|
// Image blocks
|
|
259
265
|
if (block.image && block.image.src) {
|
|
260
|
-
const alt = block.image.alt ? ` (${block.image.alt})` :
|
|
266
|
+
const alt = block.image.alt ? ` (${block.image.alt})` : '';
|
|
261
267
|
return `\n${block.image.src}${alt}\n`;
|
|
262
268
|
}
|
|
263
269
|
// Code blocks
|
|
264
|
-
if (block.code && typeof block.code ===
|
|
265
|
-
const lang = block.code.lang ||
|
|
266
|
-
const code = block.code.code ||
|
|
270
|
+
if (block.code && typeof block.code === 'object') {
|
|
271
|
+
const lang = block.code.lang || '';
|
|
272
|
+
const code = block.code.code || '';
|
|
267
273
|
return `\n\`\`\`${lang}\n${code}\n\`\`\`\n`;
|
|
268
274
|
}
|
|
269
275
|
// Header blocks
|
|
270
|
-
if (block.header && typeof block.header ===
|
|
276
|
+
if (block.header && typeof block.header === 'object') {
|
|
271
277
|
const text = block.header.content
|
|
272
|
-
?.map((item) => (typeof item ===
|
|
273
|
-
.join(
|
|
278
|
+
?.map((item) => (typeof item === 'string' ? item : ''))
|
|
279
|
+
.join('') || '';
|
|
274
280
|
return `\n## ${text}\n`;
|
|
275
281
|
}
|
|
276
282
|
// Cite/quote blocks - parse the reference structure
|
|
277
|
-
if (block.cite && typeof block.cite ===
|
|
283
|
+
if (block.cite && typeof block.cite === 'object') {
|
|
278
284
|
const cite = block.cite;
|
|
279
285
|
// ChanCite - reference to a channel message
|
|
280
|
-
if (cite.chan && typeof cite.chan ===
|
|
286
|
+
if (cite.chan && typeof cite.chan === 'object') {
|
|
281
287
|
const { nest, where } = cite.chan;
|
|
282
288
|
// where is typically /msg/~author/timestamp
|
|
283
289
|
const whereMatch = where?.match(/\/msg\/(~[a-z-]+)\/(.+)/);
|
|
@@ -288,23 +294,23 @@ export function extractMessageText(content) {
|
|
|
288
294
|
return `\n> [quoted from ${nest}]\n`;
|
|
289
295
|
}
|
|
290
296
|
// GroupCite - reference to a group
|
|
291
|
-
if (cite.group && typeof cite.group ===
|
|
297
|
+
if (cite.group && typeof cite.group === 'string') {
|
|
292
298
|
return `\n> [ref: group ${cite.group}]\n`;
|
|
293
299
|
}
|
|
294
300
|
// DeskCite - reference to an app/desk
|
|
295
|
-
if (cite.desk && typeof cite.desk ===
|
|
301
|
+
if (cite.desk && typeof cite.desk === 'object') {
|
|
296
302
|
return `\n> [ref: ${cite.desk.flag}]\n`;
|
|
297
303
|
}
|
|
298
304
|
// BaitCite - reference with group+graph context
|
|
299
|
-
if (cite.bait && typeof cite.bait ===
|
|
305
|
+
if (cite.bait && typeof cite.bait === 'object') {
|
|
300
306
|
return `\n> [ref: ${cite.bait.graph} in ${cite.bait.group}]\n`;
|
|
301
307
|
}
|
|
302
308
|
return `\n> [quoted message]\n`;
|
|
303
309
|
}
|
|
304
310
|
}
|
|
305
|
-
return
|
|
311
|
+
return '';
|
|
306
312
|
})
|
|
307
|
-
.join(
|
|
313
|
+
.join('\n')
|
|
308
314
|
.trim();
|
|
309
315
|
}
|
|
310
316
|
export function isSummarizationRequest(messageText) {
|
|
@@ -342,9 +348,9 @@ export function sanitizeMessageText(text) {
|
|
|
342
348
|
return text;
|
|
343
349
|
}
|
|
344
350
|
// Strip [BLOCK_USER: ~ship | reason] directives entirely
|
|
345
|
-
let sanitized = text.replace(/\[BLOCK_USER:\s*~[\w-]+\s*\|\s*.+?\]/gi,
|
|
351
|
+
let sanitized = text.replace(/\[BLOCK_USER:\s*~[\w-]+\s*\|\s*.+?\]/gi, '');
|
|
346
352
|
// Convert role tags from [brackets] to (parentheses)
|
|
347
|
-
sanitized = sanitized.replace(/\[(owner|user|admin|system)\]/gi,
|
|
353
|
+
sanitized = sanitized.replace(/\[(owner|user|admin|system)\]/gi, '($1)');
|
|
348
354
|
return sanitized;
|
|
349
355
|
}
|
|
350
356
|
//# sourceMappingURL=utils.js.map
|