@agentvault/claude-bridge 0.5.5 → 0.5.7
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/config.d.ts +3 -0
- package/dist/index.js +176 -150
- package/dist/session.d.ts +2 -0
- package/dist/worker-permission.d.ts +8 -0
- package/package.json +1 -1
package/dist/config.d.ts
CHANGED
|
@@ -20,6 +20,9 @@ export interface BridgeConfig {
|
|
|
20
20
|
/** Slice 2: arm the pinned room (roomFilter) for worker tools on room turns.
|
|
21
21
|
* Off by default. Valid only with worker + roomFilter + workspaceDir. */
|
|
22
22
|
armRoom: boolean;
|
|
23
|
+
/** Operator attestation that the agent process runs OS-isolated (own user / jail).
|
|
24
|
+
* Only when true is Bash permitted in worker mode (the OS boundary is the fence). */
|
|
25
|
+
osIsolated: boolean;
|
|
23
26
|
}
|
|
24
27
|
export declare function loadConfig(env: NodeJS.ProcessEnv, argv?: string[]): BridgeConfig;
|
|
25
28
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -40,6 +40,7 @@ function loadConfig(env, argv = []) {
|
|
|
40
40
|
const inviteToken = (argv[0] && !argv[0].startsWith("-") ? argv[0] : "") || env.AV_INVITE_TOKEN || "";
|
|
41
41
|
const worker = env.AV_WORKER === "1" || env.AV_WORKER === "true";
|
|
42
42
|
const workspaceDir = env.AV_WORKSPACE_DIR || void 0;
|
|
43
|
+
const osIsolated = env.AV_WORKER_OS_ISOLATED === "1" || env.AV_WORKER_OS_ISOLATED === "true";
|
|
43
44
|
const PERMISSION_MODES = ["auto", "acceptEdits", "bypassPermissions"];
|
|
44
45
|
const permissionMode = env.AV_PERMISSION_MODE ?? "auto";
|
|
45
46
|
if (!PERMISSION_MODES.includes(permissionMode)) {
|
|
@@ -84,7 +85,8 @@ function loadConfig(env, argv = []) {
|
|
|
84
85
|
worker,
|
|
85
86
|
workspaceDir,
|
|
86
87
|
permissionMode,
|
|
87
|
-
armRoom
|
|
88
|
+
armRoom,
|
|
89
|
+
osIsolated
|
|
88
90
|
};
|
|
89
91
|
}
|
|
90
92
|
var CRED_FILES, BACKUP_FILE;
|
|
@@ -65024,145 +65026,140 @@ var init_channel = __esm2({
|
|
|
65024
65026
|
}
|
|
65025
65027
|
const raw = await loadState(this.config.dataDir);
|
|
65026
65028
|
if (raw) {
|
|
65027
|
-
await
|
|
65028
|
-
this.
|
|
65029
|
-
|
|
65030
|
-
|
|
65031
|
-
|
|
65032
|
-
|
|
65033
|
-
|
|
65034
|
-
|
|
65035
|
-
|
|
65036
|
-
|
|
65037
|
-
|
|
65038
|
-
|
|
65039
|
-
}
|
|
65040
|
-
|
|
65041
|
-
|
|
65042
|
-
|
|
65043
|
-
|
|
65044
|
-
|
|
65045
|
-
|
|
65046
|
-
|
|
65047
|
-
|
|
65048
|
-
|
|
65049
|
-
|
|
65050
|
-
|
|
65051
|
-
|
|
65052
|
-
|
|
65053
|
-
|
|
65054
|
-
|
|
65055
|
-
|
|
65056
|
-
|
|
65057
|
-
|
|
65058
|
-
|
|
65029
|
+
await this._hydrateFromPersisted(raw);
|
|
65030
|
+
this._connect();
|
|
65031
|
+
return;
|
|
65032
|
+
}
|
|
65033
|
+
const restored = await restoreState(this.config.dataDir);
|
|
65034
|
+
if (restored) {
|
|
65035
|
+
console.log("[SecureChannel] Restored state from backup");
|
|
65036
|
+
const restoredRaw = await loadState(this.config.dataDir);
|
|
65037
|
+
if (restoredRaw) {
|
|
65038
|
+
await this._hydrateFromPersisted(restoredRaw);
|
|
65039
|
+
this._connect();
|
|
65040
|
+
return;
|
|
65041
|
+
}
|
|
65042
|
+
}
|
|
65043
|
+
await this._enroll();
|
|
65044
|
+
}
|
|
65045
|
+
/**
|
|
65046
|
+
* Hydrate all in-memory state from persisted creds. The single source of
|
|
65047
|
+
* truth for both the primary boot and the .bak-restore boot, so the two can
|
|
65048
|
+
* never drift (the drift is what caused #416: the backup branch used to skip
|
|
65049
|
+
* MLS group loading and dropped owner MLS DMs). Callers invoke _connect()
|
|
65050
|
+
* after this resolves.
|
|
65051
|
+
*/
|
|
65052
|
+
async _hydrateFromPersisted(raw) {
|
|
65053
|
+
await backupState(this.config.dataDir);
|
|
65054
|
+
this._persisted = migratePersistedState(raw);
|
|
65055
|
+
if (!this._persisted.messageHistory) {
|
|
65056
|
+
this._persisted.messageHistory = [];
|
|
65057
|
+
}
|
|
65058
|
+
this._deviceId = this._persisted.deviceId;
|
|
65059
|
+
this._deviceJwt = this._persisted.deviceJwt;
|
|
65060
|
+
this._primaryConversationId = this._persisted.primaryConversationId;
|
|
65061
|
+
this._fingerprint = this._persisted.fingerprint;
|
|
65062
|
+
this._lastInboundRoomId = this._persisted.lastInboundRoomId;
|
|
65063
|
+
if (this._persisted.seenMessageIds) {
|
|
65064
|
+
this._seenMessageIds = new Set(this._persisted.seenMessageIds.slice(-_SecureChannel.SEEN_MSG_MAX));
|
|
65065
|
+
}
|
|
65066
|
+
if (this._persisted.seenA2AMessageIds) {
|
|
65067
|
+
this._a2aSeenMessageIds = new Set(this._persisted.seenA2AMessageIds.slice(-_SecureChannel.A2A_SEEN_MAX));
|
|
65068
|
+
}
|
|
65069
|
+
if (this._persisted?.rooms) {
|
|
65070
|
+
const roomConvIds = /* @__PURE__ */ new Set();
|
|
65071
|
+
for (const room of Object.values(this._persisted.rooms)) {
|
|
65072
|
+
for (const cid of room.conversationIds || []) {
|
|
65073
|
+
roomConvIds.add(cid);
|
|
65059
65074
|
}
|
|
65060
65075
|
}
|
|
65061
|
-
|
|
65062
|
-
|
|
65063
|
-
|
|
65064
|
-
|
|
65065
|
-
|
|
65066
|
-
this._sessions.set(convId, {
|
|
65067
|
-
ownerDeviceId: sessionData.ownerDeviceId,
|
|
65068
|
-
ratchet,
|
|
65069
|
-
activated: sessionData.activated ?? false,
|
|
65070
|
-
epoch: sessionData.epoch
|
|
65071
|
-
});
|
|
65076
|
+
let cleanedCount = 0;
|
|
65077
|
+
for (const cid of roomConvIds) {
|
|
65078
|
+
if (this._persisted.sessions[cid]) {
|
|
65079
|
+
delete this._persisted.sessions[cid];
|
|
65080
|
+
cleanedCount++;
|
|
65072
65081
|
}
|
|
65073
65082
|
}
|
|
65074
|
-
if (
|
|
65075
|
-
|
|
65076
|
-
console.log(`[SecureChannel] Restored ${this._sessionGroupIds.size} conversation\u2192group mappings`);
|
|
65083
|
+
if (cleanedCount > 0) {
|
|
65084
|
+
console.log(`[SecureChannel] Cleaned ${cleanedCount} stale DR room sessions`);
|
|
65077
65085
|
}
|
|
65078
|
-
|
|
65079
|
-
|
|
65080
|
-
|
|
65081
|
-
|
|
65082
|
-
|
|
65083
|
-
|
|
65084
|
-
|
|
65085
|
-
|
|
65086
|
-
|
|
65087
|
-
|
|
65088
|
-
|
|
65089
|
-
|
|
65090
|
-
console.warn(`[SecureChannel] Failed to restore MLS state for room ${roomId.slice(0, 8)}:`, mlsErr);
|
|
65091
|
-
}
|
|
65092
|
-
}
|
|
65093
|
-
}
|
|
65086
|
+
}
|
|
65087
|
+
for (const [convId, sessionData] of Object.entries(
|
|
65088
|
+
this._persisted.sessions
|
|
65089
|
+
)) {
|
|
65090
|
+
if (sessionData.ratchetState) {
|
|
65091
|
+
const ratchet = DoubleRatchet.deserialize(sessionData.ratchetState);
|
|
65092
|
+
this._sessions.set(convId, {
|
|
65093
|
+
ownerDeviceId: sessionData.ownerDeviceId,
|
|
65094
|
+
ratchet,
|
|
65095
|
+
activated: sessionData.activated ?? false,
|
|
65096
|
+
epoch: sessionData.epoch
|
|
65097
|
+
});
|
|
65094
65098
|
}
|
|
65095
|
-
|
|
65096
|
-
|
|
65099
|
+
}
|
|
65100
|
+
if (this._persisted.conversationGroupIds) {
|
|
65101
|
+
this._sessionGroupIds = new Map(Object.entries(this._persisted.conversationGroupIds));
|
|
65102
|
+
console.log(`[SecureChannel] Restored ${this._sessionGroupIds.size} conversation\u2192group mappings`);
|
|
65103
|
+
}
|
|
65104
|
+
if (this._persisted.rooms) {
|
|
65105
|
+
for (const [roomId, room] of Object.entries(this._persisted.rooms)) {
|
|
65106
|
+
const mlsGroupId = room.mlsGroupId;
|
|
65107
|
+
if (mlsGroupId) {
|
|
65097
65108
|
try {
|
|
65098
|
-
const mlsState = await loadMlsState(this.config.dataDir,
|
|
65109
|
+
const mlsState = await loadMlsState(this.config.dataDir, mlsGroupId);
|
|
65099
65110
|
if (mlsState) {
|
|
65100
65111
|
const mgr = new MLSGroupManager();
|
|
65101
65112
|
mgr.importState(JSON.parse(mlsState));
|
|
65102
|
-
this._mlsGroups.set(
|
|
65113
|
+
this._mlsGroups.set(roomId, mgr);
|
|
65103
65114
|
}
|
|
65104
65115
|
} catch (mlsErr) {
|
|
65105
|
-
console.warn(`[SecureChannel] Failed to restore MLS state for
|
|
65116
|
+
console.warn(`[SecureChannel] Failed to restore MLS state for room ${roomId.slice(0, 8)}:`, mlsErr);
|
|
65106
65117
|
}
|
|
65107
65118
|
}
|
|
65108
65119
|
}
|
|
65109
|
-
|
|
65110
|
-
|
|
65120
|
+
}
|
|
65121
|
+
for (const [convId, entry] of Object.entries(this._persisted.mlsConversations ?? {})) {
|
|
65122
|
+
if (entry.mlsGroupId) {
|
|
65111
65123
|
try {
|
|
65112
|
-
const
|
|
65113
|
-
if (
|
|
65124
|
+
const mlsState = await loadMlsState(this.config.dataDir, entry.mlsGroupId);
|
|
65125
|
+
if (mlsState) {
|
|
65114
65126
|
const mgr = new MLSGroupManager();
|
|
65115
|
-
mgr.importState(JSON.parse(
|
|
65116
|
-
this._mlsGroups.set(`
|
|
65117
|
-
console.log(`[SecureChannel] Loaded shared MLS group for ${gid.slice(0, 8)} (epoch=${mgr.epoch})`);
|
|
65127
|
+
mgr.importState(JSON.parse(mlsState));
|
|
65128
|
+
this._mlsGroups.set(`conv:${convId}`, mgr);
|
|
65118
65129
|
}
|
|
65119
|
-
} catch (
|
|
65120
|
-
console.warn(`[SecureChannel] Failed to
|
|
65130
|
+
} catch (mlsErr) {
|
|
65131
|
+
console.warn(`[SecureChannel] Failed to restore MLS state for conv ${convId.slice(0, 8)}:`, mlsErr);
|
|
65121
65132
|
}
|
|
65122
65133
|
}
|
|
65123
|
-
|
|
65124
|
-
|
|
65125
|
-
|
|
65126
|
-
|
|
65127
|
-
|
|
65128
|
-
|
|
65129
|
-
|
|
65130
|
-
|
|
65131
|
-
|
|
65132
|
-
|
|
65133
|
-
console.warn(`[SecureChannel] Failed to restore MLS state for A2A ${channelId.slice(0, 8)}:`, mlsErr);
|
|
65134
|
-
}
|
|
65134
|
+
}
|
|
65135
|
+
for (const [gid, entry] of Object.entries(this._persisted.mlsGroups ?? {})) {
|
|
65136
|
+
if (!entry.mlsGroupId) continue;
|
|
65137
|
+
try {
|
|
65138
|
+
const stateJson = await loadMlsState(this.config.dataDir, entry.mlsGroupId);
|
|
65139
|
+
if (stateJson) {
|
|
65140
|
+
const mgr = new MLSGroupManager();
|
|
65141
|
+
mgr.importState(JSON.parse(stateJson));
|
|
65142
|
+
this._mlsGroups.set(`1to1-group:${gid}`, mgr);
|
|
65143
|
+
console.log(`[SecureChannel] Loaded shared MLS group for ${gid.slice(0, 8)} (epoch=${mgr.epoch})`);
|
|
65135
65144
|
}
|
|
65145
|
+
} catch (loadErr) {
|
|
65146
|
+
console.warn(`[SecureChannel] Failed to load shared MLS group ${gid.slice(0, 8)}:`, loadErr);
|
|
65136
65147
|
}
|
|
65137
|
-
this._connect();
|
|
65138
|
-
return;
|
|
65139
65148
|
}
|
|
65140
|
-
const
|
|
65141
|
-
|
|
65142
|
-
|
|
65143
|
-
|
|
65144
|
-
|
|
65145
|
-
|
|
65146
|
-
|
|
65147
|
-
|
|
65148
|
-
this._deviceJwt = this._persisted.deviceJwt;
|
|
65149
|
-
this._primaryConversationId = this._persisted.primaryConversationId;
|
|
65150
|
-
this._fingerprint = this._persisted.fingerprint;
|
|
65151
|
-
for (const [convId, sd] of Object.entries(this._persisted.sessions)) {
|
|
65152
|
-
if (sd.ratchetState) {
|
|
65153
|
-
this._sessions.set(convId, {
|
|
65154
|
-
ownerDeviceId: sd.ownerDeviceId,
|
|
65155
|
-
ratchet: DoubleRatchet.deserialize(sd.ratchetState),
|
|
65156
|
-
activated: sd.activated ?? false,
|
|
65157
|
-
epoch: sd.epoch
|
|
65158
|
-
});
|
|
65149
|
+
for (const [channelId, entry] of Object.entries(this._persisted.a2aChannels ?? {})) {
|
|
65150
|
+
if (entry.mlsGroupId) {
|
|
65151
|
+
try {
|
|
65152
|
+
const mlsState = await loadMlsState(this.config.dataDir, entry.mlsGroupId);
|
|
65153
|
+
if (mlsState) {
|
|
65154
|
+
const mgr = new MLSGroupManager();
|
|
65155
|
+
mgr.importState(JSON.parse(mlsState));
|
|
65156
|
+
this._mlsGroups.set(`a2a:${channelId}`, mgr);
|
|
65159
65157
|
}
|
|
65158
|
+
} catch (mlsErr) {
|
|
65159
|
+
console.warn(`[SecureChannel] Failed to restore MLS state for A2A ${channelId.slice(0, 8)}:`, mlsErr);
|
|
65160
65160
|
}
|
|
65161
|
-
this._connect();
|
|
65162
|
-
return;
|
|
65163
65161
|
}
|
|
65164
65162
|
}
|
|
65165
|
-
await this._enroll();
|
|
65166
65163
|
}
|
|
65167
65164
|
/**
|
|
65168
65165
|
* Fetch scan rules from the server and load them into the ScanEngine.
|
|
@@ -65502,7 +65499,7 @@ var init_channel = __esm2({
|
|
|
65502
65499
|
*/
|
|
65503
65500
|
sendActivitySpan(spanData) {
|
|
65504
65501
|
if (!this._ws || this._ws.readyState !== WebSocket2.OPEN) return;
|
|
65505
|
-
const pluginVersion = true ? "0.23.
|
|
65502
|
+
const pluginVersion = true ? "0.23.3" : "0.0.0-dev";
|
|
65506
65503
|
const agentName = this.config.agentName ?? "Agent";
|
|
65507
65504
|
const resource = {
|
|
65508
65505
|
"service.name": "agentvault-agent",
|
|
@@ -67119,7 +67116,7 @@ var init_channel = __esm2({
|
|
|
67119
67116
|
agentVersion: this.config.agentVersion ?? "0.0.0",
|
|
67120
67117
|
// __AV_VERSION__ is injected by esbuild from package.json at build time.
|
|
67121
67118
|
// Falls back to "0.0.0-dev" in non-bundled contexts (tests).
|
|
67122
|
-
pluginVersion: true ? "0.23.
|
|
67119
|
+
pluginVersion: true ? "0.23.3" : "0.0.0-dev"
|
|
67123
67120
|
});
|
|
67124
67121
|
this._telemetryReporter.startAutoFlush(3e4);
|
|
67125
67122
|
}
|
|
@@ -67429,7 +67426,7 @@ var init_channel = __esm2({
|
|
|
67429
67426
|
agentVersion: this.config.agentVersion ?? "0.0.0",
|
|
67430
67427
|
// __AV_VERSION__ is injected by esbuild from package.json at build time.
|
|
67431
67428
|
// Falls back to "0.0.0-dev" in non-bundled contexts (tests).
|
|
67432
|
-
pluginVersion: true ? "0.23.
|
|
67429
|
+
pluginVersion: true ? "0.23.3" : "0.0.0-dev"
|
|
67433
67430
|
});
|
|
67434
67431
|
this._telemetryReporter.startAutoFlush(3e4);
|
|
67435
67432
|
}
|
|
@@ -68298,13 +68295,13 @@ ${messageText}`;
|
|
|
68298
68295
|
* Looks for OpenClaw workspace config, falls back to default path.
|
|
68299
68296
|
*/
|
|
68300
68297
|
_resolveWorkspaceDir() {
|
|
68301
|
-
const
|
|
68298
|
+
const homedir = osHomedir();
|
|
68302
68299
|
const agentName = this.config.agentName;
|
|
68303
68300
|
if (this._persisted?.agentRole === "lead") {
|
|
68304
|
-
return join4(
|
|
68301
|
+
return join4(homedir, ".openclaw", "workspace");
|
|
68305
68302
|
}
|
|
68306
68303
|
try {
|
|
68307
|
-
const configPath = join4(
|
|
68304
|
+
const configPath = join4(homedir, ".openclaw", "openclaw.json");
|
|
68308
68305
|
const raw = readFileSync(configPath, "utf-8");
|
|
68309
68306
|
const config22 = JSON.parse(raw);
|
|
68310
68307
|
const agents = config22?.agents?.list;
|
|
@@ -68318,9 +68315,9 @@ ${messageText}`;
|
|
|
68318
68315
|
} catch {
|
|
68319
68316
|
}
|
|
68320
68317
|
if (agentName && agentName !== "CLI Agent" && agentName !== "OpenClaw Agent") {
|
|
68321
|
-
return join4(
|
|
68318
|
+
return join4(homedir, ".openclaw", `workspace-${agentName}`);
|
|
68322
68319
|
}
|
|
68323
|
-
return join4(
|
|
68320
|
+
return join4(homedir, ".openclaw", "workspace");
|
|
68324
68321
|
}
|
|
68325
68322
|
/**
|
|
68326
68323
|
* Send a structured JSON reply to a specific conversation.
|
|
@@ -97176,7 +97173,7 @@ var init_index = __esm2({
|
|
|
97176
97173
|
init_skill_invoker();
|
|
97177
97174
|
await init_skill_telemetry();
|
|
97178
97175
|
await init_policy_enforcer();
|
|
97179
|
-
VERSION = true ? "0.23.
|
|
97176
|
+
VERSION = true ? "0.23.3" : "0.0.0-dev";
|
|
97180
97177
|
}
|
|
97181
97178
|
});
|
|
97182
97179
|
await init_index();
|
|
@@ -118480,52 +118477,75 @@ function Z_($10, Q4) {
|
|
|
118480
118477
|
|
|
118481
118478
|
// src/worker-permission.ts
|
|
118482
118479
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
118483
|
-
import { resolve as resolve2, dirname, basename, sep } from "node:path";
|
|
118484
|
-
import { homedir } from "node:os";
|
|
118480
|
+
import { resolve as resolve2, dirname, basename, sep, isAbsolute } from "node:path";
|
|
118485
118481
|
var PATH_FIELDS = ["file_path", "path", "notebook_path"];
|
|
118486
118482
|
function canonical(p2) {
|
|
118487
118483
|
const abs = resolve2(p2);
|
|
118488
118484
|
try {
|
|
118489
118485
|
return realpathSync2(abs);
|
|
118490
118486
|
} catch {
|
|
118491
|
-
|
|
118492
|
-
|
|
118493
|
-
|
|
118494
|
-
|
|
118487
|
+
const suffix = [];
|
|
118488
|
+
let dir = abs;
|
|
118489
|
+
for (; ; ) {
|
|
118490
|
+
const parent2 = dirname(dir);
|
|
118491
|
+
suffix.unshift(basename(dir));
|
|
118492
|
+
if (parent2 === dir) return abs;
|
|
118493
|
+
try {
|
|
118494
|
+
return resolve2(realpathSync2(parent2), ...suffix);
|
|
118495
|
+
} catch {
|
|
118496
|
+
dir = parent2;
|
|
118497
|
+
}
|
|
118495
118498
|
}
|
|
118496
118499
|
}
|
|
118497
118500
|
}
|
|
118498
|
-
|
|
118499
|
-
|
|
118501
|
+
var FILE_TOOLS = /* @__PURE__ */ new Set(["Read", "Write", "Edit", "MultiEdit", "NotebookEdit", "Glob", "Grep"]);
|
|
118502
|
+
function pathsOf(input) {
|
|
118503
|
+
const out = [];
|
|
118500
118504
|
for (const f7 of PATH_FIELDS) {
|
|
118501
118505
|
const v5 = input[f7];
|
|
118502
|
-
if (typeof v5 === "string")
|
|
118503
|
-
const canon = canonical(v5);
|
|
118504
|
-
if (canon === canonDir || canon.startsWith(canonDir + sep)) return true;
|
|
118505
|
-
}
|
|
118506
|
+
if (typeof v5 === "string" && v5.length > 0) out.push(canonical(v5));
|
|
118506
118507
|
}
|
|
118507
|
-
|
|
118508
|
-
|
|
118509
|
-
|
|
118510
|
-
|
|
118511
|
-
|
|
118512
|
-
|
|
118513
|
-
|
|
118514
|
-
|
|
118515
|
-
|
|
118516
|
-
|
|
118517
|
-
}
|
|
118518
|
-
return false;
|
|
118508
|
+
return out;
|
|
118509
|
+
}
|
|
118510
|
+
function within(canonTarget, canonRoot) {
|
|
118511
|
+
return canonTarget === canonRoot || canonTarget.startsWith(canonRoot + sep);
|
|
118512
|
+
}
|
|
118513
|
+
function globPatternEscapes(pattern) {
|
|
118514
|
+
if (typeof pattern !== "string" || pattern.length === 0) return true;
|
|
118515
|
+
if (!/^[A-Za-z0-9 _./*?-]+$/.test(pattern)) return true;
|
|
118516
|
+
if (isAbsolute(pattern)) return true;
|
|
118517
|
+
return pattern.split("/").some((seg) => seg === ".." || seg === "");
|
|
118519
118518
|
}
|
|
118520
118519
|
function gateDecision(toolName, input, opts) {
|
|
118521
118520
|
if (toolName === ROOM_SAY_TOOL_NAME) return { deny: false };
|
|
118522
118521
|
if (!opts.isToolTurn()) {
|
|
118523
118522
|
return { deny: true, reason: "tools are disabled on this turn; reply with the say tool only" };
|
|
118524
118523
|
}
|
|
118525
|
-
if (
|
|
118526
|
-
return { deny: true, reason: "
|
|
118524
|
+
if (toolName === "Bash") {
|
|
118525
|
+
return opts.osIsolated ? { deny: false } : { deny: true, reason: "Bash is disabled in worker mode unless the process is OS-isolated (set AV_WORKER_OS_ISOLATED=1)" };
|
|
118527
118526
|
}
|
|
118528
|
-
|
|
118527
|
+
if (FILE_TOOLS.has(toolName)) {
|
|
118528
|
+
if (!opts.workspaceDir) {
|
|
118529
|
+
return { deny: true, reason: "no workspace is configured; file tools are disabled" };
|
|
118530
|
+
}
|
|
118531
|
+
const paths = pathsOf(input);
|
|
118532
|
+
if (paths.length === 0) {
|
|
118533
|
+
return { deny: true, reason: "file tool call has no resolvable path; blocked (workspace-confined)" };
|
|
118534
|
+
}
|
|
118535
|
+
if (toolName === "Glob" && globPatternEscapes(input.pattern)) {
|
|
118536
|
+
return { deny: true, reason: "glob pattern must be workspace-relative" };
|
|
118537
|
+
}
|
|
118538
|
+
const wsRoot = canonical(opts.workspaceDir);
|
|
118539
|
+
if (!paths.every((p2) => within(p2, wsRoot))) {
|
|
118540
|
+
return { deny: true, reason: "file access is restricted to the workspace directory" };
|
|
118541
|
+
}
|
|
118542
|
+
const dataRoot = canonical(opts.dataDir);
|
|
118543
|
+
if (paths.some((p2) => within(p2, dataRoot))) {
|
|
118544
|
+
return { deny: true, reason: "access to the AgentVault key directory is not permitted" };
|
|
118545
|
+
}
|
|
118546
|
+
return { deny: false };
|
|
118547
|
+
}
|
|
118548
|
+
return { deny: true, reason: `tool ${toolName} is not permitted in worker mode` };
|
|
118529
118549
|
}
|
|
118530
118550
|
function makeWorkerPreToolUseHook(opts) {
|
|
118531
118551
|
return {
|
|
@@ -132489,6 +132509,8 @@ var PersistentClaudeSession = class {
|
|
|
132489
132509
|
}
|
|
132490
132510
|
const gateOpts = {
|
|
132491
132511
|
dataDir: this.opts.dataDir ?? "",
|
|
132512
|
+
workspaceDir: this.opts.workspaceDir,
|
|
132513
|
+
osIsolated: this.opts.osIsolated ?? false,
|
|
132492
132514
|
// LOAD-BEARING: tools are allowed when this is an owner DM turn
|
|
132493
132515
|
// (currentAutoReply) OR an armed-room turn (currentArmedGetter()). An UNARMED
|
|
132494
132516
|
// room turn keeps both false → the gate denies all tools but room_say.
|
|
@@ -132510,6 +132532,9 @@ var PersistentClaudeSession = class {
|
|
|
132510
132532
|
});
|
|
132511
132533
|
}
|
|
132512
132534
|
};
|
|
132535
|
+
console.error(
|
|
132536
|
+
`[worker-gate] allowlist active \u2014 workspace=${this.opts.workspaceDir ?? "(none: file tools disabled)"}, bash=${this.opts.osIsolated ? "enabled (OS-isolated)" : "disabled"}`
|
|
132537
|
+
);
|
|
132513
132538
|
return {
|
|
132514
132539
|
...base,
|
|
132515
132540
|
permissionMode: this.opts.permissionMode ?? "auto",
|
|
@@ -132918,7 +132943,7 @@ async function main() {
|
|
|
132918
132943
|
"[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"
|
|
132919
132944
|
);
|
|
132920
132945
|
}
|
|
132921
|
-
console.error(`[bridge] version: ${true ? "0.5.
|
|
132946
|
+
console.error(`[bridge] version: ${true ? "0.5.7" : "dev"}`);
|
|
132922
132947
|
console.error(`[bridge] data dir: ${cfg.dataDir} (${cfg.dataDirSource})`);
|
|
132923
132948
|
if (cfg.worker) {
|
|
132924
132949
|
console.error(`[bridge] WORKER MODE \u2014 workspace: ${cfg.workspaceDir} \xB7 permissions: ${cfg.permissionMode} \xB7 enclave dir fenced`);
|
|
@@ -132956,6 +132981,7 @@ async function main() {
|
|
|
132956
132981
|
onObserve: (text) => console.error(`[bridge] observed (${text.length} chars, not sent)`),
|
|
132957
132982
|
worker: cfg.worker,
|
|
132958
132983
|
workspaceDir: cfg.workspaceDir,
|
|
132984
|
+
osIsolated: cfg.osIsolated,
|
|
132959
132985
|
permissionMode: cfg.permissionMode,
|
|
132960
132986
|
dataDir: cfg.dataDir,
|
|
132961
132987
|
// Slice 2 Plan B: audit self-report context (only used on armed-room turns).
|
package/dist/session.d.ts
CHANGED
|
@@ -60,6 +60,8 @@ export interface SessionOpts {
|
|
|
60
60
|
worker?: boolean;
|
|
61
61
|
/** Workspace directory to set as cwd in worker mode. */
|
|
62
62
|
workspaceDir?: string;
|
|
63
|
+
/** True when the process is attested OS-isolated, gating whether Bash is allowed at all. */
|
|
64
|
+
osIsolated?: boolean;
|
|
63
65
|
/** Claude permission mode for worker turns (default: "auto"). */
|
|
64
66
|
permissionMode?: "auto" | "acceptEdits" | "bypassPermissions";
|
|
65
67
|
/** AgentVault data directory — fenced off from worker tool access. */
|
|
@@ -8,6 +8,10 @@ import type { CanUseTool, HookCallbackMatcher } from "@anthropic-ai/claude-agent
|
|
|
8
8
|
*/
|
|
9
9
|
export declare function makeWorkerPreToolUseHook(opts: {
|
|
10
10
|
dataDir: string;
|
|
11
|
+
/** The confined workspace root; file tools are denied entirely when unset. */
|
|
12
|
+
workspaceDir?: string;
|
|
13
|
+
/** True when the process is attested OS-isolated, gating whether Bash is allowed at all. */
|
|
14
|
+
osIsolated: boolean;
|
|
11
15
|
isToolTurn: () => boolean;
|
|
12
16
|
/** Slice 2 Plan B: true when this turn comes from an armed room. When set,
|
|
13
17
|
* each tool decision (allow AND deny) is forwarded to onToolDecision for
|
|
@@ -27,6 +31,10 @@ export declare function makeWorkerPreToolUseHook(opts: {
|
|
|
27
31
|
*/
|
|
28
32
|
export declare function makeWorkerPermission(opts: {
|
|
29
33
|
dataDir: string;
|
|
34
|
+
/** The confined workspace root; file tools are denied entirely when unset. */
|
|
35
|
+
workspaceDir?: string;
|
|
36
|
+
/** True when the process is attested OS-isolated, gating whether Bash is allowed at all. */
|
|
37
|
+
osIsolated: boolean;
|
|
30
38
|
isToolTurn: () => boolean;
|
|
31
39
|
}): CanUseTool;
|
|
32
40
|
//# sourceMappingURL=worker-permission.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentvault/claude-bridge",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AgentVault Claude Bridge — daemon for bridging a Claude agent into secure E2E-encrypted AgentVault 1:1 direct messages and rooms.",
|
|
6
6
|
"main": "dist/index.js",
|