@agentvault/claude-bridge 0.7.0 → 0.7.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.
@@ -19,8 +19,30 @@ export declare function trustDir(root?: string): string;
19
19
  */
20
20
  export declare function isTrusted(deviceId: string, root?: string): boolean;
21
21
  export declare function grant(deviceId: string, root?: string): void;
22
- /** Returns true only if a marker was actually removed. */
22
+ /**
23
+ * Returns true only if a real marker was actually removed.
24
+ *
25
+ * M1. This used `existsSync` + `rmSync(p, { force: true, recursive: true })`.
26
+ * `existsSync` is true for a DIRECTORY, so a directory squatting at a marker
27
+ * path was recursively deleted — contents and all — and reported as a
28
+ * successful revoke. Reached in practice through `untrust-host --all`
29
+ * (approve-cli.ts:131), which revokes everything `listTrusted()` returns.
30
+ *
31
+ * Only a regular file is a marker, which is already `isTrusted`'s rule; `lstat`
32
+ * so a symlink is never followed or counted. Anything else was never a grant,
33
+ * so removing it is not this function's job — and refusing keeps `recursive`
34
+ * out of this file entirely.
35
+ *
36
+ * The invariant callers actually depend on is preserved: after `revoke()`,
37
+ * `isTrusted()` is false, because it rejects non-files too.
38
+ */
23
39
  export declare function revoke(deviceId: string, root?: string): boolean;
40
+ /**
41
+ * Filtered through `isTrusted` rather than the filename alone, so the listing
42
+ * cannot disagree with the decision. A name-only filter reported directories
43
+ * and symlinks as trusted devices, which both over-stated trust to an operator
44
+ * reading the list and fed non-markers to `revoke()` in the `--all` path.
45
+ */
24
46
  export declare function listTrusted(root?: string): string[];
25
47
  /**
26
48
  * Resolve this agent's device-id from its persisted identity. `trust-host` runs
package/dist/index.js CHANGED
@@ -349,7 +349,7 @@ var init_systemd = __esm({
349
349
 
350
350
  // src/service/backend.ts
351
351
  import { spawnSync } from "node:child_process";
352
- import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync3, rmSync as rmSync4, existsSync as existsSync5, chmodSync as chmodSync2 } from "node:fs";
352
+ import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync3, rmSync as rmSync4, existsSync as existsSync4, chmodSync as chmodSync3 } from "node:fs";
353
353
  import { userInfo } from "node:os";
354
354
  function defaultDeps() {
355
355
  return {
@@ -362,9 +362,9 @@ function defaultDeps() {
362
362
  },
363
363
  writeFile: (p2, d10) => writeFileSync3(p2, d10),
364
364
  mkdir: (p2) => mkdirSync5(p2, { recursive: true }),
365
- chmod: (p2, m6) => chmodSync2(p2, m6),
365
+ chmod: (p2, m6) => chmodSync3(p2, m6),
366
366
  rm: (p2) => rmSync4(p2, { force: true }),
367
- exists: (p2) => existsSync5(p2)
367
+ exists: (p2) => existsSync4(p2)
368
368
  };
369
369
  }
370
370
  function selectBackend(platform, deps) {
@@ -118702,10 +118702,12 @@ import { realpathSync as realpathSync2 } from "node:fs";
118702
118702
  import { resolve as resolve3, dirname as dirname2, basename, sep as sep2, isAbsolute } from "node:path";
118703
118703
 
118704
118704
  // src/host-trust.ts
118705
- import { mkdirSync as mkdirSync3, writeFileSync, rmSync as rmSync2, existsSync as existsSync3, readdirSync as readdirSync2, lstatSync as lstatSync2, readFileSync as readFileSync4 } from "node:fs";
118705
+ import { mkdirSync as mkdirSync3, writeFileSync, rmSync as rmSync2, readdirSync as readdirSync2, lstatSync as lstatSync2, readFileSync as readFileSync4, chmodSync as chmodSync2 } from "node:fs";
118706
118706
  import { join as join6 } from "node:path";
118707
118707
  import { homedir, hostname as hostname3 } from "node:os";
118708
118708
  var TRUST_SUBDIR = "host-trust";
118709
+ var DIR_MODE3 = 448;
118710
+ var FILE_MODE3 = 384;
118709
118711
  var ID_RE = /^[A-Za-z0-9_-]{1,128}$/;
118710
118712
  var IDENTITY_FILES = ["agentvault.json", "secure-channel.json", "agentvault.json.bak"];
118711
118713
  var HostTrustError = class extends Error {
@@ -118731,23 +118733,33 @@ function isTrusted(deviceId, root3) {
118731
118733
  function grant(deviceId, root3) {
118732
118734
  const id = sanitize(deviceId);
118733
118735
  const dir = trustDir(root3);
118734
- mkdirSync3(dir, { recursive: true });
118736
+ const p2 = join6(dir, id);
118737
+ mkdirSync3(dir, { recursive: true, mode: DIR_MODE3 });
118735
118738
  writeFileSync(
118736
- join6(dir, id),
118739
+ p2,
118737
118740
  `granted_at=${(/* @__PURE__ */ new Date()).toISOString()} host=${hostname3()}
