@agentvault/claude-bridge 0.7.10 → 0.7.11
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/index.js +84 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -63791,6 +63791,35 @@ async function deleteMlsState(dataDir, groupId) {
|
|
|
63791
63791
|
} catch {
|
|
63792
63792
|
}
|
|
63793
63793
|
}
|
|
63794
|
+
async function quarantineOrphanedMlsState(dataDir, isStillMember, opts = {}) {
|
|
63795
|
+
const max = opts.max ?? 20;
|
|
63796
|
+
const quarantined = [];
|
|
63797
|
+
let names;
|
|
63798
|
+
try {
|
|
63799
|
+
names = await readdir(dataDir);
|
|
63800
|
+
} catch {
|
|
63801
|
+
return quarantined;
|
|
63802
|
+
}
|
|
63803
|
+
for (const name of names) {
|
|
63804
|
+
if (quarantined.length >= max) break;
|
|
63805
|
+
const m22 = /^mls-(?!kp-pending-)([A-Za-z0-9_-]+)\.json$/.exec(name);
|
|
63806
|
+
if (!m22) continue;
|
|
63807
|
+
const groupId = m22[1];
|
|
63808
|
+
let member;
|
|
63809
|
+
try {
|
|
63810
|
+
member = await isStillMember(groupId);
|
|
63811
|
+
} catch {
|
|
63812
|
+
continue;
|
|
63813
|
+
}
|
|
63814
|
+
if (member === null || member === true) continue;
|
|
63815
|
+
try {
|
|
63816
|
+
await rename(join(dataDir, name), join(dataDir, `${name}.orphaned`));
|
|
63817
|
+
quarantined.push(groupId);
|
|
63818
|
+
} catch {
|
|
63819
|
+
}
|
|
63820
|
+
}
|
|
63821
|
+
return quarantined;
|
|
63822
|
+
}
|
|
63794
63823
|
var SYNC_LOCK_STALE_MS;
|
|
63795
63824
|
var pendingKpPath;
|
|
63796
63825
|
var init_mls_state = __esm2({
|
|
@@ -64149,6 +64178,16 @@ var init_a2a_log_gate = __esm2({
|
|
|
64149
64178
|
};
|
|
64150
64179
|
}
|
|
64151
64180
|
});
|
|
64181
|
+
function mlsMembershipFromStatus(status) {
|
|
64182
|
+
if (status === 200) return true;
|
|
64183
|
+
if (status === 403 || status === 404) return false;
|
|
64184
|
+
return null;
|
|
64185
|
+
}
|
|
64186
|
+
var init_mls_membership_probe = __esm2({
|
|
64187
|
+
"src/mls-membership-probe.ts"() {
|
|
64188
|
+
"use strict";
|
|
64189
|
+
}
|
|
64190
|
+
});
|
|
64152
64191
|
var openclaw_compat_exports = {};
|
|
64153
64192
|
__export2(openclaw_compat_exports, {
|
|
64154
64193
|
AGENT_EVENT_CANDIDATES: () => AGENT_EVENT_CANDIDATES,
|
|
@@ -64709,6 +64748,7 @@ var init_channel = __esm2({
|
|
|
64709
64748
|
await init_state();
|
|
64710
64749
|
init_transport2();
|
|
64711
64750
|
init_a2a_log_gate();
|
|
64751
|
+
init_mls_membership_probe();
|
|
64712
64752
|
ROOM_AGENT_TYPES = /* @__PURE__ */ new Set([
|
|
64713
64753
|
"message",
|
|
64714
64754
|
"text",
|
|
@@ -66072,6 +66112,47 @@ var init_channel = __esm2({
|
|
|
66072
66112
|
);
|
|
66073
66113
|
this.emit("rooms_reconciled", { pruned: stale });
|
|
66074
66114
|
}
|
|
66115
|
+
/**
|
|
66116
|
+
* #629 — quarantine MLS state for groups this device is no longer in.
|
|
66117
|
+
*
|
|
66118
|
+
* `_reconcileRoomsWithServer` above covers ROOMS: anything absent from
|
|
66119
|
+
* `GET /rooms` is pruned. It cannot see a group that was never a room — a 1:1
|
|
66120
|
+
* conversation group or an A2A channel group — so that state lingered with
|
|
66121
|
+
* nothing to reconcile it. Measured on loopita 2026-08-08: one group-state
|
|
66122
|
+
* file whose group had no server-side row at all.
|
|
66123
|
+
*
|
|
66124
|
+
* `quarantineOrphanedMlsState` was written for exactly this and shipped with
|
|
66125
|
+
* 11 passing tests, but nothing ever called it. This is that call site.
|
|
66126
|
+
*
|
|
66127
|
+
* Runs AFTER the room reconcile so rooms are already gone and this only sees
|
|
66128
|
+
* genuine non-room orphans.
|
|
66129
|
+
*
|
|
66130
|
+
* Quarantine RENAMES to `.orphaned` rather than deleting: if the verdict is
|
|
66131
|
+
* ever wrong the state is recoverable by hand, which deletion would not be.
|
|
66132
|
+
*/
|
|
66133
|
+
async _quarantineOrphanedMlsGroups() {
|
|
66134
|
+
if (!this._deviceJwt) return;
|
|
66135
|
+
const quarantined = await quarantineOrphanedMlsState(
|
|
66136
|
+
this.config.dataDir,
|
|
66137
|
+
async (groupId) => {
|
|
66138
|
+
try {
|
|
66139
|
+
const res = await fetch(
|
|
66140
|
+
`${this.config.apiUrl}/api/v1/mls/groups/${encodeURIComponent(groupId)}`,
|
|
66141
|
+
{ headers: { Authorization: `Bearer ${this._deviceJwt}` } }
|
|
66142
|
+
);
|
|
66143
|
+
return mlsMembershipFromStatus(res.status);
|
|
66144
|
+
} catch {
|
|
66145
|
+
return null;
|
|
66146
|
+
}
|
|
66147
|
+
}
|
|
66148
|
+
);
|
|
66149
|
+
if (quarantined.length > 0) {
|
|
66150
|
+
console.log(
|
|
66151
|
+
`[SecureChannel] Quarantined ${quarantined.length} orphaned MLS group state file(s): ` + quarantined.map((g22) => g22.slice(0, 8)).join(", ")
|
|
66152
|
+
);
|
|
66153
|
+
this.emit("mls_state_quarantined", { groupIds: quarantined });
|
|
66154
|
+
}
|
|
66155
|
+
}
|
|
66075
66156
|
/**
|
|
66076
66157
|
* Handle an in-band `{event:"error"}` frame from the server.
|
|
66077
66158
|
*
|
|
@@ -67596,6 +67677,8 @@ var init_channel = __esm2({
|
|
|
67596
67677
|
this._setState("ready");
|
|
67597
67678
|
void this._reconcileRoomsWithServer().catch(
|
|
67598
67679
|
(err) => console.warn(`[SecureChannel] room reconcile failed (ignored): ${err instanceof Error ? err.message : String(err)}`)
|
|
67680
|
+
).then(() => this._quarantineOrphanedMlsGroups()).catch(
|
|
67681
|
+
(err) => console.warn(`[SecureChannel] MLS orphan quarantine failed (ignored): ${err instanceof Error ? err.message : String(err)}`)
|
|
67599
67682
|
);
|
|
67600
67683
|
if (this.config.enableScanning) {
|
|
67601
67684
|
this._scanEngine = new ScanEngine();
|
|
@@ -134185,7 +134268,7 @@ async function main() {
|
|
|
134185
134268
|
"[bridge] warning: passing the invite token on the command line is visible to other local users via 'ps'. Prefer: AV_INVITE_TOKEN=\u2026 npx @agentvault/claude-bridge"
|
|
134186
134269
|
);
|
|
134187
134270
|
}
|
|
134188
|
-
logLine(`[bridge] version: ${true ? "0.7.
|
|
134271
|
+
logLine(`[bridge] version: ${true ? "0.7.11" : "dev"}`);
|
|
134189
134272
|
logLine(`[bridge] data dir: ${cfg.dataDir} (${cfg.dataDirSource})`);
|
|
134190
134273
|
logLine(`[bridge] workspace: ${cfg.workspaceDir} \xB7 permissions: ${cfg.permissionMode} \xB7 enclave dir fenced`);
|
|
134191
134274
|
if (cfg.armRoom) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentvault/claude-bridge",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AgentVault Claude Bridge \u2014 daemon for bridging a Claude agent into secure E2E-encrypted AgentVault 1:1 direct messages and rooms.",
|
|
6
6
|
"main": "dist/index.js",
|