@agentvault/grok-bridge 0.4.1 → 0.4.3
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/dist/bridge.d.ts
CHANGED
|
@@ -9,9 +9,6 @@
|
|
|
9
9
|
* Those are Claude-shaped; Grok's gate is the pre_tool_use hook and arrives with
|
|
10
10
|
* the tools-on posture.
|
|
11
11
|
*/
|
|
12
|
-
/** `RoomSession` is declared ONCE in this package, by grok-session.ts. The Claude
|
|
13
|
-
* bridge declares its own in its bridge.ts; that declaration was NOT copied.
|
|
14
|
-
* Type-only, so this cannot create a runtime import cycle. */
|
|
15
12
|
import type { RoomSession } from "./grok-session.js";
|
|
16
13
|
export interface RoomMessage {
|
|
17
14
|
roomId: string;
|
|
@@ -167,6 +164,12 @@ export declare function attachLifecycle(channel: LifecycleChannel, opts?: {
|
|
|
167
164
|
*/
|
|
168
165
|
export declare function roomTurnPrefix(roomId: string, senderName: string, roomName?: string): string;
|
|
169
166
|
export declare function wireBridge(channel: RoomChannel, session: RoomSession, target: ActiveTarget, opts?: {
|
|
167
|
+
/**
|
|
168
|
+
* #1107: this agent's own name, used to recognise its own @mention. Threaded
|
|
169
|
+
* from the bridge config. Without it the agent can only ever answer @all —
|
|
170
|
+
* `_makeOwesReply` warns once, loudly, rather than going quietly deaf.
|
|
171
|
+
*/
|
|
172
|
+
agentName?: string;
|
|
170
173
|
roomFilter?: string;
|
|
171
174
|
log?: (msg: string) => void;
|
|
172
175
|
}): void;
|
package/dist/index.js
CHANGED
|
@@ -1074,6 +1074,28 @@ var __toESM = (mod4, isNodeMode, target) => (target = mod4 != null ? __create(__
|
|
|
1074
1074
|
isNodeMode || !mod4 || !mod4.__esModule ? __defProp2(target, "default", { value: mod4, enumerable: true }) : target,
|
|
1075
1075
|
mod4
|
|
1076
1076
|
));
|
|
1077
|
+
function stripWrappers(s2) {
|
|
1078
|
+
let start = 0;
|
|
1079
|
+
let end = s2.length;
|
|
1080
|
+
while (start < end && WRAPPERS.includes(s2[start])) start++;
|
|
1081
|
+
while (end > start && WRAPPERS.includes(s2[end - 1])) end--;
|
|
1082
|
+
return s2.slice(start, end);
|
|
1083
|
+
}
|
|
1084
|
+
function isAbstention(text) {
|
|
1085
|
+
if (typeof text !== "string") return false;
|
|
1086
|
+
return stripWrappers(text).toLowerCase().startsWith(SENTINEL);
|
|
1087
|
+
}
|
|
1088
|
+
var SENTINEL;
|
|
1089
|
+
var WRAPPERS;
|
|
1090
|
+
var INSTRUCTION;
|
|
1091
|
+
var init_abstention = __esm2({
|
|
1092
|
+
"src/abstention.ts"() {
|
|
1093
|
+
"use strict";
|
|
1094
|
+
SENTINEL = "[[no-reply]]";
|
|
1095
|
+
WRAPPERS = " \r\n`\"'*_";
|
|
1096
|
+
INSTRUCTION = "not every message needs an answer from you: if this one is not addressed to you and asks nothing of you, reply with exactly " + SENTINEL + " and nothing else \u2014 that is discarded, not posted, and is how you stay quiet; never post a message SAYING that you are staying quiet";
|
|
1097
|
+
}
|
|
1098
|
+
});
|
|
1077
1099
|
function toEpoch(v2) {
|
|
1078
1100
|
if (typeof v2 === "bigint") return v2;
|
|
1079
1101
|
if (typeof v2 === "number") {
|
|
@@ -63752,6 +63774,39 @@ var init_mls_group = __esm2({
|
|
|
63752
63774
|
const s2 = this._requireState();
|
|
63753
63775
|
return s2.groupContext.groupId;
|
|
63754
63776
|
}
|
|
63777
|
+
/**
|
|
63778
|
+
* Proof that this client actually holds the group's keys at its current
|
|
63779
|
+
* epoch. Throws if not initialized.
|
|
63780
|
+
*
|
|
63781
|
+
* RFC 9420 §8.2's `epoch_authenticator`, derived from the epoch secret. Two
|
|
63782
|
+
* properties make it the thing this codebase has been missing:
|
|
63783
|
+
*
|
|
63784
|
+
* * every member at the same epoch computes the SAME value, so it is
|
|
63785
|
+
* comparable across clients and can be checked by a server;
|
|
63786
|
+
* * it cannot be computed without the key schedule, so possessing it is
|
|
63787
|
+
* evidence of membership rather than a claim about it. RFC 9420 names
|
|
63788
|
+
* this as its purpose: "to authenticate the shared group state".
|
|
63789
|
+
*
|
|
63790
|
+
* It is safe to publish. It is a KDF output over the epoch secret, not the
|
|
63791
|
+
* secret, and the RFC intends it to be shown to out-of-band verifiers.
|
|
63792
|
+
*
|
|
63793
|
+
* WHY THIS EXISTS. `mls_groups.member_device_ids` records membership; the
|
|
63794
|
+
* ability to decrypt lives only in one browser's localStorage. Nothing
|
|
63795
|
+
* compared the two, and nothing could — so a device in the roster holding no
|
|
63796
|
+
* keys was indistinguishable from a healthy one, on every signal the server
|
|
63797
|
+
* has. Measured on production 2026-08-26: one owner device carried the keys
|
|
63798
|
+
* for 19 of the 21 owner leaves on the platform, and one 1:1 group had been
|
|
63799
|
+
* unreadable by its owner's browser for two months while every status column
|
|
63800
|
+
* read healthy.
|
|
63801
|
+
*
|
|
63802
|
+
* `epoch` alone cannot do this job: it is a number the client reports about
|
|
63803
|
+
* itself, it collides across groups, and a client that has lost its state
|
|
63804
|
+
* still remembers one.
|
|
63805
|
+
*/
|
|
63806
|
+
get epochAuthenticator() {
|
|
63807
|
+
const s2 = this._requireState();
|
|
63808
|
+
return s2.keySchedule.epochAuthenticator;
|
|
63809
|
+
}
|
|
63755
63810
|
/** The cipher suite name in use. */
|
|
63756
63811
|
get ciphersuiteName() {
|
|
63757
63812
|
return this._ciphersuiteName;
|
|
@@ -63902,11 +63957,84 @@ var init_mls_group = __esm2({
|
|
|
63902
63957
|
return { commit: commitBytes, welcome: welcomeBytes };
|
|
63903
63958
|
}
|
|
63904
63959
|
/**
|
|
63905
|
-
*
|
|
63960
|
+
* Admit N members with TWO commits total, replacing any stale leaf they hold.
|
|
63961
|
+
*
|
|
63962
|
+
* `addMembers` cannot do this alone: MLS rejects an Add for an identity
|
|
63963
|
+
* already in the tree, so a member that lost its local state must be removed
|
|
63964
|
+
* first. Doing that pair PER MEMBER is what the fulfiller did, and it is not
|
|
63965
|
+
* merely slow — it is self-defeating.
|
|
63966
|
+
*
|
|
63967
|
+
* Live 2026-08-28 14:02:21-28Z: the owner sweep re-admitted 7 room members
|
|
63968
|
+
* sequentially, each as its own removeMember + addMembers. Room 007 ran
|
|
63969
|
+
* **epoch 71 -> 85 in seven seconds**, and the Welcome minted for member n
|
|
63970
|
+
* named an epoch that member n+1's commit had already replaced — so six of
|
|
63971
|
+
* seven were stale before they finished joining, and one (`smartcode`) could
|
|
63972
|
+
* not replay forward afterwards at all.
|
|
63973
|
+
*
|
|
63974
|
+
* 🎯 A REPAIR THAT MOVES THE EPOCH ONCE PER MEMBER IS RACING ITSELF.
|
|
63975
|
+
*
|
|
63976
|
+
* ⚠️ **Why two commits and not one.** RFC 9420 §12.3 allows Remove and Add in
|
|
63977
|
+
* a single commit, and ts-mls builds it happily — but with MORE THAN ONE of
|
|
63978
|
+
* each, a REMAINING member fails to process it:
|
|
63906
63979
|
*
|
|
63907
|
-
*
|
|
63908
|
-
*
|
|
63980
|
+
* OpenError at applyUpdatePathSecret (ts-mls/src/createCommit.ts:471)
|
|
63981
|
+
* at updatePrivateKeyPath (processMessages.ts:397)
|
|
63982
|
+
*
|
|
63983
|
+
* One remove + one add in a single commit is fine; 2+2 is not. That is
|
|
63984
|
+
* pinned by a test in `mls-group.test.ts` so this cannot be "optimised" back
|
|
63985
|
+
* into one commit without the failure showing up first. Two commits still
|
|
63986
|
+
* turns 7 members from 14 epochs into 2, and every joiner lands current.
|
|
63987
|
+
*
|
|
63988
|
+
* @param keyPackages - Fresh KeyPackages, one per member to admit. Members
|
|
63989
|
+
* already holding a leaf are removed by the first commit; members with no
|
|
63990
|
+
* leaf are plain adds. Duplicate identities keep the first KeyPackage.
|
|
63991
|
+
* @returns Every commit to broadcast IN ORDER, and the Welcome to deliver to
|
|
63992
|
+
* EVERY member in the batch (each finds its own secrets inside it).
|
|
63909
63993
|
*/
|
|
63994
|
+
async reAdmitMembers(keyPackages) {
|
|
63995
|
+
this._requireState();
|
|
63996
|
+
await this._ensureCiphersuite();
|
|
63997
|
+
const seenIdentities = [];
|
|
63998
|
+
const toAdd = [];
|
|
63999
|
+
const leavesToRemove = [];
|
|
64000
|
+
for (const kp of keyPackages) {
|
|
64001
|
+
const identity = keyPackageIdentity(kp);
|
|
64002
|
+
if (identity !== null) {
|
|
64003
|
+
if (seenIdentities.some((id) => bytesEqual(id, identity)))
|
|
64004
|
+
continue;
|
|
64005
|
+
seenIdentities.push(identity);
|
|
64006
|
+
const leaf = this.memberLeafIndex(identity);
|
|
64007
|
+
if (leaf !== null)
|
|
64008
|
+
leavesToRemove.push(leaf);
|
|
64009
|
+
}
|
|
64010
|
+
toAdd.push(kp);
|
|
64011
|
+
}
|
|
64012
|
+
if (toAdd.length === 0) {
|
|
64013
|
+
throw new Error("reAdmitMembers: no members to admit");
|
|
64014
|
+
}
|
|
64015
|
+
const commits = [];
|
|
64016
|
+
if (leavesToRemove.length > 0) {
|
|
64017
|
+
const { commit } = await this.removeMembers(leavesToRemove);
|
|
64018
|
+
commits.push({ commit, epoch: this.epoch });
|
|
64019
|
+
}
|
|
64020
|
+
const added = await this.addMembers(toAdd);
|
|
64021
|
+
commits.push({ commit: added.commit, epoch: this.epoch });
|
|
64022
|
+
return { commits, welcome: added.welcome };
|
|
64023
|
+
}
|
|
64024
|
+
async removeMembers(memberIndices) {
|
|
64025
|
+
const s2 = this._requireState();
|
|
64026
|
+
const cs = await this._ensureCiphersuite();
|
|
64027
|
+
if (memberIndices.length === 0) {
|
|
64028
|
+
throw new Error("removeMembers: no members to remove");
|
|
64029
|
+
}
|
|
64030
|
+
const extraProposals = memberIndices.map((removed) => ({
|
|
64031
|
+
proposalType: "remove",
|
|
64032
|
+
remove: { removed }
|
|
64033
|
+
}));
|
|
64034
|
+
const result = await createCommit({ state: s2, cipherSuite: cs, pskIndex: this._pskIndex }, { extraProposals });
|
|
64035
|
+
this.state = result.newState;
|
|
64036
|
+
return { commit: encodeMlsMessage(result.commit) };
|
|
64037
|
+
}
|
|
63910
64038
|
async removeMember(memberIndex) {
|
|
63911
64039
|
const s2 = this._requireState();
|
|
63912
64040
|
const cs = await this._ensureCiphersuite();
|
|
@@ -64461,17 +64589,28 @@ var init_mls_kp_pool = __esm2({
|
|
|
64461
64589
|
}
|
|
64462
64590
|
});
|
|
64463
64591
|
function ownIdentity() {
|
|
64464
|
-
const v2 = true ? "0.23.
|
|
64592
|
+
const v2 = true ? "0.23.30" : FALLBACK;
|
|
64465
64593
|
return `${PACKAGE}@${v2}`;
|
|
64466
64594
|
}
|
|
64595
|
+
function buildSha() {
|
|
64596
|
+
const raw = true ? "1fff5d6" : "";
|
|
64597
|
+
const cleaned = (raw ?? "").trim();
|
|
64598
|
+
return !cleaned || cleaned === "unknown" ? null : cleaned;
|
|
64599
|
+
}
|
|
64600
|
+
function withBuildSha(identity) {
|
|
64601
|
+
const sha = buildSha();
|
|
64602
|
+
if (!sha || identity.includes("+")) return identity;
|
|
64603
|
+
const stamped = `${identity}+${sha}`;
|
|
64604
|
+
return stamped.length <= MAX_LEN ? stamped : identity;
|
|
64605
|
+
}
|
|
64467
64606
|
function buildClientVersion(override) {
|
|
64468
64607
|
try {
|
|
64469
64608
|
const candidate = (override ?? "").trim();
|
|
64470
64609
|
if (candidate) {
|
|
64471
|
-
const cleaned = candidate.replace(DISALLOWED, "").slice(0, MAX_LEN);
|
|
64610
|
+
const cleaned = withBuildSha(candidate.replace(DISALLOWED, "").slice(0, MAX_LEN));
|
|
64472
64611
|
if (cleaned && !cleaned.includes("..")) return cleaned;
|
|
64473
64612
|
}
|
|
64474
|
-
return ownIdentity().replace(DISALLOWED, "").slice(0, MAX_LEN);
|
|
64613
|
+
return withBuildSha(ownIdentity().replace(DISALLOWED, "").slice(0, MAX_LEN));
|
|
64475
64614
|
} catch {
|
|
64476
64615
|
return FALLBACK;
|
|
64477
64616
|
}
|
|
@@ -65373,6 +65512,7 @@ var SecureChannel;
|
|
|
65373
65512
|
var init_channel = __esm2({
|
|
65374
65513
|
async "src/channel.ts"() {
|
|
65375
65514
|
"use strict";
|
|
65515
|
+
init_abstention();
|
|
65376
65516
|
init_mls_commit_classify();
|
|
65377
65517
|
await init_libsodium_wrappers();
|
|
65378
65518
|
await init_dist();
|
|
@@ -65802,6 +65942,18 @@ var init_channel = __esm2({
|
|
|
65802
65942
|
get ownHubAddress() {
|
|
65803
65943
|
return this._persisted?.hubAddress ?? "";
|
|
65804
65944
|
}
|
|
65945
|
+
/** This agent's AgentVault hub_id. "" until enrolment persists it.
|
|
65946
|
+
*
|
|
65947
|
+
* Lives in the credential store, NOT in the channel config — which is where
|
|
65948
|
+
* the memory-recall helper was reading it from. `channel.config.hubId` is
|
|
65949
|
+
* unset for every agent enrolled through the normal flow, so
|
|
65950
|
+
* `channel.config.hubId || ""` produced `/api/v1/agents//memory/search`, a
|
|
65951
|
+
* 404 on every inbound message, swallowed by `if (!res.ok) return ""`.
|
|
65952
|
+
* Memory recall was silently dead while the hub_id sat right here.
|
|
65953
|
+
*/
|
|
65954
|
+
get ownHubId() {
|
|
65955
|
+
return this._persisted?.hubId ?? "";
|
|
65956
|
+
}
|
|
65805
65957
|
/** Public best-effort trigger to (re)resolve this agent's display_name.
|
|
65806
65958
|
* Called lazily from the 1:1 DM path when the name is still unknown, so a
|
|
65807
65959
|
* resolve that failed at connect (or a fresh agent that hadn't registered
|
|
@@ -66190,6 +66342,7 @@ var init_channel = __esm2({
|
|
|
66190
66342
|
* Each session gets the same plaintext encrypted independently.
|
|
66191
66343
|
*/
|
|
66192
66344
|
async send(plaintext, options) {
|
|
66345
|
+
if (isAbstention(plaintext)) return;
|
|
66193
66346
|
if (this._state === "error" || this._state === "idle") {
|
|
66194
66347
|
throw new Error("Channel is not ready");
|
|
66195
66348
|
}
|
|
@@ -66518,7 +66671,7 @@ var init_channel = __esm2({
|
|
|
66518
66671
|
*/
|
|
66519
66672
|
sendActivitySpan(spanData) {
|
|
66520
66673
|
if (!this._ws || this._ws.readyState !== WebSocket.OPEN) return;
|
|
66521
|
-
const pluginVersion = true ? "0.23.
|
|
66674
|
+
const pluginVersion = true ? "0.23.30" : "0.0.0-dev";
|
|
66522
66675
|
const agentName = this.config.agentName ?? "Agent";
|
|
66523
66676
|
const resource = {
|
|
66524
66677
|
"service.name": "agentvault-agent",
|
|
@@ -66712,6 +66865,7 @@ var init_channel = __esm2({
|
|
|
66712
66865
|
* Uses MLS (preferred) or pairwise fan-out as fallback.
|
|
66713
66866
|
*/
|
|
66714
66867
|
async sendToRoom(roomId, plaintext, opts) {
|
|
66868
|
+
if (isAbstention(plaintext)) return;
|
|
66715
66869
|
if (!this._persisted?.rooms?.[roomId]) {
|
|
66716
66870
|
throw new Error(`Room ${roomId} not found`);
|
|
66717
66871
|
}
|
|
@@ -68455,7 +68609,7 @@ var init_channel = __esm2({
|
|
|
68455
68609
|
agentVersion: this.config.agentVersion ?? "0.0.0",
|
|
68456
68610
|
// __AV_VERSION__ is injected by esbuild from package.json at build time.
|
|
68457
68611
|
// Falls back to "0.0.0-dev" in non-bundled contexts (tests).
|
|
68458
|
-
pluginVersion: true ? "0.23.
|
|
68612
|
+
pluginVersion: true ? "0.23.30" : "0.0.0-dev"
|
|
68459
68613
|
});
|
|
68460
68614
|
this._telemetryReporter.startAutoFlush(3e4);
|
|
68461
68615
|
}
|
|
@@ -68779,7 +68933,7 @@ var init_channel = __esm2({
|
|
|
68779
68933
|
agentVersion: this.config.agentVersion ?? "0.0.0",
|
|
68780
68934
|
// __AV_VERSION__ is injected by esbuild from package.json at build time.
|
|
68781
68935
|
// Falls back to "0.0.0-dev" in non-bundled contexts (tests).
|
|
68782
|
-
pluginVersion: true ? "0.23.
|
|
68936
|
+
pluginVersion: true ? "0.23.30" : "0.0.0-dev"
|
|
68783
68937
|
});
|
|
68784
68938
|
this._telemetryReporter.startAutoFlush(3e4);
|
|
68785
68939
|
}
|
|
@@ -72923,6 +73077,58 @@ var init_gateway_send = __esm2({
|
|
|
72923
73077
|
init_openclaw_compat();
|
|
72924
73078
|
}
|
|
72925
73079
|
});
|
|
73080
|
+
function parseMentions(text) {
|
|
73081
|
+
const mentions = [];
|
|
73082
|
+
const re2 = new RegExp(MENTION_RE.source, MENTION_RE.flags);
|
|
73083
|
+
let match;
|
|
73084
|
+
while ((match = re2.exec(text)) !== null) {
|
|
73085
|
+
mentions.push(match[1].toLowerCase());
|
|
73086
|
+
}
|
|
73087
|
+
return mentions;
|
|
73088
|
+
}
|
|
73089
|
+
function resolveOwn(mention, names) {
|
|
73090
|
+
if (names.has(mention)) return mention;
|
|
73091
|
+
const parts = mention.split("-");
|
|
73092
|
+
for (let i2 = parts.length - 1; i2 > 0; i2--) {
|
|
73093
|
+
const candidate = parts.slice(0, i2).join("-");
|
|
73094
|
+
if (names.has(candidate)) return candidate;
|
|
73095
|
+
}
|
|
73096
|
+
return null;
|
|
73097
|
+
}
|
|
73098
|
+
function owesRoomReply(plaintext, agentName, accountId, senderIsAgent, roomDisplayName, ownDisplayName, selfResolved = true) {
|
|
73099
|
+
const mentions = parseMentions(plaintext);
|
|
73100
|
+
if (mentions.length === 0) return false;
|
|
73101
|
+
const ownNames = ownRoomNames(agentName, accountId, roomDisplayName, ownDisplayName);
|
|
73102
|
+
if (mentions.some((m2) => resolveOwn(m2, ownNames) !== null)) return true;
|
|
73103
|
+
if (mentions.some((m2) => resolveOwn(m2, BROADCAST_NAMES) !== null)) {
|
|
73104
|
+
return senderIsAgent !== true;
|
|
73105
|
+
}
|
|
73106
|
+
if (!selfResolved) return true;
|
|
73107
|
+
return false;
|
|
73108
|
+
}
|
|
73109
|
+
function ownRoomNames(agentName, accountId, roomDisplayName, ownDisplayName) {
|
|
73110
|
+
const names = /* @__PURE__ */ new Set();
|
|
73111
|
+
const add4 = (n2) => {
|
|
73112
|
+
if (!n2) return;
|
|
73113
|
+
const lower = n2.toLowerCase();
|
|
73114
|
+
names.add(lower);
|
|
73115
|
+
names.add(lower.split(/[\s(]/)[0]);
|
|
73116
|
+
};
|
|
73117
|
+
add4(agentName);
|
|
73118
|
+
add4(accountId);
|
|
73119
|
+
add4(roomDisplayName);
|
|
73120
|
+
add4(ownDisplayName);
|
|
73121
|
+
return names;
|
|
73122
|
+
}
|
|
73123
|
+
var MENTION_RE;
|
|
73124
|
+
var BROADCAST_NAMES;
|
|
73125
|
+
var init_room_protocol = __esm2({
|
|
73126
|
+
"src/room-protocol.ts"() {
|
|
73127
|
+
"use strict";
|
|
73128
|
+
MENTION_RE = /@([\w-]+)/gi;
|
|
73129
|
+
BROADCAST_NAMES = /* @__PURE__ */ new Set(["all", "everyone"]);
|
|
73130
|
+
}
|
|
73131
|
+
});
|
|
72926
73132
|
var init_llm_response_parser = __esm2({
|
|
72927
73133
|
"src/llm-response-parser.ts"() {
|
|
72928
73134
|
"use strict";
|
|
@@ -72956,6 +73162,7 @@ var isUsingManagedRoutes;
|
|
|
72956
73162
|
var init_openclaw_entry = __esm2({
|
|
72957
73163
|
"src/openclaw-entry.ts"() {
|
|
72958
73164
|
"use strict";
|
|
73165
|
+
init_room_protocol();
|
|
72959
73166
|
init_account_config();
|
|
72960
73167
|
init_fetch_interceptor();
|
|
72961
73168
|
init_http_handlers();
|
|
@@ -99014,7 +99221,8 @@ var init_index = __esm2({
|
|
|
99014
99221
|
init_skill_invoker();
|
|
99015
99222
|
await init_skill_telemetry();
|
|
99016
99223
|
await init_policy_enforcer();
|
|
99017
|
-
|
|
99224
|
+
init_room_protocol();
|
|
99225
|
+
VERSION = true ? "0.23.30" : "0.0.0-dev";
|
|
99018
99226
|
}
|
|
99019
99227
|
});
|
|
99020
99228
|
await init_index();
|
|
@@ -99767,9 +99975,32 @@ function roomTurnPrefix(roomId, senderName, roomName) {
|
|
|
99767
99975
|
const room = roomName ? `"${roomName}"` : roomId.slice(0, 8);
|
|
99768
99976
|
return `[room ${room} | ${senderName}]`;
|
|
99769
99977
|
}
|
|
99978
|
+
function _makeOwesReply(agentName, channel, log) {
|
|
99979
|
+
let warnedNoIdentity = false;
|
|
99980
|
+
return (e) => {
|
|
99981
|
+
const own = agentName ?? "";
|
|
99982
|
+
const hub = channel.ownDisplayName ?? "";
|
|
99983
|
+
if (!own && !hub && !warnedNoIdentity) {
|
|
99984
|
+
warnedNoIdentity = true;
|
|
99985
|
+
log(
|
|
99986
|
+
"WARNING: this bridge has no agentName and no hub display_name, so it cannot recognise its own @mention (#1107). It will answer @all and any @-addressed message (fail-open), but targeted replies will be unreliable. Set the agent name in the bridge config."
|
|
99987
|
+
);
|
|
99988
|
+
}
|
|
99989
|
+
return owesRoomReply(
|
|
99990
|
+
e.plaintext,
|
|
99991
|
+
own,
|
|
99992
|
+
own,
|
|
99993
|
+
e.senderIsAgent,
|
|
99994
|
+
void 0,
|
|
99995
|
+
hub,
|
|
99996
|
+
Boolean(own || hub)
|
|
99997
|
+
);
|
|
99998
|
+
};
|
|
99999
|
+
}
|
|
99770
100000
|
function wireBridge(channel, session, target, opts = {}) {
|
|
99771
100001
|
const log = opts.log ?? (() => {
|
|
99772
100002
|
});
|
|
100003
|
+
const _owesReply = _makeOwesReply(opts.agentName, channel, log);
|
|
99773
100004
|
channel.on("error", (err) => {
|
|
99774
100005
|
const msg = err instanceof Error ? err.message : String(err);
|
|
99775
100006
|
log(`channel error (non-fatal, not a reconnect trigger): ${msg}`);
|
|
@@ -99808,7 +100039,7 @@ function wireBridge(channel, session, target, opts = {}) {
|
|
|
99808
100039
|
target.setRoom(e.roomId);
|
|
99809
100040
|
session.push(`${roomTurnPrefix(e.roomId, e.senderName, roomNames.get(e.roomId))}: ${e.plaintext}`, target.snapshotReply(channel, log), {
|
|
99810
100041
|
autoReplyOnText: false,
|
|
99811
|
-
replyExpected: e
|
|
100042
|
+
replyExpected: _owesReply(e)
|
|
99812
100043
|
});
|
|
99813
100044
|
});
|
|
99814
100045
|
channel.on("message", (text, metadata) => {
|
|
@@ -99917,7 +100148,7 @@ async function main() {
|
|
|
99917
100148
|
const info = parseInfoFlags(process.argv.slice(2));
|
|
99918
100149
|
if (info.showVersion || info.showHelp) {
|
|
99919
100150
|
const version2 = buildClientVersion2(
|
|
99920
|
-
true ? "0.4.
|
|
100151
|
+
true ? "0.4.3" : void 0
|
|
99921
100152
|
);
|
|
99922
100153
|
if (info.showVersion) printLine(version2);
|
|
99923
100154
|
if (info.showHelp) {
|
|
@@ -99970,7 +100201,7 @@ async function main() {
|
|
|
99970
100201
|
agentName: cfg.agentName,
|
|
99971
100202
|
platform: "node",
|
|
99972
100203
|
clientVersion: buildClientVersion2(
|
|
99973
|
-
true ? "0.4.
|
|
100204
|
+
true ? "0.4.3" : void 0
|
|
99974
100205
|
)
|
|
99975
100206
|
});
|
|
99976
100207
|
channelRef = channel;
|
|
@@ -100050,6 +100281,9 @@ async function main() {
|
|
|
100050
100281
|
const target = new ActiveTarget();
|
|
100051
100282
|
wireBridge(channel, session, target, {
|
|
100052
100283
|
roomFilter: cfg.roomFilter,
|
|
100284
|
+
// #1107: needed to recognise this agent's own @mention. Without it the
|
|
100285
|
+
// agent can only answer @all.
|
|
100286
|
+
agentName: cfg.agentName,
|
|
100053
100287
|
log: (m2) => logLine("[grok-bridge] " + m2)
|
|
100054
100288
|
});
|
|
100055
100289
|
attachLifecycle2(channel, {
|
package/package.json
CHANGED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { type BridgeConfig } from "../config.js";
|
|
2
|
-
import type { ReapResult } from "../reap.js";
|
|
3
|
-
import { type ServiceBackend } from "./backend.js";
|
|
4
|
-
export interface InstallOnReadyDeps {
|
|
5
|
-
entrypoint: string;
|
|
6
|
-
env: NodeJS.ProcessEnv;
|
|
7
|
-
backend?: ServiceBackend;
|
|
8
|
-
hasCreds?: (dataDir: string) => boolean;
|
|
9
|
-
/** Contents of the installed launcher, or undefined when none is installed. */
|
|
10
|
-
readLauncher?: (path: string) => string | undefined;
|
|
11
|
-
fenceAuthExists?: (fenceHome: string) => boolean;
|
|
12
|
-
/** Resolves when no turn is in flight (GrokSession.idle). See rule 2. */
|
|
13
|
-
waitForIdle?: () => Promise<void>;
|
|
14
|
-
/** Bound on that wait. The terminal coming back is the product promise, so a
|
|
15
|
-
* wedged turn must never hold the customer's shell open. */
|
|
16
|
-
idleTimeoutMs?: number;
|
|
17
|
-
/** The ONE teardown (src/reap.ts). Must complete before launchctl runs. */
|
|
18
|
-
reap: () => Promise<ReapResult>;
|
|
19
|
-
exit: (code: number) => void;
|
|
20
|
-
log: (msg: string) => void;
|
|
21
|
-
}
|
|
22
|
-
interface ReadyChannel {
|
|
23
|
-
on(ev: "ready", cb: () => void): unknown;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* One-paste install: enrol in the foreground, hand off to the supervisor, exit —
|
|
27
|
-
* so the customer's terminal comes back and the agent survives a reboot.
|
|
28
|
-
*
|
|
29
|
-
* Four rules this module exists to enforce.
|
|
30
|
-
*
|
|
31
|
-
* 1. REFUSE BEFORE REAPING. Everything that can say no does so before anything is
|
|
32
|
-
* torn down. Refusing afterwards leaves the customer with an approved device,
|
|
33
|
-
* a spent invite token, and no running process — strictly worse than never
|
|
34
|
-
* having guarded at all.
|
|
35
|
-
*
|
|
36
|
-
* 2. REAP COMPLETELY, THEN BOOTSTRAP. `LaunchdBackend.install` runs bootout →
|
|
37
|
-
* poll-until-gone → bootstrap → kickstart synchronously, so the service is
|
|
38
|
-
* live the instant install returns. A partial teardown means two ACP sessions
|
|
39
|
-
* and two WebSockets on one device. `reap()` reports failure rather than
|
|
40
|
-
* swallowing it, and a failed reap is a refusal.
|
|
41
|
-
*
|
|
42
|
-
* 3. COMPARE, DON'T DETECT. `status().loaded` means only that a plist with this
|
|
43
|
-
* label exists. The old `install` subcommand never guarded its entrypoint
|
|
44
|
-
* (subcommand.ts), so a customer can hold a LOADED plist baked against a
|
|
45
|
-
* pruned npx cache; restarting that repairs nothing and reports success.
|
|
46
|
-
* Restart only when a service is loaded AND its baked entrypoint is the one we
|
|
47
|
-
* would install. Compare the ENTRYPOINT, never the whole launcher script —
|
|
48
|
-
* that embeds the install-time PATH and is volatile across shells.
|
|
49
|
-
*
|
|
50
|
-
* 4. VERIFY BEFORE CLAIMING. `backend.install` returns void, and launchd's
|
|
51
|
-
* implementation runs `kickstart` regardless of every `bootstrap` exit code.
|
|
52
|
-
* This log line is the customer's only feedback, so it comes after a
|
|
53
|
-
* `status()` that returned loaded:true.
|
|
54
|
-
*/
|
|
55
|
-
export declare function installOnReady(channel: ReadyChannel, cfg: BridgeConfig, deps: InstallOnReadyDeps): void;
|
|
56
|
-
export {};
|
|
57
|
-
//# sourceMappingURL=install-on-ready.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"install-on-ready.d.ts","sourceRoot":"","sources":["../../src/service/install-on-ready.ts"],"names":[],"mappings":"AAEA,OAAO,EAA4C,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAC3F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7C,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAElE,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IACxC,+EAA+E;IAC/E,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACpD,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;IACjD,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC;iEAC6D;IAC7D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2EAA2E;IAC3E,IAAI,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;IAChC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5B;AAMD,UAAU,YAAY;IACpB,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC;CAC1C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,YAAY,EACrB,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,kBAAkB,GACvB,IAAI,CAgHN"}
|