118738
- `
118741
+ `,
118742
+ { mode: FILE_MODE3 }
118739
118743
  );
118744
+ chmodSync2(dir, DIR_MODE3);
118745
+ chmodSync2(p2, FILE_MODE3);
118740
118746
  }
118741
118747
  function revoke(deviceId, root3) {
118742
118748
  const id = sanitize(deviceId);
118743
118749
  const p2 = join6(trustDir(root3), id);
118744
- if (!existsSync3(p2)) return false;
118745
- rmSync2(p2, { force: true, recursive: true });
118750
+ try {
118751
+ if (!lstatSync2(p2).isFile()) return false;
118752
+ } catch {
118753
+ return false;
118754
+ }
118755
+ rmSync2(p2, { force: true });
118746
118756
  return true;
118747
118757
  }
118748
118758
  function listTrusted(root3) {
118749
118759
  try {
118750
- return readdirSync2(trustDir(root3)).filter((n10) => ID_RE.test(n10));
118760
+ return readdirSync2(trustDir(root3)).filter(
118761
+ (n10) => ID_RE.test(n10) && isTrusted(n10, root3)
118762
+ );
118751
118763
  } catch {
118752
118764
  return [];
118753
118765
  }
@@ -133227,7 +133239,7 @@ var ArmingState = class {
133227
133239
  };
133228
133240
 
133229
133241
  // src/approve-cli.ts
133230
- import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync2, readFileSync as readFileSync5, readdirSync as readdirSync3, rmSync as rmSync3, existsSync as existsSync4 } from "node:fs";
133242
+ import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync2, readFileSync as readFileSync5, readdirSync as readdirSync3, rmSync as rmSync3, existsSync as existsSync3 } from "node:fs";
133231
133243
  import { join as join7 } from "node:path";
133232
133244
  var APPROVALS_SUBDIR = "arm-approvals";
133233
133245
  var ID_RE2 = /^[A-Za-z0-9_-]{1,128}$/;
@@ -133254,7 +133266,7 @@ function writeApproval(dataDir, requestId, roomId) {
133254
133266
  }
133255
133267
  function drainApprovals(dataDir) {
133256
133268
  const dir = join7(dataDir, APPROVALS_SUBDIR);
133257
- if (!existsSync4(dir)) return [];
133269
+ if (!existsSync3(dir)) return [];
133258
133270
  const out = [];
133259
133271
  for (const name of readdirSync3(dir)) {
133260
133272
  if (!ID_RE2.test(name)) continue;
@@ -133473,7 +133485,14 @@ function wireBridge(channel, session, target, opts = {}) {
133473
133485
  e7.hushedUntil ? `room ${e7.roomId.slice(0, 8)} hushed until ${e7.hushedUntil} \u2014 holding` : `room ${e7.roomId.slice(0, 8)} hush cleared`
133474
133486
  );
133475
133487
  });
133488
+ let warnedMissingSenderIsAgent = false;
133476
133489
  channel.on("room_message", (e7) => {
133490
+ if (typeof e7.senderIsAgent !== "boolean" && !warnedMissingSenderIsAgent) {
133491
+ warnedMissingSenderIsAgent = true;
133492
+ log(
133493
+ "WARNING: inbound room_message has no `senderIsAgent` \u2014 replies to humans in rooms will be DROPPED whenever the model answers in plain text instead of calling say (#630). Most likely cause: a stale bundled plugin dist. Rebuild the bridge (npm run build in packages/claude-room-bridge) and reinstall."
133494
+ );
133495
+ }
133477
133496
  if (opts.roomFilter && e7.roomId !== opts.roomFilter) return;
133478
133497
  if (hush.isHushed(e7.roomId)) {
133479
133498
  log(`inbound from ${e7.senderName} in ${e7.roomId.slice(0, 8)} \u2014 room hushed, holding (not replying)`);
@@ -133632,7 +133651,7 @@ async function main() {
133632
133651
  "[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"
133633
133652
  );
133634
133653
  }
133635
- console.error(`[bridge] version: ${true ? "0.7.0" : "dev"}`);
133654
+ console.error(`[bridge] version: ${true ? "0.7.1" : "dev"}`);
133636
133655
  console.error(`[bridge] data dir: ${cfg.dataDir} (${cfg.dataDirSource})`);
133637
133656
  console.error(`[bridge] workspace: ${cfg.workspaceDir} \xB7 permissions: ${cfg.permissionMode} \xB7 enclave dir fenced`);
133638
133657
  if (cfg.armRoom) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentvault/claude-bridge",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
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",