@securecoms/agent-bridge 0.34.0 → 0.35.0
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 +30 -3
- package/dist/attachments.d.ts +13 -0
- package/dist/bin.js +386 -249
- package/dist/bridge-agent.d.ts +16 -1
- package/dist/errors.d.ts +1 -1
- package/dist/index.js +325 -188
- package/dist/outbox.d.ts +42 -0
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -24728,8 +24728,8 @@ function openDeliveryPings(o) {
|
|
|
24728
24728
|
return Promise.resolve({ value: void 0, done: true });
|
|
24729
24729
|
if (queue.length)
|
|
24730
24730
|
return Promise.resolve({ value: queue.shift(), done: false });
|
|
24731
|
-
return new Promise((
|
|
24732
|
-
waiter =
|
|
24731
|
+
return new Promise((resolve2) => {
|
|
24732
|
+
waiter = resolve2;
|
|
24733
24733
|
});
|
|
24734
24734
|
}
|
|
24735
24735
|
};
|
|
@@ -25049,8 +25049,8 @@ var PingSubscriber = class {
|
|
|
25049
25049
|
return Promise.resolve({ value: void 0, done: true });
|
|
25050
25050
|
if (this.queue.length)
|
|
25051
25051
|
return Promise.resolve({ value: this.queue.shift(), done: false });
|
|
25052
|
-
return new Promise((
|
|
25053
|
-
this.waiter =
|
|
25052
|
+
return new Promise((resolve2) => {
|
|
25053
|
+
this.waiter = resolve2;
|
|
25054
25054
|
});
|
|
25055
25055
|
}
|
|
25056
25056
|
};
|
|
@@ -29706,8 +29706,96 @@ function loadPackageMeta(importMetaUrl) {
|
|
|
29706
29706
|
}
|
|
29707
29707
|
|
|
29708
29708
|
// src/bridge-agent.ts
|
|
29709
|
-
import { existsSync as existsSync5, promises as
|
|
29710
|
-
|
|
29709
|
+
import { existsSync as existsSync5, promises as fsp2, readFileSync as readFileSync10, statSync as statSync4 } from "node:fs";
|
|
29710
|
+
|
|
29711
|
+
// src/outbox.ts
|
|
29712
|
+
import { constants, mkdirSync, lstatSync, chmodSync, realpathSync, promises as fsp } from "node:fs";
|
|
29713
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
29714
|
+
var VAULT_OUTBOX_DIRNAME = "vault-outbox";
|
|
29715
|
+
var PathOutsideOutboxError = class extends Error {
|
|
29716
|
+
constructor() {
|
|
29717
|
+
super("path_outside_outbox");
|
|
29718
|
+
this.name = "PathOutsideOutboxError";
|
|
29719
|
+
}
|
|
29720
|
+
};
|
|
29721
|
+
var POSIX = process.platform !== "win32";
|
|
29722
|
+
function ownedPrivateDir(st) {
|
|
29723
|
+
if (st.isSymbolicLink() || !st.isDirectory()) return false;
|
|
29724
|
+
if (!POSIX) return true;
|
|
29725
|
+
const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
|
|
29726
|
+
if (uid !== void 0 && st.uid !== uid) return false;
|
|
29727
|
+
return (st.mode & 511) === 448;
|
|
29728
|
+
}
|
|
29729
|
+
function ensureOutbox(dir) {
|
|
29730
|
+
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
29731
|
+
let st = lstatSync(dir);
|
|
29732
|
+
if (st.isSymbolicLink() || !st.isDirectory()) throw new PathOutsideOutboxError();
|
|
29733
|
+
const uid = POSIX && typeof process.getuid === "function" ? process.getuid() : void 0;
|
|
29734
|
+
if (uid !== void 0 && st.uid !== uid) throw new PathOutsideOutboxError();
|
|
29735
|
+
if (POSIX && (st.mode & 511) !== 448) {
|
|
29736
|
+
chmodSync(dir, 448);
|
|
29737
|
+
st = lstatSync(dir);
|
|
29738
|
+
}
|
|
29739
|
+
if (!ownedPrivateDir(st)) throw new PathOutsideOutboxError();
|
|
29740
|
+
return { dir, real: realpathSync(dir), dev: st.dev, ino: st.ino };
|
|
29741
|
+
}
|
|
29742
|
+
var NOFOLLOW = constants.O_NOFOLLOW ?? 0;
|
|
29743
|
+
var NONBLOCK = constants.O_NONBLOCK ?? 0;
|
|
29744
|
+
async function readOutboxFile(pin, callerPath) {
|
|
29745
|
+
if (!pin) throw new PathOutsideOutboxError();
|
|
29746
|
+
try {
|
|
29747
|
+
const st = await fsp.lstat(pin.dir);
|
|
29748
|
+
if (!ownedPrivateDir(st) || st.dev !== pin.dev || st.ino !== pin.ino) throw new PathOutsideOutboxError();
|
|
29749
|
+
} catch {
|
|
29750
|
+
throw new PathOutsideOutboxError();
|
|
29751
|
+
}
|
|
29752
|
+
const requested = resolve(pin.dir, callerPath);
|
|
29753
|
+
const name = basename(requested);
|
|
29754
|
+
let realParent;
|
|
29755
|
+
try {
|
|
29756
|
+
realParent = await fsp.realpath(dirname(requested));
|
|
29757
|
+
} catch {
|
|
29758
|
+
throw new PathOutsideOutboxError();
|
|
29759
|
+
}
|
|
29760
|
+
if (realParent !== pin.real) throw new PathOutsideOutboxError();
|
|
29761
|
+
const target = join(pin.real, name);
|
|
29762
|
+
const pre = await fsp.lstat(target);
|
|
29763
|
+
if (pre.isSymbolicLink() || !pre.isFile()) throw new PathOutsideOutboxError();
|
|
29764
|
+
let handle;
|
|
29765
|
+
try {
|
|
29766
|
+
handle = await fsp.open(target, constants.O_RDONLY | NOFOLLOW | NONBLOCK);
|
|
29767
|
+
} catch (e) {
|
|
29768
|
+
if (e.code === "ENOENT") throw e;
|
|
29769
|
+
throw new PathOutsideOutboxError();
|
|
29770
|
+
}
|
|
29771
|
+
try {
|
|
29772
|
+
const st = await handle.stat();
|
|
29773
|
+
if (!st.isFile() || st.dev !== pre.dev || st.ino !== pre.ino || st.nlink !== 1) {
|
|
29774
|
+
throw new PathOutsideOutboxError();
|
|
29775
|
+
}
|
|
29776
|
+
return { bytes: new Uint8Array(await handle.readFile()), path: target, dev: st.dev, ino: st.ino };
|
|
29777
|
+
} finally {
|
|
29778
|
+
await handle.close().catch(() => {
|
|
29779
|
+
});
|
|
29780
|
+
}
|
|
29781
|
+
}
|
|
29782
|
+
async function consumeOutboxFile(pin, read) {
|
|
29783
|
+
try {
|
|
29784
|
+
const dir = await fsp.lstat(pin.dir);
|
|
29785
|
+
if (!ownedPrivateDir(dir) || dir.dev !== pin.dev || dir.ino !== pin.ino) return false;
|
|
29786
|
+
if (await fsp.realpath(pin.dir) !== pin.real) return false;
|
|
29787
|
+
const target = join(pin.real, basename(read.path));
|
|
29788
|
+
const st = await fsp.lstat(target);
|
|
29789
|
+
if (st.isSymbolicLink() || st.dev !== read.dev || st.ino !== read.ino) return false;
|
|
29790
|
+
await fsp.unlink(target);
|
|
29791
|
+
return true;
|
|
29792
|
+
} catch {
|
|
29793
|
+
return false;
|
|
29794
|
+
}
|
|
29795
|
+
}
|
|
29796
|
+
|
|
29797
|
+
// src/bridge-agent.ts
|
|
29798
|
+
import { join as join18, dirname as dirname6 } from "node:path";
|
|
29711
29799
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
29712
29800
|
|
|
29713
29801
|
// src/latency.ts
|
|
@@ -30205,11 +30293,21 @@ function pinCoverage(pinStripped, ownerMessage, coverTexts) {
|
|
|
30205
30293
|
}
|
|
30206
30294
|
|
|
30207
30295
|
// src/attachments.ts
|
|
30208
|
-
import { basename } from "node:path";
|
|
30296
|
+
import { basename as basename2 } from "node:path";
|
|
30209
30297
|
var VAULT_REF_MAX_SIZE_HINT = 100 * 1024 * 1024 - 16;
|
|
30210
30298
|
var VAULT_REF_MAX_NAME = 255;
|
|
30211
30299
|
var VAULT_REF_MAX_MIME = 127;
|
|
30212
30300
|
var CANONICAL_UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
30301
|
+
var InvalidBlobIdError = class extends Error {
|
|
30302
|
+
constructor() {
|
|
30303
|
+
super("invalid_blob_id");
|
|
30304
|
+
this.name = "InvalidBlobIdError";
|
|
30305
|
+
}
|
|
30306
|
+
};
|
|
30307
|
+
function assertBlobId(blobId) {
|
|
30308
|
+
if (typeof blobId !== "string" || !CANONICAL_UUID.test(blobId)) throw new InvalidBlobIdError();
|
|
30309
|
+
return blobId;
|
|
30310
|
+
}
|
|
30213
30311
|
var VAULT_PIN = /^blake2b:[0-9a-f]{64}$/;
|
|
30214
30312
|
var HINT_FORBIDDEN = /[\u0000-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/;
|
|
30215
30313
|
var MIME_TYPE = /^[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*\/[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*$/;
|
|
@@ -30248,7 +30346,7 @@ function toVaultRefEntry(body) {
|
|
|
30248
30346
|
return entry;
|
|
30249
30347
|
}
|
|
30250
30348
|
function sanitizeFilename(name, fallback) {
|
|
30251
|
-
const base =
|
|
30349
|
+
const base = basename2(name ?? "");
|
|
30252
30350
|
const cleaned = base.replace(/[/\\]/g, "").replace(/^\.+$/, "");
|
|
30253
30351
|
return cleaned.length > 0 ? cleaned : fallback;
|
|
30254
30352
|
}
|
|
@@ -30278,7 +30376,7 @@ function mimeForName(name) {
|
|
|
30278
30376
|
async function prepareAttachment(filePath2, caption, channelId, deps) {
|
|
30279
30377
|
await deps.ready();
|
|
30280
30378
|
const bytes = await deps.readFile(filePath2);
|
|
30281
|
-
const name =
|
|
30379
|
+
const name = basename2(filePath2);
|
|
30282
30380
|
const { encryptedData, fileKey, fileNonce, digest } = await deps.encryptFile(bytes);
|
|
30283
30381
|
const blobId = await deps.uploadBlob(encryptedData, channelId);
|
|
30284
30382
|
const body = {
|
|
@@ -30296,8 +30394,9 @@ async function prepareAttachment(filePath2, caption, channelId, deps) {
|
|
|
30296
30394
|
return body;
|
|
30297
30395
|
}
|
|
30298
30396
|
async function materializeAttachment(body, ctx, deps) {
|
|
30397
|
+
const blobId = assertBlobId(body.blobId);
|
|
30299
30398
|
await deps.ready();
|
|
30300
|
-
const ciphertext = await deps.downloadBlob(
|
|
30399
|
+
const ciphertext = await deps.downloadBlob(blobId);
|
|
30301
30400
|
const sha25612 = await deps.computeFileDigest(ciphertext);
|
|
30302
30401
|
if (sha25612 !== body.digest) {
|
|
30303
30402
|
throw new Error(`attachment digest mismatch for blob ${body.blobId}`);
|
|
@@ -30323,13 +30422,13 @@ function ensureSodiumReady2() {
|
|
|
30323
30422
|
// src/memory/hermes-session-map.ts
|
|
30324
30423
|
import { readFileSync } from "node:fs";
|
|
30325
30424
|
import { homedir } from "node:os";
|
|
30326
|
-
import { join } from "node:path";
|
|
30425
|
+
import { join as join2 } from "node:path";
|
|
30327
30426
|
function expandHome(p) {
|
|
30328
|
-
return p === "~" || p.startsWith("~/") ?
|
|
30427
|
+
return p === "~" || p.startsWith("~/") ? join2(homedir(), p.slice(1)) : p;
|
|
30329
30428
|
}
|
|
30330
30429
|
function resolveHermesSession(baseDir, conversationId) {
|
|
30331
30430
|
try {
|
|
30332
|
-
const path =
|
|
30431
|
+
const path = join2(expandHome(baseDir), "sessions", "sessions.json");
|
|
30333
30432
|
const map = JSON.parse(readFileSync(path, "utf8"));
|
|
30334
30433
|
const entry = map[`agent:main:securecoms:dm:${conversationId}`];
|
|
30335
30434
|
const sid = entry?.session_id;
|
|
@@ -30341,11 +30440,11 @@ function resolveHermesSession(baseDir, conversationId) {
|
|
|
30341
30440
|
|
|
30342
30441
|
// src/memory/hermes-store.ts
|
|
30343
30442
|
import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
|
|
30344
|
-
import { join as
|
|
30443
|
+
import { join as join3 } from "node:path";
|
|
30345
30444
|
var HermesStore = class {
|
|
30346
30445
|
dbPath;
|
|
30347
30446
|
constructor(baseDir) {
|
|
30348
|
-
this.dbPath =
|
|
30447
|
+
this.dbPath = join3(expandHome(baseDir), "state.db");
|
|
30349
30448
|
}
|
|
30350
30449
|
/** Recent-K conversational turns for a session, chronological. Fail-safe → []. */
|
|
30351
30450
|
readRecent(sessionId, limit) {
|
|
@@ -30487,10 +30586,10 @@ var HermesMemoryProvider = class {
|
|
|
30487
30586
|
|
|
30488
30587
|
// src/memory/openclaw-session-map.ts
|
|
30489
30588
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
30490
|
-
import { join as
|
|
30589
|
+
import { join as join4 } from "node:path";
|
|
30491
30590
|
function resolveOwnerDmSession(baseDir, agent) {
|
|
30492
30591
|
try {
|
|
30493
|
-
const path =
|
|
30592
|
+
const path = join4(expandHome(baseDir), "agents", agent, "sessions", "sessions.json");
|
|
30494
30593
|
const map = JSON.parse(readFileSync2(path, "utf8"));
|
|
30495
30594
|
let best = null;
|
|
30496
30595
|
for (const [key, entry] of Object.entries(map)) {
|
|
@@ -30508,11 +30607,11 @@ function resolveOwnerDmSession(baseDir, agent) {
|
|
|
30508
30607
|
|
|
30509
30608
|
// src/memory/openclaw-session-log.ts
|
|
30510
30609
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
30511
|
-
import { join as
|
|
30610
|
+
import { join as join5 } from "node:path";
|
|
30512
30611
|
function readRecentTurns(baseDir, agent, sessionId, k) {
|
|
30513
30612
|
let raw;
|
|
30514
30613
|
try {
|
|
30515
|
-
raw = readFileSync3(
|
|
30614
|
+
raw = readFileSync3(join5(expandHome(baseDir), "agents", agent, "sessions", `${sessionId}.jsonl`), "utf8");
|
|
30516
30615
|
} catch {
|
|
30517
30616
|
return [];
|
|
30518
30617
|
}
|
|
@@ -30543,7 +30642,7 @@ function readRecentTurns(baseDir, agent, sessionId, k) {
|
|
|
30543
30642
|
|
|
30544
30643
|
// src/memory/openclaw-workspace-facts.ts
|
|
30545
30644
|
import { readdirSync, readFileSync as readFileSync4, statSync } from "node:fs";
|
|
30546
|
-
import { join as
|
|
30645
|
+
import { join as join6 } from "node:path";
|
|
30547
30646
|
var DEFAULT_FACTS_BUDGET = 8e3;
|
|
30548
30647
|
var MEMORY_MD_CAP = 6e3;
|
|
30549
30648
|
var MIN_FRAGMENT = 200;
|
|
@@ -30554,7 +30653,7 @@ function resolveWorkspaceDir(baseDir, agent, override) {
|
|
|
30554
30653
|
const base = expandHome(baseDir);
|
|
30555
30654
|
const isMain = agent === "" || agent === "main";
|
|
30556
30655
|
try {
|
|
30557
|
-
const cfg = JSON.parse(readFileSync4(
|
|
30656
|
+
const cfg = JSON.parse(readFileSync4(join6(base, "openclaw.json"), "utf8"));
|
|
30558
30657
|
const agents = cfg?.agents;
|
|
30559
30658
|
if (agents && typeof agents === "object") {
|
|
30560
30659
|
const list = Array.isArray(agents.list) ? agents.list : [];
|
|
@@ -30567,7 +30666,7 @@ function resolveWorkspaceDir(baseDir, agent, override) {
|
|
|
30567
30666
|
}
|
|
30568
30667
|
} catch {
|
|
30569
30668
|
}
|
|
30570
|
-
return isMain ?
|
|
30669
|
+
return isMain ? join6(base, "workspace") : join6(base, `workspace-${agent}`);
|
|
30571
30670
|
}
|
|
30572
30671
|
var TRUNC = "\u2026[truncated]";
|
|
30573
30672
|
function headSlice(s, n) {
|
|
@@ -30597,7 +30696,7 @@ function readWorkspaceFacts(baseDir, agent, opts) {
|
|
|
30597
30696
|
let truncated = false;
|
|
30598
30697
|
let remaining = budget;
|
|
30599
30698
|
try {
|
|
30600
|
-
const r = readBounded(
|
|
30699
|
+
const r = readBounded(join6(dir, "MEMORY.md"));
|
|
30601
30700
|
if (r.oversize) truncated = true;
|
|
30602
30701
|
else if (r.text && r.text.trim()) {
|
|
30603
30702
|
const { text, clipped } = headSlice(r.text, Math.min(MEMORY_MD_CAP, budget));
|
|
@@ -30610,7 +30709,7 @@ ${TRUNC}` : ""}`);
|
|
|
30610
30709
|
} catch {
|
|
30611
30710
|
}
|
|
30612
30711
|
try {
|
|
30613
|
-
const dailies = readdirSync(
|
|
30712
|
+
const dailies = readdirSync(join6(dir, "memory")).filter((f) => DAILY_RE.test(f)).sort().reverse().slice(0, 2);
|
|
30614
30713
|
for (const f of dailies) {
|
|
30615
30714
|
if (remaining < MIN_FRAGMENT) {
|
|
30616
30715
|
truncated = true;
|
|
@@ -30618,7 +30717,7 @@ ${TRUNC}` : ""}`);
|
|
|
30618
30717
|
}
|
|
30619
30718
|
let r;
|
|
30620
30719
|
try {
|
|
30621
|
-
r = readBounded(
|
|
30720
|
+
r = readBounded(join6(dir, "memory", f));
|
|
30622
30721
|
} catch {
|
|
30623
30722
|
continue;
|
|
30624
30723
|
}
|
|
@@ -31357,21 +31456,21 @@ function parsePayloadMemory(raw) {
|
|
|
31357
31456
|
|
|
31358
31457
|
// src/memory/embedder/client.ts
|
|
31359
31458
|
import { connect } from "node:net";
|
|
31360
|
-
import { existsSync as existsSync3, mkdirSync as
|
|
31459
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync5, readFileSync as readFileSync7, rmSync as rmSync6, statSync as statSync2 } from "node:fs";
|
|
31361
31460
|
import { fileURLToPath } from "node:url";
|
|
31362
31461
|
|
|
31363
31462
|
// src/memory/embedder/download.ts
|
|
31364
31463
|
import { createHash as createHash2, randomBytes as randomBytes6 } from "node:crypto";
|
|
31365
|
-
import { chmodSync as
|
|
31464
|
+
import { chmodSync as chmodSync3, rmSync as rmSync2 } from "node:fs";
|
|
31366
31465
|
import { open } from "node:fs/promises";
|
|
31367
|
-
import { join as
|
|
31466
|
+
import { join as join8 } from "node:path";
|
|
31368
31467
|
|
|
31369
31468
|
// src/memory/embedder/layout.ts
|
|
31370
|
-
import { chmodSync, lstatSync, mkdirSync, renameSync, rmSync } from "node:fs";
|
|
31469
|
+
import { chmodSync as chmodSync2, lstatSync as lstatSync2, mkdirSync as mkdirSync2, renameSync, rmSync } from "node:fs";
|
|
31371
31470
|
import { homedir as homedir2 } from "node:os";
|
|
31372
|
-
import { basename as
|
|
31373
|
-
var defaultModelsRoot = (home = homedir2()) =>
|
|
31374
|
-
var filePath = (root3, modelId, f) =>
|
|
31471
|
+
import { basename as basename3, dirname as dirname2, join as join7 } from "node:path";
|
|
31472
|
+
var defaultModelsRoot = (home = homedir2()) => join7(home, ".securecoms", "models", "embeddings");
|
|
31473
|
+
var filePath = (root3, modelId, f) => join7(root3, modelId, f.sha256, f.name);
|
|
31375
31474
|
var LayoutRefused = class extends Error {
|
|
31376
31475
|
constructor() {
|
|
31377
31476
|
super("the model directory is not a plain directory");
|
|
@@ -31379,32 +31478,32 @@ var LayoutRefused = class extends Error {
|
|
|
31379
31478
|
};
|
|
31380
31479
|
function kind(p) {
|
|
31381
31480
|
try {
|
|
31382
|
-
return
|
|
31481
|
+
return lstatSync2(p).isDirectory() ? "dir" : "other";
|
|
31383
31482
|
} catch (e) {
|
|
31384
31483
|
if (e.code === "ENOENT") return "absent";
|
|
31385
31484
|
throw e;
|
|
31386
31485
|
}
|
|
31387
31486
|
}
|
|
31388
31487
|
function plainDirChain(root3, parts, opts) {
|
|
31389
|
-
const modelsDir =
|
|
31488
|
+
const modelsDir = dirname2(root3);
|
|
31390
31489
|
for (const part of parts) if (!part || part === "." || part === ".." || part.includes("/") || part.includes("\\")) throw new LayoutRefused();
|
|
31391
31490
|
const k = kind(modelsDir);
|
|
31392
31491
|
if (k === "other") throw new LayoutRefused();
|
|
31393
31492
|
if (k === "absent") {
|
|
31394
31493
|
if (!opts.create) return null;
|
|
31395
|
-
|
|
31494
|
+
mkdirSync2(modelsDir, { recursive: true, mode: 448 });
|
|
31396
31495
|
if (kind(modelsDir) !== "dir") throw new LayoutRefused();
|
|
31397
31496
|
}
|
|
31398
|
-
const chain = opts.fromModelsDir ? parts : [
|
|
31497
|
+
const chain = opts.fromModelsDir ? parts : [basename3(root3), ...parts];
|
|
31399
31498
|
let p = modelsDir;
|
|
31400
31499
|
for (let i = 0; i < chain.length; i++) {
|
|
31401
|
-
p =
|
|
31500
|
+
p = join7(p, chain[i]);
|
|
31402
31501
|
const c = kind(p);
|
|
31403
31502
|
if (c === "other") throw new LayoutRefused();
|
|
31404
31503
|
if (c === "absent") {
|
|
31405
31504
|
if (!opts.create) return null;
|
|
31406
31505
|
try {
|
|
31407
|
-
|
|
31506
|
+
mkdirSync2(p, { mode: i === chain.length - 1 && opts.mode !== void 0 ? opts.mode : 493 });
|
|
31408
31507
|
} catch (e) {
|
|
31409
31508
|
if (e.code !== "EEXIST") throw e;
|
|
31410
31509
|
}
|
|
@@ -31415,7 +31514,7 @@ function plainDirChain(root3, parts, opts) {
|
|
|
31415
31514
|
}
|
|
31416
31515
|
function presentWithSize(p, size) {
|
|
31417
31516
|
try {
|
|
31418
|
-
const s =
|
|
31517
|
+
const s = lstatSync2(p);
|
|
31419
31518
|
return s.isFile() && s.size === size;
|
|
31420
31519
|
} catch {
|
|
31421
31520
|
return false;
|
|
@@ -31423,7 +31522,7 @@ function presentWithSize(p, size) {
|
|
|
31423
31522
|
}
|
|
31424
31523
|
function wrongTypeAt(p) {
|
|
31425
31524
|
try {
|
|
31426
|
-
const s =
|
|
31525
|
+
const s = lstatSync2(p);
|
|
31427
31526
|
return !s.isFile() && !s.isSymbolicLink();
|
|
31428
31527
|
} catch {
|
|
31429
31528
|
return false;
|
|
@@ -31436,16 +31535,16 @@ function installVerified(root3, modelId, f, partial, opts) {
|
|
|
31436
31535
|
dir = plainDirChain(root3, [modelId, f.sha256], { create: true });
|
|
31437
31536
|
if (!dir) throw new LayoutRefused();
|
|
31438
31537
|
if (!opts.replace && presentWithSize(dest, f.size)) return;
|
|
31439
|
-
|
|
31538
|
+
chmodSync2(dir, 493);
|
|
31440
31539
|
try {
|
|
31441
31540
|
renameSync(partial, dest);
|
|
31442
31541
|
} catch (e) {
|
|
31443
31542
|
if (!presentWithSize(dest, f.size)) throw e;
|
|
31444
31543
|
return;
|
|
31445
31544
|
}
|
|
31446
|
-
|
|
31545
|
+
chmodSync2(dest, 292);
|
|
31447
31546
|
} finally {
|
|
31448
|
-
if (dir)
|
|
31547
|
+
if (dir) chmodSync2(dir, 365);
|
|
31449
31548
|
rmSync(partial, { force: true });
|
|
31450
31549
|
}
|
|
31451
31550
|
}
|
|
@@ -31465,8 +31564,8 @@ function removeModelFiles(root3, m) {
|
|
|
31465
31564
|
for (const f of m.files) {
|
|
31466
31565
|
const dir = plainDirChain(root3, [m.modelId, f.sha256], { create: false });
|
|
31467
31566
|
if (!dir) continue;
|
|
31468
|
-
|
|
31469
|
-
rmSync2(
|
|
31567
|
+
chmodSync3(dir, 493);
|
|
31568
|
+
rmSync2(join8(dir, f.name), { force: true });
|
|
31470
31569
|
}
|
|
31471
31570
|
}
|
|
31472
31571
|
var VerifyFailed = class extends Error {
|
|
@@ -31513,7 +31612,7 @@ async function fetchSameOrigin(url, origin, fetchImpl, signal, stallMs, abort) {
|
|
|
31513
31612
|
async function downloadOne(f, o) {
|
|
31514
31613
|
if (wrongTypeAt(filePath(o.root, o.modelId, f))) throw new WrongType("wrong type at model path");
|
|
31515
31614
|
const pdir = plainDirChain(o.root, [".partial"], { create: true, fromModelsDir: true, mode: 448 });
|
|
31516
|
-
const partial =
|
|
31615
|
+
const partial = join8(pdir, randomBytes6(12).toString("hex"));
|
|
31517
31616
|
const fh = await open(partial, "wx", 384);
|
|
31518
31617
|
const ac = new AbortController();
|
|
31519
31618
|
const abort = () => ac.abort();
|
|
@@ -31589,17 +31688,17 @@ async function ensureModelFiles(o) {
|
|
|
31589
31688
|
}
|
|
31590
31689
|
|
|
31591
31690
|
// src/memory/embedder/gc.ts
|
|
31592
|
-
import { chmodSync as
|
|
31593
|
-
import { join as
|
|
31691
|
+
import { chmodSync as chmodSync4, closeSync, constants as constants2, fstatSync, futimesSync, lstatSync as lstatSync3, openSync, readdirSync as readdirSync2, rmSync as rmSync3 } from "node:fs";
|
|
31692
|
+
import { join as join9 } from "node:path";
|
|
31594
31693
|
var THIRTY_DAYS = 30 * 864e5;
|
|
31595
31694
|
var SAFE_ID = /^[A-Za-z0-9_-]{1,128}$/;
|
|
31596
31695
|
function touchUserMarker(root3, modelId, identityId) {
|
|
31597
31696
|
if (!SAFE_ID.test(identityId)) throw new Error("invalid identity id for the model marker");
|
|
31598
31697
|
const dir = plainDirChain(root3, [modelId, ".users"], { create: true });
|
|
31599
|
-
const p =
|
|
31698
|
+
const p = join9(dir, identityId);
|
|
31600
31699
|
let fd;
|
|
31601
31700
|
try {
|
|
31602
|
-
fd = openSync(p,
|
|
31701
|
+
fd = openSync(p, constants2.O_WRONLY | constants2.O_CREAT | constants2.O_NOFOLLOW | constants2.O_NONBLOCK, 420);
|
|
31603
31702
|
} catch {
|
|
31604
31703
|
throw new Error("the model marker is not a regular file");
|
|
31605
31704
|
}
|
|
@@ -31613,22 +31712,22 @@ function touchUserMarker(root3, modelId, identityId) {
|
|
|
31613
31712
|
}
|
|
31614
31713
|
function isRealDir(p) {
|
|
31615
31714
|
try {
|
|
31616
|
-
return
|
|
31715
|
+
return lstatSync3(p).isDirectory();
|
|
31617
31716
|
} catch {
|
|
31618
31717
|
return false;
|
|
31619
31718
|
}
|
|
31620
31719
|
}
|
|
31621
31720
|
function makeWritable(p) {
|
|
31622
31721
|
if (!isRealDir(p)) return;
|
|
31623
|
-
|
|
31624
|
-
for (const e of readdirSync2(p)) makeWritable(
|
|
31722
|
+
chmodSync4(p, 493);
|
|
31723
|
+
for (const e of readdirSync2(p)) makeWritable(join9(p, e));
|
|
31625
31724
|
}
|
|
31626
31725
|
function newestMarkerMs(users) {
|
|
31627
31726
|
if (!isRealDir(users)) return void 0;
|
|
31628
31727
|
let newest;
|
|
31629
31728
|
for (const u of readdirSync2(users)) {
|
|
31630
31729
|
try {
|
|
31631
|
-
const s =
|
|
31730
|
+
const s = lstatSync3(join9(users, u));
|
|
31632
31731
|
if (!s.isFile()) continue;
|
|
31633
31732
|
newest = newest === void 0 ? s.mtimeMs : Math.max(newest, s.mtimeMs);
|
|
31634
31733
|
} catch {
|
|
@@ -31641,9 +31740,9 @@ function gcModels(root3, keepModelIds, now, maxAgeMs = THIRTY_DAYS) {
|
|
|
31641
31740
|
const removed = [];
|
|
31642
31741
|
for (const modelId of readdirSync2(root3).sort()) {
|
|
31643
31742
|
if (modelId.startsWith(".") || keepModelIds.includes(modelId)) continue;
|
|
31644
|
-
const tree =
|
|
31743
|
+
const tree = join9(root3, modelId);
|
|
31645
31744
|
if (!isRealDir(tree)) continue;
|
|
31646
|
-
const lastUse = newestMarkerMs(
|
|
31745
|
+
const lastUse = newestMarkerMs(join9(tree, ".users")) ?? lstatSync3(tree).mtimeMs;
|
|
31647
31746
|
if (now - lastUse <= maxAgeMs) continue;
|
|
31648
31747
|
makeWritable(tree);
|
|
31649
31748
|
rmSync3(tree, { recursive: true, force: true });
|
|
@@ -31776,44 +31875,44 @@ var SealedChannel = class {
|
|
|
31776
31875
|
// src/memory/embedder/embedder-paths.ts
|
|
31777
31876
|
import { createHash as createHash3 } from "node:crypto";
|
|
31778
31877
|
import { homedir as homedir3 } from "node:os";
|
|
31779
|
-
import { join as
|
|
31878
|
+
import { join as join10 } from "node:path";
|
|
31780
31879
|
function embedderKey(m) {
|
|
31781
31880
|
const model = m.files.find((f) => f.name === "model.onnx");
|
|
31782
31881
|
return createHash3("sha256").update(`${EMBEDDER_PROTOCOL}\0${m.modelId}\0${model.sha256}\0${m.wasmSha256}`).digest("hex").slice(0, 16);
|
|
31783
31882
|
}
|
|
31784
|
-
var embedderRunDir = (home = homedir3()) =>
|
|
31883
|
+
var embedderRunDir = (home = homedir3()) => join10(home, ".securecoms", "run", "embedder");
|
|
31785
31884
|
var embedderPaths = (dir, key) => ({
|
|
31786
|
-
sock:
|
|
31787
|
-
token:
|
|
31788
|
-
lock:
|
|
31789
|
-
status:
|
|
31790
|
-
pid:
|
|
31885
|
+
sock: join10(dir, `${key}.sock`),
|
|
31886
|
+
token: join10(dir, `${key}.token`),
|
|
31887
|
+
lock: join10(dir, `${key}.spawn.lock`),
|
|
31888
|
+
status: join10(dir, `${key}.status`),
|
|
31889
|
+
pid: join10(dir, `${key}.pid`)
|
|
31791
31890
|
// E1 delta H1: the instance's lifetime lock
|
|
31792
31891
|
});
|
|
31793
31892
|
var SOCKET_PATH_MAX = 103;
|
|
31794
31893
|
var windowsRunDir = (env = process.env) => {
|
|
31795
31894
|
if (!env.LOCALAPPDATA) throw new Error("LOCALAPPDATA unset");
|
|
31796
|
-
return
|
|
31895
|
+
return join10(env.LOCALAPPDATA, "SecureComs", "run", "embedder");
|
|
31797
31896
|
};
|
|
31798
31897
|
|
|
31799
31898
|
// src/memory/embedder/spawn.ts
|
|
31800
31899
|
import { spawn } from "node:child_process";
|
|
31801
|
-
import { existsSync as existsSync2, mkdirSync as
|
|
31900
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync4, realpathSync as realpathSync2 } from "node:fs";
|
|
31802
31901
|
|
|
31803
31902
|
// src/memory/embedder/run-dir.ts
|
|
31804
|
-
import { existsSync, lstatSync as
|
|
31805
|
-
import { dirname as
|
|
31903
|
+
import { existsSync, lstatSync as lstatSync4, mkdirSync as mkdirSync3 } from "node:fs";
|
|
31904
|
+
import { dirname as dirname3 } from "node:path";
|
|
31806
31905
|
var RunDirRefused = class extends Error {
|
|
31807
31906
|
};
|
|
31808
|
-
function ensureRunDir(dir, uid = process.getuid?.() ?? -1, lstat =
|
|
31809
|
-
const parent3 =
|
|
31810
|
-
if (!existsSync(parent3))
|
|
31907
|
+
function ensureRunDir(dir, uid = process.getuid?.() ?? -1, lstat = lstatSync4) {
|
|
31908
|
+
const parent3 = dirname3(dir);
|
|
31909
|
+
if (!existsSync(parent3)) mkdirSync3(parent3, { recursive: true, mode: 448 });
|
|
31811
31910
|
const ps = lstat(parent3);
|
|
31812
31911
|
if (ps.isSymbolicLink() || !ps.isDirectory()) throw new RunDirRefused("run directory parent is not a real directory");
|
|
31813
31912
|
if (ps.uid !== uid) throw new RunDirRefused("run directory parent is not owned by this user");
|
|
31814
31913
|
if ((ps.mode & 18) !== 0) throw new RunDirRefused("run directory parent is group or world writable");
|
|
31815
31914
|
try {
|
|
31816
|
-
|
|
31915
|
+
mkdirSync3(dir, { mode: 448 });
|
|
31817
31916
|
} catch (e) {
|
|
31818
31917
|
if (e.code !== "EEXIST") throw e;
|
|
31819
31918
|
}
|
|
@@ -31824,10 +31923,10 @@ function ensureRunDir(dir, uid = process.getuid?.() ?? -1, lstat = lstatSync3) {
|
|
|
31824
31923
|
}
|
|
31825
31924
|
|
|
31826
31925
|
// src/memory/embedder/spawn.ts
|
|
31827
|
-
import { basename as
|
|
31926
|
+
import { basename as basename4, dirname as dirname4, join as join11 } from "node:path";
|
|
31828
31927
|
|
|
31829
31928
|
// src/memory/embedder/locks.ts
|
|
31830
|
-
import { closeSync as closeSync2, constants as
|
|
31929
|
+
import { closeSync as closeSync2, constants as constants3, fstatSync as fstatSync2, linkSync, openSync as openSync2, readFileSync as readFileSync5, renameSync as renameSync2, rmSync as rmSync4, writeSync } from "node:fs";
|
|
31831
31930
|
import { randomBytes as randomBytes9 } from "node:crypto";
|
|
31832
31931
|
import { uptime } from "node:os";
|
|
31833
31932
|
var LOCK_STALE_MS = 1e4;
|
|
@@ -31849,7 +31948,7 @@ var PROCESS_LOCK_ENV = {
|
|
|
31849
31948
|
function inspect(path) {
|
|
31850
31949
|
let fd;
|
|
31851
31950
|
try {
|
|
31852
|
-
fd = openSync2(path,
|
|
31951
|
+
fd = openSync2(path, constants3.O_RDONLY | constants3.O_NOFOLLOW);
|
|
31853
31952
|
} catch {
|
|
31854
31953
|
return null;
|
|
31855
31954
|
}
|
|
@@ -31873,7 +31972,7 @@ function takeLock(path, now = Date.now, env = PROCESS_LOCK_ENV) {
|
|
|
31873
31972
|
const id = `${env.pid} ${env.bootTime()} ${env.startTime()} ${randomBytes9(8).toString("hex")}`;
|
|
31874
31973
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
31875
31974
|
try {
|
|
31876
|
-
const fd = openSync2(path,
|
|
31975
|
+
const fd = openSync2(path, constants3.O_CREAT | constants3.O_EXCL | constants3.O_WRONLY, 384);
|
|
31877
31976
|
try {
|
|
31878
31977
|
writeSync(fd, id);
|
|
31879
31978
|
} finally {
|
|
@@ -31934,7 +32033,7 @@ function embedderEnv(env = process.env, platform = process.platform) {
|
|
|
31934
32033
|
}
|
|
31935
32034
|
var withReal = (p) => {
|
|
31936
32035
|
try {
|
|
31937
|
-
const r =
|
|
32036
|
+
const r = realpathSync2(p);
|
|
31938
32037
|
return r === p ? [p] : [p, r];
|
|
31939
32038
|
} catch {
|
|
31940
32039
|
return [p];
|
|
@@ -31942,10 +32041,10 @@ var withReal = (p) => {
|
|
|
31942
32041
|
};
|
|
31943
32042
|
var realish = (p) => {
|
|
31944
32043
|
try {
|
|
31945
|
-
return
|
|
32044
|
+
return realpathSync2(p);
|
|
31946
32045
|
} catch {
|
|
31947
|
-
const up =
|
|
31948
|
-
return up === p ? p :
|
|
32046
|
+
const up = dirname4(p);
|
|
32047
|
+
return up === p ? p : join11(realish(up), basename4(p));
|
|
31949
32048
|
}
|
|
31950
32049
|
};
|
|
31951
32050
|
var both = (p) => {
|
|
@@ -31957,7 +32056,7 @@ function spawnEmbedder(o) {
|
|
|
31957
32056
|
const run = o.runDir ?? embedderRunDir(o.home);
|
|
31958
32057
|
const win = (o.platform ?? process.platform) === "win32";
|
|
31959
32058
|
if (o.createRunDir !== false) {
|
|
31960
|
-
if (win)
|
|
32059
|
+
if (win) mkdirSync4(run, { recursive: true, mode: 448 });
|
|
31961
32060
|
else ensureRunDir(run);
|
|
31962
32061
|
}
|
|
31963
32062
|
const perm = permissionFlags();
|
|
@@ -31966,13 +32065,13 @@ function spawnEmbedder(o) {
|
|
|
31966
32065
|
o.onNoPermissionModel?.();
|
|
31967
32066
|
}
|
|
31968
32067
|
const reads = perm.length === 0 ? [] : [
|
|
31969
|
-
...withReal(
|
|
32068
|
+
...withReal(dirname4(o.distDir)),
|
|
31970
32069
|
...existsSync2(defaultModelsRoot(o.home)) ? withReal(defaultModelsRoot(o.home)) : [defaultModelsRoot(o.home)],
|
|
31971
|
-
...both(
|
|
31972
|
-
...win ? both(
|
|
32070
|
+
...both(dirname4(run)),
|
|
32071
|
+
...win ? both(join11(o.home, ".securecoms", "run")) : []
|
|
31973
32072
|
// the voice-call heartbeats (the run dir lives elsewhere)
|
|
31974
32073
|
];
|
|
31975
|
-
const script = withReal(
|
|
32074
|
+
const script = withReal(join11(o.distDir, "embedder.js")).at(-1);
|
|
31976
32075
|
const net = (o.nodeFlags ?? process.allowedNodeEnvironmentFlags).has("--allow-net") ? ["--allow-net"] : [];
|
|
31977
32076
|
const flags = perm.length === 0 ? [] : [...perm, ...reads.map((r) => `--allow-fs-read=${r}`), ...both(run).map((w) => `--allow-fs-write=${w}`), "--allow-worker", ...net];
|
|
31978
32077
|
const child = (o.spawnFn ?? spawn)(
|
|
@@ -31981,7 +32080,7 @@ function spawnEmbedder(o) {
|
|
|
31981
32080
|
// 11c review LOW 3, fixed by the Task 12 Mini gate: cwd is the run directory's PARENT, which the bridge created (0700)
|
|
31982
32081
|
// before spawning; the run directory itself is created by the embedder, so on a first start it does not exist yet and
|
|
31983
32082
|
// a cwd there fails the spawn with ENOENT. Never the bridge's working directory.
|
|
31984
|
-
{ detached: true, stdio: "ignore", windowsHide: true, cwd:
|
|
32083
|
+
{ detached: true, stdio: "ignore", windowsHide: true, cwd: dirname4(run), env: win ? { ...embedderEnv(process.env, "win32"), USERPROFILE: o.home, LOCALAPPDATA: dirname4(dirname4(dirname4(run))) } : { ...embedderEnv(), HOME: o.home } }
|
|
31985
32084
|
);
|
|
31986
32085
|
child.unref();
|
|
31987
32086
|
child.on("error", () => {
|
|
@@ -31993,8 +32092,8 @@ function spawnEmbedder(o) {
|
|
|
31993
32092
|
import { execFile } from "node:child_process";
|
|
31994
32093
|
import { promisify } from "node:util";
|
|
31995
32094
|
import { randomBytes as randomBytes10 } from "node:crypto";
|
|
31996
|
-
import { lstatSync as
|
|
31997
|
-
import { join as
|
|
32095
|
+
import { lstatSync as lstatSync5, readFileSync as readFileSync6, rmSync as rmSync5 } from "node:fs";
|
|
32096
|
+
import { join as join12, win32 } from "node:path";
|
|
31998
32097
|
var WINDOWS_SEMANTIC_ENABLED = false;
|
|
31999
32098
|
var windowsSemanticOn = (platform, enabled = WINDOWS_SEMANTIC_ENABLED) => platform !== "win32" || enabled;
|
|
32000
32099
|
function parseSaveSddl(saveFile) {
|
|
@@ -32022,7 +32121,7 @@ function aclAllows(sddl, ownerSid) {
|
|
|
32022
32121
|
if (aces.length === 0 || rest !== "" && !rest.startsWith("S:")) return false;
|
|
32023
32122
|
return aces.every((a) => a[0] === "A" && allowed.has(a[5] ?? "") || a[0] === "D");
|
|
32024
32123
|
}
|
|
32025
|
-
function hasReparsePoint(path, lstat =
|
|
32124
|
+
function hasReparsePoint(path, lstat = lstatSync5) {
|
|
32026
32125
|
const root3 = win32.parse(path).root;
|
|
32027
32126
|
let cur = root3;
|
|
32028
32127
|
for (const part of path.slice(root3.length).split(/[\\/]/).filter(Boolean)) {
|
|
@@ -32041,7 +32140,7 @@ async function currentUserSid(run = defaultRunner) {
|
|
|
32041
32140
|
}
|
|
32042
32141
|
async function verifyRunDirAcl(path, deps = {}, sid) {
|
|
32043
32142
|
const run = deps.run ?? defaultRunner;
|
|
32044
|
-
const out =
|
|
32143
|
+
const out = join12(deps.tmp ?? process.env.TEMP ?? process.env.TMP ?? ".", `sc-acl-${randomBytes10(8).toString("hex")}.txt`);
|
|
32045
32144
|
try {
|
|
32046
32145
|
if (hasReparsePoint(path, deps.lstat)) return false;
|
|
32047
32146
|
const user = await (sid ? sid() : currentUserSid(run));
|
|
@@ -32122,12 +32221,12 @@ var EmbedderClient = class {
|
|
|
32122
32221
|
ready(ms) {
|
|
32123
32222
|
if (this.st.state === "ready") return Promise.resolve(true);
|
|
32124
32223
|
if (this.st.state !== "preparing" || !(ms > 0)) return Promise.resolve(false);
|
|
32125
|
-
return new Promise((
|
|
32224
|
+
return new Promise((resolve2) => {
|
|
32126
32225
|
let t;
|
|
32127
32226
|
const w = (ok) => {
|
|
32128
32227
|
clearTimeout(t);
|
|
32129
32228
|
this.readyWaiters.delete(w);
|
|
32130
|
-
|
|
32229
|
+
resolve2(ok);
|
|
32131
32230
|
};
|
|
32132
32231
|
this.readyWaiters.add(w);
|
|
32133
32232
|
t = setTimeout(() => w(false), ms);
|
|
@@ -32236,7 +32335,7 @@ var EmbedderClient = class {
|
|
|
32236
32335
|
const p = this.paths();
|
|
32237
32336
|
if (!this.tcp() && Buffer.byteLength(`${p.sock}.00000000`) > SOCKET_PATH_MAX) return this.fail("run_dir_refused");
|
|
32238
32337
|
if (this.tcp()) {
|
|
32239
|
-
|
|
32338
|
+
mkdirSync5(this.runDir(), { recursive: true, mode: 448 });
|
|
32240
32339
|
if (!await this.aclOk(true)) return this.fail("acl_unverified");
|
|
32241
32340
|
}
|
|
32242
32341
|
if (!this.tcp()) {
|
|
@@ -32372,7 +32471,7 @@ var EmbedderClient = class {
|
|
|
32372
32471
|
}
|
|
32373
32472
|
if (this.closed) return false;
|
|
32374
32473
|
}
|
|
32375
|
-
return new Promise((
|
|
32474
|
+
return new Promise((resolve2) => {
|
|
32376
32475
|
const s = this.tcp() ? connect({ host: "127.0.0.1", port: pub.port }) : connect(p.sock);
|
|
32377
32476
|
const nc = nonce();
|
|
32378
32477
|
let ns = "";
|
|
@@ -32385,7 +32484,7 @@ var EmbedderClient = class {
|
|
|
32385
32484
|
if (!settled) {
|
|
32386
32485
|
settled = true;
|
|
32387
32486
|
clearTimeout(t);
|
|
32388
|
-
|
|
32487
|
+
resolve2(ok);
|
|
32389
32488
|
}
|
|
32390
32489
|
}
|
|
32391
32490
|
const refuse2 = (reason) => {
|
|
@@ -32950,12 +33049,12 @@ var ReembedQueue = class {
|
|
|
32950
33049
|
};
|
|
32951
33050
|
|
|
32952
33051
|
// src/memory/recall/call-heartbeat.ts
|
|
32953
|
-
import { closeSync as closeSync3, constants as
|
|
32954
|
-
import { join as
|
|
33052
|
+
import { closeSync as closeSync3, constants as constants4, fstatSync as fstatSync3, futimesSync as futimesSync2, openSync as openSync3, rmSync as rmSync7 } from "node:fs";
|
|
33053
|
+
import { join as join14 } from "node:path";
|
|
32955
33054
|
|
|
32956
33055
|
// src/memory/embedder/heartbeats.ts
|
|
32957
|
-
import { lstatSync as
|
|
32958
|
-
import { join as
|
|
33056
|
+
import { lstatSync as lstatSync6, readdirSync as readdirSync3 } from "node:fs";
|
|
33057
|
+
import { join as join13 } from "node:path";
|
|
32959
33058
|
var HEARTBEAT_FUTURE_SKEW_MS = 6e4;
|
|
32960
33059
|
var HEARTBEAT_STALE_MS = 3e4;
|
|
32961
33060
|
function heartbeatAgeFresh(ageMs, staleMs = HEARTBEAT_STALE_MS) {
|
|
@@ -32970,7 +33069,7 @@ function anyHeartbeatFresh(dir, now, staleMs = HEARTBEAT_STALE_MS) {
|
|
|
32970
33069
|
}
|
|
32971
33070
|
return names.some((n) => {
|
|
32972
33071
|
try {
|
|
32973
|
-
const st =
|
|
33072
|
+
const st = lstatSync6(join13(dir, n));
|
|
32974
33073
|
return st.isFile() && heartbeatAgeFresh(now - st.mtimeMs, staleMs);
|
|
32975
33074
|
} catch {
|
|
32976
33075
|
return false;
|
|
@@ -33036,7 +33135,7 @@ var CallHeartbeat = class {
|
|
|
33036
33135
|
if (dir === null) return;
|
|
33037
33136
|
let fd;
|
|
33038
33137
|
try {
|
|
33039
|
-
fd = openSync3(
|
|
33138
|
+
fd = openSync3(join14(dir, this.identityId), constants4.O_WRONLY | constants4.O_CREAT | constants4.O_NOFOLLOW | constants4.O_NONBLOCK, 384);
|
|
33040
33139
|
if (!fstatSync3(fd).isFile()) return;
|
|
33041
33140
|
const t = new Date(this.now());
|
|
33042
33141
|
futimesSync2(fd, t, t);
|
|
@@ -33051,7 +33150,7 @@ var CallHeartbeat = class {
|
|
|
33051
33150
|
const dir = SAFE_ID2.test(this.identityId) ? this.dirOk() : null;
|
|
33052
33151
|
if (dir === null) return;
|
|
33053
33152
|
try {
|
|
33054
|
-
rmSync7(
|
|
33153
|
+
rmSync7(join14(dir, this.identityId), { force: true });
|
|
33055
33154
|
this.wrote = false;
|
|
33056
33155
|
} catch (e) {
|
|
33057
33156
|
this.log("warn", "memory.call_heartbeat_failed", {}, e);
|
|
@@ -33114,9 +33213,9 @@ function queryTokenMacs(key, text, max = QUERY_MACS_MAX) {
|
|
|
33114
33213
|
|
|
33115
33214
|
// src/memory/unified/ranking-client.ts
|
|
33116
33215
|
import { Worker } from "node:worker_threads";
|
|
33117
|
-
import { join as
|
|
33216
|
+
import { join as join15 } from "node:path";
|
|
33118
33217
|
function workerTransport(init, distDir) {
|
|
33119
|
-
const w = new Worker(
|
|
33218
|
+
const w = new Worker(join15(distDir, "memory-worker.js"), { workerData: init });
|
|
33120
33219
|
return {
|
|
33121
33220
|
post: (m) => w.postMessage(m),
|
|
33122
33221
|
onMessage: (cb) => {
|
|
@@ -33176,15 +33275,15 @@ var RankingClient = class {
|
|
|
33176
33275
|
ask(build, deadlineAt) {
|
|
33177
33276
|
const id = ++this.seq;
|
|
33178
33277
|
if (this.closed) return Promise.resolve("failed");
|
|
33179
|
-
return new Promise((
|
|
33278
|
+
return new Promise((resolve2) => {
|
|
33180
33279
|
const timer = setTimeout(() => {
|
|
33181
33280
|
this.waiting.delete(id);
|
|
33182
33281
|
this.misses++;
|
|
33183
|
-
|
|
33282
|
+
resolve2("late");
|
|
33184
33283
|
}, Math.max(0, deadlineAt - Date.now()));
|
|
33185
33284
|
this.waiting.set(id, { resolve: (m) => {
|
|
33186
33285
|
clearTimeout(timer);
|
|
33187
|
-
|
|
33286
|
+
resolve2(m);
|
|
33188
33287
|
} });
|
|
33189
33288
|
try {
|
|
33190
33289
|
this.transport().post(build(id));
|
|
@@ -33193,7 +33292,7 @@ var RankingClient = class {
|
|
|
33193
33292
|
this.waiting.delete(id);
|
|
33194
33293
|
this.misses++;
|
|
33195
33294
|
(this.d.log ?? writeServiceLog2)("warn", "memory.ranking_worker_spawn_failed", void 0, e);
|
|
33196
|
-
|
|
33295
|
+
resolve2("failed");
|
|
33197
33296
|
}
|
|
33198
33297
|
});
|
|
33199
33298
|
}
|
|
@@ -34787,17 +34886,17 @@ async function runSummarize(opts) {
|
|
|
34787
34886
|
// src/service/runtime-config-dir.ts
|
|
34788
34887
|
import { createHash as createHash5, randomUUID } from "node:crypto";
|
|
34789
34888
|
import {
|
|
34790
|
-
chmodSync as
|
|
34889
|
+
chmodSync as chmodSync5,
|
|
34791
34890
|
existsSync as existsSync4,
|
|
34792
|
-
lstatSync as
|
|
34793
|
-
mkdirSync as
|
|
34891
|
+
lstatSync as lstatSync7,
|
|
34892
|
+
mkdirSync as mkdirSync6,
|
|
34794
34893
|
readFileSync as readFileSync8,
|
|
34795
34894
|
renameSync as renameSync3,
|
|
34796
34895
|
statSync as statSync3,
|
|
34797
34896
|
unlinkSync,
|
|
34798
34897
|
writeFileSync
|
|
34799
34898
|
} from "node:fs";
|
|
34800
|
-
import { basename as
|
|
34899
|
+
import { basename as basename5, isAbsolute, join as join16 } from "node:path";
|
|
34801
34900
|
|
|
34802
34901
|
// src/grants/search-providers.ts
|
|
34803
34902
|
var SEARCH_PROVIDERS = /* @__PURE__ */ new Set(["brave", "tavily", "parallel", "exa", "firecrawl"]);
|
|
@@ -34809,18 +34908,18 @@ function isSearchProvider(value) {
|
|
|
34809
34908
|
// src/service/runtime-config-dir.ts
|
|
34810
34909
|
var MEMORY_FILE = "MEMORY.md";
|
|
34811
34910
|
var REAL_FS = {
|
|
34812
|
-
mkdir: (p, mode) =>
|
|
34813
|
-
chmod: (p, mode) =>
|
|
34911
|
+
mkdir: (p, mode) => mkdirSync6(p, { recursive: true, mode }),
|
|
34912
|
+
chmod: (p, mode) => chmodSync5(p, mode),
|
|
34814
34913
|
writeFile: (p, data, mode) => writeFileSync(p, data, { mode }),
|
|
34815
34914
|
rename: (a, b) => renameSync3(a, b),
|
|
34816
34915
|
readFile: (p) => readFileSync8(p, "utf8"),
|
|
34817
34916
|
unlink: (p) => unlinkSync(p)
|
|
34818
34917
|
};
|
|
34819
34918
|
function runtimeConfigDir(home, identityId) {
|
|
34820
|
-
return
|
|
34919
|
+
return join16(home, ".securecoms", "runtime-config", identityId);
|
|
34821
34920
|
}
|
|
34822
34921
|
function assertManagedName(name) {
|
|
34823
|
-
if (!name || name.includes("/") || name.includes("\\") || name === "." || name === ".." || name !==
|
|
34922
|
+
if (!name || name.includes("/") || name.includes("\\") || name === "." || name === ".." || name !== basename5(name)) {
|
|
34824
34923
|
throw new Error(`refusing managed config file name ${JSON.stringify(name)}: not a plain filename`);
|
|
34825
34924
|
}
|
|
34826
34925
|
if (isLocalOnlyName(name)) {
|
|
@@ -34834,19 +34933,19 @@ function isLocalOnlyName(name) {
|
|
|
34834
34933
|
var MANIFEST_POLICY_FILE = "manifest-policy.json";
|
|
34835
34934
|
function removeManagedLlmSource(home, identityId, deps = REAL_FS) {
|
|
34836
34935
|
try {
|
|
34837
|
-
deps.unlink(
|
|
34936
|
+
deps.unlink(join16(runtimeConfigDir(home, identityId), "llm-source.json"));
|
|
34838
34937
|
} catch (e) {
|
|
34839
34938
|
if (e?.code !== "ENOENT") throw e;
|
|
34840
34939
|
}
|
|
34841
34940
|
}
|
|
34842
34941
|
function writeManifestPolicy(home, identityId, policy, deps = REAL_FS) {
|
|
34843
|
-
const parent3 =
|
|
34942
|
+
const parent3 = join16(home, ".securecoms", "runtime-config");
|
|
34844
34943
|
const dir = runtimeConfigDir(home, identityId);
|
|
34845
|
-
for (const d of [
|
|
34944
|
+
for (const d of [join16(home, ".securecoms"), parent3, dir]) {
|
|
34846
34945
|
deps.mkdir(d, 448);
|
|
34847
34946
|
deps.chmod(d, 448);
|
|
34848
34947
|
}
|
|
34849
|
-
atomicWrite(
|
|
34948
|
+
atomicWrite(join16(dir, MANIFEST_POLICY_FILE), JSON.stringify(policy) + "\n", deps);
|
|
34850
34949
|
}
|
|
34851
34950
|
function atomicWrite(path, body, deps) {
|
|
34852
34951
|
const tmp = `${path}.${process.pid}.${randomUUID()}.tmp`;
|
|
@@ -34865,13 +34964,13 @@ function atomicWrite(path, body, deps) {
|
|
|
34865
34964
|
function writeManagedFiles(home, identityId, files, deps = REAL_FS) {
|
|
34866
34965
|
const entries = Object.entries(files);
|
|
34867
34966
|
for (const [name] of entries) assertManagedName(name);
|
|
34868
|
-
const parent3 =
|
|
34967
|
+
const parent3 = join16(home, ".securecoms", "runtime-config");
|
|
34869
34968
|
const dir = runtimeConfigDir(home, identityId);
|
|
34870
|
-
for (const d of [
|
|
34969
|
+
for (const d of [join16(home, ".securecoms"), parent3, dir]) {
|
|
34871
34970
|
deps.mkdir(d, 448);
|
|
34872
34971
|
deps.chmod(d, 448);
|
|
34873
34972
|
}
|
|
34874
|
-
for (const [name, body] of entries) atomicWrite(
|
|
34973
|
+
for (const [name, body] of entries) atomicWrite(join16(dir, name), body, deps);
|
|
34875
34974
|
}
|
|
34876
34975
|
function checkConfiguredPaths(skillsJson, statFn = (p) => {
|
|
34877
34976
|
const s = statSync3(p);
|
|
@@ -34950,7 +35049,7 @@ function localLegacySources(doc) {
|
|
|
34950
35049
|
const channelId = source.channelId;
|
|
34951
35050
|
if (kind2 !== "global-memory" && kind2 !== "conversation-history" && kind2 !== "captured-memory" || typeof path !== "string" || !isAbsolute(path) || channelId !== void 0 && typeof channelId !== "string") continue;
|
|
34952
35051
|
try {
|
|
34953
|
-
const st =
|
|
35052
|
+
const st = lstatSync7(path);
|
|
34954
35053
|
if (!st.isFile() || st.isSymbolicLink()) continue;
|
|
34955
35054
|
if (st.size <= LEGACY_MEMORY_SOURCE_MAX_BYTES && st.size > contentBudget) continue;
|
|
34956
35055
|
const oversize = st.size > LEGACY_MEMORY_SOURCE_MAX_BYTES;
|
|
@@ -34978,7 +35077,7 @@ function localLegacySources(doc) {
|
|
|
34978
35077
|
return out;
|
|
34979
35078
|
}
|
|
34980
35079
|
function readLocalReport(home, identityId) {
|
|
34981
|
-
const p =
|
|
35080
|
+
const p = join16(runtimeConfigDir(home, identityId), LOCAL_REPORT_FILE);
|
|
34982
35081
|
if (!existsSync4(p)) return null;
|
|
34983
35082
|
let doc;
|
|
34984
35083
|
try {
|
|
@@ -35013,7 +35112,7 @@ function readLocalReport(home, identityId) {
|
|
|
35013
35112
|
}
|
|
35014
35113
|
function deleteLegacyMemorySources(home, identityId, ids) {
|
|
35015
35114
|
if (ids.length === 0) return 0;
|
|
35016
|
-
const p =
|
|
35115
|
+
const p = join16(runtimeConfigDir(home, identityId), LOCAL_REPORT_FILE);
|
|
35017
35116
|
if (!existsSync4(p)) return 0;
|
|
35018
35117
|
let doc;
|
|
35019
35118
|
try {
|
|
@@ -35056,7 +35155,7 @@ async function applyLegacyMemoryFactDecisions(home, identityId, rawDecisions, re
|
|
|
35056
35155
|
group.set(decision.fact_hash, decision);
|
|
35057
35156
|
bySource.set(decision.source_id, group);
|
|
35058
35157
|
}
|
|
35059
|
-
const reportPath =
|
|
35158
|
+
const reportPath = join16(runtimeConfigDir(home, identityId), LOCAL_REPORT_FILE);
|
|
35060
35159
|
if (!existsSync4(reportPath)) return { sourcesDeleted: 0, factsAssigned: 0 };
|
|
35061
35160
|
let doc;
|
|
35062
35161
|
try {
|
|
@@ -35094,7 +35193,7 @@ async function applyLegacyMemoryFactDecisions(home, identityId, rawDecisions, re
|
|
|
35094
35193
|
}
|
|
35095
35194
|
function pruneManagedMemory(home, identityId, hashes, deps = REAL_FS) {
|
|
35096
35195
|
const dir = runtimeConfigDir(home, identityId);
|
|
35097
|
-
const path =
|
|
35196
|
+
const path = join16(dir, MEMORY_FILE);
|
|
35098
35197
|
if (!existsSync4(path)) return 0;
|
|
35099
35198
|
const drop = new Set(hashes);
|
|
35100
35199
|
const before = deps.readFile(path).split("\n");
|
|
@@ -35127,9 +35226,9 @@ import { sha256 as sha25611 } from "@noble/hashes/sha256";
|
|
|
35127
35226
|
import { ed25519 as ed255195 } from "@noble/curves/ed25519";
|
|
35128
35227
|
|
|
35129
35228
|
// src/grants/pin.ts
|
|
35130
|
-
import { lstatSync as
|
|
35229
|
+
import { lstatSync as lstatSync8, readFileSync as readFileSync9 } from "node:fs";
|
|
35131
35230
|
import { ed25519 as ed255194 } from "@noble/curves/ed25519";
|
|
35132
|
-
import { dirname as
|
|
35231
|
+
import { dirname as dirname5, join as join17 } from "node:path";
|
|
35133
35232
|
var PIN_FILE_NAME = "owner-signing-key.json";
|
|
35134
35233
|
var UUID_LOWER = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
35135
35234
|
var PIN_KEYS = ["key_algo", "owner_identity_id", "public_key"];
|
|
@@ -35159,7 +35258,7 @@ function parsePinObject(v) {
|
|
|
35159
35258
|
pin: Object.freeze({ ownerIdentityId: o.owner_identity_id, keyAlgo: "ed25519", publicKey, publicKeyB64: o.public_key })
|
|
35160
35259
|
};
|
|
35161
35260
|
}
|
|
35162
|
-
var NODE_FS = { lstat: (p) =>
|
|
35261
|
+
var NODE_FS = { lstat: (p) => lstatSync8(p), readFile: (p) => readFileSync9(p, "utf8") };
|
|
35163
35262
|
function fromValue(v) {
|
|
35164
35263
|
const r = parsePinObject(v);
|
|
35165
35264
|
return r.ok ? { kind: "ok", pin: r.pin } : { kind: "bad", state: r.state };
|
|
@@ -35193,7 +35292,7 @@ function samePin(a, b) {
|
|
|
35193
35292
|
}
|
|
35194
35293
|
function loadOwnerGrantPin(opts) {
|
|
35195
35294
|
const fs = opts.fs ?? NODE_FS;
|
|
35196
|
-
const file2 = readPinFile(
|
|
35295
|
+
const file2 = readPinFile(join17(dirname5(opts.credentialPath), PIN_FILE_NAME), fs);
|
|
35197
35296
|
const field = "owner_signing_key" in opts.credentialJson && opts.credentialJson.owner_signing_key !== void 0 ? fromValue(opts.credentialJson.owner_signing_key) : { kind: "absent" };
|
|
35198
35297
|
if (file2.kind === "bad") return { state: file2.state, pin: null };
|
|
35199
35298
|
if (field.kind === "bad") return { state: field.state, pin: null };
|
|
@@ -36217,8 +36316,8 @@ function voiceWindowEligible(t) {
|
|
|
36217
36316
|
}
|
|
36218
36317
|
function waitMs(ms) {
|
|
36219
36318
|
if (ms <= 0) return Promise.resolve();
|
|
36220
|
-
return new Promise((
|
|
36221
|
-
const t = setTimeout(
|
|
36319
|
+
return new Promise((resolve2) => {
|
|
36320
|
+
const t = setTimeout(resolve2, ms);
|
|
36222
36321
|
t.unref?.();
|
|
36223
36322
|
});
|
|
36224
36323
|
}
|
|
@@ -36355,7 +36454,7 @@ var FileOwnerAuthorityStore = class {
|
|
|
36355
36454
|
}
|
|
36356
36455
|
async readAll() {
|
|
36357
36456
|
try {
|
|
36358
|
-
return JSON.parse(await
|
|
36457
|
+
return JSON.parse(await fsp2.readFile(this.path, "utf8"));
|
|
36359
36458
|
} catch (e) {
|
|
36360
36459
|
if (e.code === "ENOENT") return {};
|
|
36361
36460
|
throw e;
|
|
@@ -36368,8 +36467,8 @@ var FileOwnerAuthorityStore = class {
|
|
|
36368
36467
|
async save(enclaveId, pin) {
|
|
36369
36468
|
const all = await this.readAll();
|
|
36370
36469
|
all[enclaveId] = pin;
|
|
36371
|
-
await
|
|
36372
|
-
await
|
|
36470
|
+
await fsp2.mkdir(dirname6(this.path), { recursive: true });
|
|
36471
|
+
await fsp2.writeFile(this.path, JSON.stringify(all), "utf8");
|
|
36373
36472
|
}
|
|
36374
36473
|
};
|
|
36375
36474
|
var AgentPausedSendError = class extends Error {
|
|
@@ -36576,7 +36675,7 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
36576
36675
|
threshold: EMBEDDING_MANIFEST.similarityThreshold,
|
|
36577
36676
|
warm: windowsSemanticOn(this.platform)
|
|
36578
36677
|
};
|
|
36579
|
-
return deps.rankingTransport ? deps.rankingTransport(init) : workerTransport(init,
|
|
36678
|
+
return deps.rankingTransport ? deps.rankingTransport(init) : workerTransport(init, dirname6(fileURLToPath2(import.meta.url)));
|
|
36580
36679
|
}
|
|
36581
36680
|
});
|
|
36582
36681
|
this.embedder = deps.embedder ?? (deps.hostMachine === true && deps.home === void 0 ? new EmbedderClient({ identityId: cfg.identityId, home: homedir4(), source: cfg.modelSource, fetchImpl: this.fetchImpl, platform: this.platform }) : INERT_EMBEDDER);
|
|
@@ -36587,7 +36686,7 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
36587
36686
|
modelId: EMBEDDING_MANIFEST.modelId,
|
|
36588
36687
|
threshold: EMBEDDING_MANIFEST.similarityThreshold
|
|
36589
36688
|
});
|
|
36590
|
-
this.heartbeat = new CallHeartbeat(this.machinePaths ?
|
|
36689
|
+
this.heartbeat = new CallHeartbeat(this.machinePaths ? join18(this.home, ".securecoms", "run", "voice-call") : null, cfg.identityId, VOICE_LIVE_WINDOW_MS);
|
|
36591
36690
|
this.reembed = new ReembedQueue({
|
|
36592
36691
|
store: this.store,
|
|
36593
36692
|
embedder: this.embedder,
|
|
@@ -36646,15 +36745,15 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
36646
36745
|
this.bootDrainWaitMs = deps.bootDrainWaitMs ?? BOOT_DRAIN_WAIT_MS_DEFAULT;
|
|
36647
36746
|
this.searchCapabilityRefetchDebounceMs = deps.searchCapabilityRefetchDebounceMs ?? SEARCH_CAPABILITY_REFETCH_DEBOUNCE_MS;
|
|
36648
36747
|
this.searchCapabilityRefetchMaxWaitMs = deps.searchCapabilityRefetchMaxWaitMs ?? SEARCH_CAPABILITY_REFETCH_MAX_WAIT_MS;
|
|
36649
|
-
this.replySleep = deps.replySleep ?? ((ms) => new Promise((
|
|
36650
|
-
const t = setTimeout(
|
|
36748
|
+
this.replySleep = deps.replySleep ?? ((ms) => new Promise((resolve2) => {
|
|
36749
|
+
const t = setTimeout(resolve2, ms);
|
|
36651
36750
|
t.unref?.();
|
|
36652
36751
|
}));
|
|
36653
36752
|
this.actionRateFloor = new TokenBucketFloor({ capacity: 1, refillPerMinute: 30, now: this.actionClock });
|
|
36654
36753
|
this.globalActionRateFloor = new TokenBucketFloor({ capacity: 1, refillPerMinute: 30, now: this.actionClock });
|
|
36655
36754
|
const self = this;
|
|
36656
36755
|
this.downloadBlobImpl = deps.downloadBlob ?? async function(blobId) {
|
|
36657
|
-
const url = `${cfg.apiBase}/api/v1/attachments/${encodeURIComponent(blobId)}?caller_identity_id=${encodeURIComponent(cfg.identityId)}`;
|
|
36756
|
+
const url = `${cfg.apiBase}/api/v1/attachments/${encodeURIComponent(assertBlobId(blobId))}?caller_identity_id=${encodeURIComponent(cfg.identityId)}`;
|
|
36658
36757
|
const res = await fetchWithDeadline(self.fetchImpl, url, { headers: { authorization: `Bearer ${cfg.apiKey}` } }, {
|
|
36659
36758
|
op: "attachment_download",
|
|
36660
36759
|
timeoutMs: FETCH_DEADLINE_MS.blobBase,
|
|
@@ -36674,8 +36773,9 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
36674
36773
|
const j = await res.json();
|
|
36675
36774
|
return String(j.attachment_id);
|
|
36676
36775
|
};
|
|
36677
|
-
this.attachmentsDirImpl = deps.attachmentsDir ??
|
|
36678
|
-
this.
|
|
36776
|
+
this.attachmentsDirImpl = deps.attachmentsDir ?? join18(dirname6(cfg.storePath), "attachments");
|
|
36777
|
+
this.vaultOutboxDirImpl = deps.vaultOutboxDir !== void 0 ? deps.vaultOutboxDir : cfg.storePath === ":memory:" ? null : join18(dirname6(cfg.storePath), VAULT_OUTBOX_DIRNAME);
|
|
36778
|
+
this.vaultOwnerStoreImpl = deps.vaultOwnerStore ?? new FileOwnerAuthorityStore(join18(dirname6(cfg.storePath), "vault-owner-pins.json"));
|
|
36679
36779
|
this.action = {
|
|
36680
36780
|
begin: (channelId) => this.actionBegin(channelId),
|
|
36681
36781
|
start: (opts) => this.actionStart(opts),
|
|
@@ -37406,6 +37506,9 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
37406
37506
|
uploadBlobImpl;
|
|
37407
37507
|
/** Track 5: directory where received attachments are saved. */
|
|
37408
37508
|
attachmentsDirImpl;
|
|
37509
|
+
vaultOutboxDirImpl;
|
|
37510
|
+
/** Audit 2026-10-30 HIGH 2: the outbox pinned at start(); null = every upload refused. */
|
|
37511
|
+
outboxPin = null;
|
|
37409
37512
|
/** B7: persistence for the vault kekset's owner-pin TOFU state. */
|
|
37410
37513
|
vaultOwnerStoreImpl;
|
|
37411
37514
|
/** B7: last-seen kekset generation per enclave, enforced monotonic across
|
|
@@ -37682,7 +37785,7 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
37682
37785
|
}
|
|
37683
37786
|
/** No manifest in force: a manifest-policy.json left by an earlier one is replaced by an empty tool list. */
|
|
37684
37787
|
overwriteStalePolicy() {
|
|
37685
|
-
if (!existsSync5(
|
|
37788
|
+
if (!existsSync5(join18(runtimeConfigDir(this.home, this.cfg.identityId), "manifest-policy.json"))) return;
|
|
37686
37789
|
this.grantWriters.writeManifestPolicy(this.home, this.cfg.identityId, { v: 1, manifest_tools: [], secret_path_mode: "enforce" });
|
|
37687
37790
|
}
|
|
37688
37791
|
/** The report half of refetchRuntimeConfigOnce (split out for the plan 4 Task 11 bind_failed path). */
|
|
@@ -37849,6 +37952,13 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
37849
37952
|
}
|
|
37850
37953
|
async startBody() {
|
|
37851
37954
|
this.startedAt = Date.now();
|
|
37955
|
+
if (this.vaultOutboxDirImpl) {
|
|
37956
|
+
try {
|
|
37957
|
+
this.outboxPin = ensureOutbox(this.vaultOutboxDirImpl);
|
|
37958
|
+
} catch (e) {
|
|
37959
|
+
writeServiceLog2("warn", "vault_outbox.unavailable", {}, e);
|
|
37960
|
+
}
|
|
37961
|
+
}
|
|
37852
37962
|
await this.restoreRuntimeInbox();
|
|
37853
37963
|
await this.loadToolGrantState();
|
|
37854
37964
|
this.recomputeManifestPolicy(NO_FEATURES);
|
|
@@ -37874,8 +37984,8 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
37874
37984
|
const drain = this.ingestOnce().then(() => true, () => true);
|
|
37875
37985
|
const drainedInTime = await Promise.race([
|
|
37876
37986
|
drain,
|
|
37877
|
-
new Promise((
|
|
37878
|
-
const t = setTimeout(() =>
|
|
37987
|
+
new Promise((resolve2) => {
|
|
37988
|
+
const t = setTimeout(() => resolve2(false), this.bootDrainWaitMs);
|
|
37879
37989
|
t.unref?.();
|
|
37880
37990
|
void drain.then(() => clearTimeout(t));
|
|
37881
37991
|
})
|
|
@@ -37885,7 +37995,7 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
37885
37995
|
await this.bootReconcileKeyPackage();
|
|
37886
37996
|
} else {
|
|
37887
37997
|
writeServiceLog2("warn", "boot.drain_slow", { wait_ms: this.bootDrainWaitMs });
|
|
37888
|
-
const settled = new Promise((
|
|
37998
|
+
const settled = new Promise((resolve2) => this.ingestSettledWaiters.push(resolve2));
|
|
37889
37999
|
this.deferredBootPublish = settled.then(async () => {
|
|
37890
38000
|
this.bootDrainPending = false;
|
|
37891
38001
|
if (this.closingDown) return;
|
|
@@ -39392,7 +39502,8 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
39392
39502
|
uploadBlob: (ciphertext, channelId) => this.uploadBlobImpl(ciphertext, channelId),
|
|
39393
39503
|
encryptFile,
|
|
39394
39504
|
bytesToBase64: bytesToBase642,
|
|
39395
|
-
|
|
39505
|
+
// Security fix 2026-10-30: attachments upload only from the outbox.
|
|
39506
|
+
readFile: (p) => readOutboxFile(this.outboxPin, p).then((r) => r.bytes)
|
|
39396
39507
|
};
|
|
39397
39508
|
}
|
|
39398
39509
|
receiveDeps() {
|
|
@@ -39402,8 +39513,8 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
39402
39513
|
decryptFile,
|
|
39403
39514
|
computeFileDigest,
|
|
39404
39515
|
base64ToBytes: base64ToBytes2,
|
|
39405
|
-
mkdirp: (d) =>
|
|
39406
|
-
writeFile: (p, data) =>
|
|
39516
|
+
mkdirp: (d) => fsp2.mkdir(d, { recursive: true }).then(() => void 0),
|
|
39517
|
+
writeFile: (p, data) => fsp2.writeFile(p, data)
|
|
39407
39518
|
};
|
|
39408
39519
|
}
|
|
39409
39520
|
async sendAttachment(channelId, filePath2, caption) {
|
|
@@ -39411,8 +39522,11 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
39411
39522
|
const joined = await this.reconcileJoin(channelId);
|
|
39412
39523
|
if (!joined) throw new ChannelPendingError(channelId);
|
|
39413
39524
|
let body;
|
|
39525
|
+
let read;
|
|
39414
39526
|
try {
|
|
39415
|
-
|
|
39527
|
+
read = await readOutboxFile(this.outboxPin, filePath2);
|
|
39528
|
+
const bytes = read.bytes;
|
|
39529
|
+
body = await prepareAttachment(filePath2, caption, channelId, { ...this.sendDeps(), readFile: async () => bytes });
|
|
39416
39530
|
} catch (e) {
|
|
39417
39531
|
if (e.code === "ENOENT" || e.code === "EACCES" || e.code === "ENOTDIR" || e.code === "EISDIR") {
|
|
39418
39532
|
throw new InvalidPathError(filePath2, e);
|
|
@@ -39453,6 +39567,7 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
39453
39567
|
);
|
|
39454
39568
|
this.latency.record("send.total", performance.now() - sendStart);
|
|
39455
39569
|
this.agentHops.noteOwnSend(channelId);
|
|
39570
|
+
await this.consumeUploaded(read);
|
|
39456
39571
|
return { message_id: id, status: "sent" };
|
|
39457
39572
|
}
|
|
39458
39573
|
// ── B7: FileSafe vault commands (loopback boundary) ──────────────────────
|
|
@@ -39978,25 +40093,26 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
39978
40093
|
}
|
|
39979
40094
|
};
|
|
39980
40095
|
}
|
|
39981
|
-
/** Read `path`
|
|
40096
|
+
/** Read `path` from the vault outbox (security fix 2026-10-30; see
|
|
40097
|
+
* ./outbox.ts), encrypt + wrap its DEK under the vault's
|
|
39982
40098
|
* current KEK generation, and create+upload+commit it as a new vault
|
|
39983
40099
|
* file node named `name` (which may differ from `path`'s basename). */
|
|
39984
40100
|
async vaultWrite(enclaveId, vaultChannelId, path, name) {
|
|
39985
|
-
|
|
39986
|
-
let bytes;
|
|
40101
|
+
let read;
|
|
39987
40102
|
try {
|
|
39988
|
-
|
|
40103
|
+
read = await readOutboxFile(this.outboxPin, path);
|
|
39989
40104
|
} catch (e) {
|
|
39990
40105
|
const code = e.code;
|
|
39991
40106
|
if (code === "ENOENT" || code === "EACCES" || code === "ENOTDIR" || code === "EISDIR") throw new InvalidPathError(path, e);
|
|
39992
40107
|
throw e;
|
|
39993
40108
|
}
|
|
40109
|
+
const session = await this.getVaultSession(enclaveId, await this.resolveVaultChannelId(enclaveId, vaultChannelId));
|
|
39994
40110
|
const nodeId = crypto.randomUUID();
|
|
39995
|
-
|
|
40111
|
+
const written = await vaultWriteImpl({
|
|
39996
40112
|
enclaveId,
|
|
39997
40113
|
nodeId,
|
|
39998
40114
|
name,
|
|
39999
|
-
bytes,
|
|
40115
|
+
bytes: read.bytes,
|
|
40000
40116
|
deps: {
|
|
40001
40117
|
exporterKekForGeneration: session.kekForGeneration,
|
|
40002
40118
|
currentGeneration: session.currentGeneration,
|
|
@@ -40005,6 +40121,16 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
40005
40121
|
commitNode: (committedNodeId) => this.vaultCommitNode(enclaveId, committedNodeId)
|
|
40006
40122
|
}
|
|
40007
40123
|
});
|
|
40124
|
+
await this.consumeUploaded(read);
|
|
40125
|
+
return written;
|
|
40126
|
+
}
|
|
40127
|
+
/** Audit 2026-10-30 MED 5: an uploaded file leaves the outbox (no plaintext lingers). Content-free log. */
|
|
40128
|
+
async consumeUploaded(read) {
|
|
40129
|
+
if (!this.outboxPin || !await consumeOutboxFile(this.outboxPin, read)) writeServiceLog2("warn", "vault_outbox.consume_failed");
|
|
40130
|
+
}
|
|
40131
|
+
/** Audit 2026-10-30 MED 3: the pinned outbox path, served only on the authenticated GET /v1/vault-outbox. */
|
|
40132
|
+
vaultOutboxPath() {
|
|
40133
|
+
return this.outboxPin?.dir ?? null;
|
|
40008
40134
|
}
|
|
40009
40135
|
/** Download + verify + decrypt a vault file node. Returns the plaintext
|
|
40010
40136
|
* base64-encoded (the loopback boundary is JSON-only, mirroring how
|
|
@@ -42437,13 +42563,13 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
42437
42563
|
throw new Error("summarize_no_runtime");
|
|
42438
42564
|
}
|
|
42439
42565
|
const messages = [{ role: "user", content: prompt }];
|
|
42440
|
-
return new Promise((
|
|
42566
|
+
return new Promise((resolve2, reject) => {
|
|
42441
42567
|
const onAbort = () => reject(new Error("aborted"));
|
|
42442
42568
|
signal.addEventListener("abort", onAbort);
|
|
42443
42569
|
this.fastLlm.complete(messages).then(
|
|
42444
42570
|
(text) => {
|
|
42445
42571
|
signal.removeEventListener("abort", onAbort);
|
|
42446
|
-
|
|
42572
|
+
resolve2(text);
|
|
42447
42573
|
},
|
|
42448
42574
|
(err) => {
|
|
42449
42575
|
signal.removeEventListener("abort", onAbort);
|
|
@@ -43391,7 +43517,7 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
43391
43517
|
return got;
|
|
43392
43518
|
}
|
|
43393
43519
|
const cap = Math.min(waitSeconds, 50) * 1e3;
|
|
43394
|
-
await new Promise((
|
|
43520
|
+
await new Promise((resolve2) => {
|
|
43395
43521
|
let fired = false;
|
|
43396
43522
|
let timer;
|
|
43397
43523
|
const wake = () => {
|
|
@@ -43400,7 +43526,7 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
43400
43526
|
clearTimeout(timer);
|
|
43401
43527
|
const i = this.waiters.indexOf(wake);
|
|
43402
43528
|
if (i >= 0) this.waiters.splice(i, 1);
|
|
43403
|
-
|
|
43529
|
+
resolve2();
|
|
43404
43530
|
};
|
|
43405
43531
|
timer = setTimeout(wake, cap);
|
|
43406
43532
|
this.waiters.push(wake);
|
|
@@ -43443,13 +43569,13 @@ var BridgeAgent = class _BridgeAgent {
|
|
|
43443
43569
|
const bound = b !== null && b.state === "bound" && b.counter === this.toolGrantCounter;
|
|
43444
43570
|
const switchOn = audience === "owner_dm" ? this.ownerDmManifestGrants : audience === "team_room" ? this.roomManifestGrants : false;
|
|
43445
43571
|
const signedNow = new Set(audience && manifest ? manifest.grants[audience] ?? [] : []);
|
|
43446
|
-
const
|
|
43572
|
+
const constants5 = new Set(audience === "owner_dm" ? OWNER_DM_DEFAULT_READ_GRANTS.map((g) => g.tool) : audience === "team_room" ? ROOM_DEFAULT_READ_GRANTS.map((g) => g.tool) : []);
|
|
43447
43573
|
let changed = false;
|
|
43448
43574
|
const out = a.tool_grants.flatMap((g) => {
|
|
43449
43575
|
if (!(g.mode === "read" && g.source === "manifest")) return [g];
|
|
43450
43576
|
if (switchOn && bound && signedNow.has(g.tool)) return [g];
|
|
43451
43577
|
changed = true;
|
|
43452
|
-
return
|
|
43578
|
+
return constants5.has(g.tool) && signedNow.has(g.tool) ? [Object.freeze({ tool: g.tool, mode: "read" })] : [];
|
|
43453
43579
|
});
|
|
43454
43580
|
if (!changed) return m;
|
|
43455
43581
|
return { ...m, authorization: Object.freeze({ ...a, tool_grants: Object.freeze(out) }) };
|
|
@@ -44266,7 +44392,7 @@ ${channelId}`;
|
|
|
44266
44392
|
}
|
|
44267
44393
|
const withheld = new Set(Object.keys(TOOL_FEATURE).filter((t) => !toolAllowedByFeatures(t, features)));
|
|
44268
44394
|
if (withheld.size === 0) return;
|
|
44269
|
-
const path =
|
|
44395
|
+
const path = join18(runtimeConfigDir(this.home, this.cfg.identityId), MANIFEST_POLICY_FILE);
|
|
44270
44396
|
if (!existsSync5(path)) return;
|
|
44271
44397
|
let doc;
|
|
44272
44398
|
try {
|
|
@@ -44491,8 +44617,8 @@ ${channelId}`;
|
|
|
44491
44617
|
let timer;
|
|
44492
44618
|
await Promise.race([
|
|
44493
44619
|
ingest.released,
|
|
44494
|
-
new Promise((
|
|
44495
|
-
timer = setTimeout(
|
|
44620
|
+
new Promise((resolve2) => {
|
|
44621
|
+
timer = setTimeout(resolve2, _BridgeAgent.GRACEFUL_DRAIN_MS);
|
|
44496
44622
|
})
|
|
44497
44623
|
]);
|
|
44498
44624
|
if (timer) clearTimeout(timer);
|
|
@@ -44502,8 +44628,8 @@ ${channelId}`;
|
|
|
44502
44628
|
let timer;
|
|
44503
44629
|
await Promise.race([
|
|
44504
44630
|
starting,
|
|
44505
|
-
new Promise((
|
|
44506
|
-
timer = setTimeout(
|
|
44631
|
+
new Promise((resolve2) => {
|
|
44632
|
+
timer = setTimeout(resolve2, _BridgeAgent.GRACEFUL_DRAIN_MS);
|
|
44507
44633
|
})
|
|
44508
44634
|
]);
|
|
44509
44635
|
if (timer) clearTimeout(timer);
|
|
@@ -44512,8 +44638,8 @@ ${channelId}`;
|
|
|
44512
44638
|
let timer;
|
|
44513
44639
|
await Promise.race([
|
|
44514
44640
|
this.membershipSweepWork,
|
|
44515
|
-
new Promise((
|
|
44516
|
-
timer = setTimeout(
|
|
44641
|
+
new Promise((resolve2) => {
|
|
44642
|
+
timer = setTimeout(resolve2, _BridgeAgent.GRACEFUL_DRAIN_MS);
|
|
44517
44643
|
})
|
|
44518
44644
|
]);
|
|
44519
44645
|
if (timer) clearTimeout(timer);
|
|
@@ -44523,8 +44649,8 @@ ${channelId}`;
|
|
|
44523
44649
|
let timer;
|
|
44524
44650
|
await Promise.race([
|
|
44525
44651
|
this.recallPruneWork,
|
|
44526
|
-
new Promise((
|
|
44527
|
-
timer = setTimeout(
|
|
44652
|
+
new Promise((resolve2) => {
|
|
44653
|
+
timer = setTimeout(resolve2, _BridgeAgent.GRACEFUL_DRAIN_MS);
|
|
44528
44654
|
})
|
|
44529
44655
|
]);
|
|
44530
44656
|
if (timer) clearTimeout(timer);
|
|
@@ -44534,8 +44660,8 @@ ${channelId}`;
|
|
|
44534
44660
|
let timer;
|
|
44535
44661
|
await Promise.race([
|
|
44536
44662
|
this.recallMaintenanceWork,
|
|
44537
|
-
new Promise((
|
|
44538
|
-
timer = setTimeout(
|
|
44663
|
+
new Promise((resolve2) => {
|
|
44664
|
+
timer = setTimeout(resolve2, _BridgeAgent.GRACEFUL_DRAIN_MS);
|
|
44539
44665
|
})
|
|
44540
44666
|
]);
|
|
44541
44667
|
if (timer) clearTimeout(timer);
|
|
@@ -44547,8 +44673,8 @@ ${channelId}`;
|
|
|
44547
44673
|
let timer;
|
|
44548
44674
|
await Promise.race([
|
|
44549
44675
|
Promise.allSettled([...this.recallTapWork]),
|
|
44550
|
-
new Promise((
|
|
44551
|
-
timer = setTimeout(
|
|
44676
|
+
new Promise((resolve2) => {
|
|
44677
|
+
timer = setTimeout(resolve2, _BridgeAgent.GRACEFUL_DRAIN_MS);
|
|
44552
44678
|
})
|
|
44553
44679
|
]);
|
|
44554
44680
|
if (timer) clearTimeout(timer);
|
|
@@ -44557,8 +44683,8 @@ ${channelId}`;
|
|
|
44557
44683
|
let timer;
|
|
44558
44684
|
await Promise.race([
|
|
44559
44685
|
Promise.allSettled([...this.unifiedWork]),
|
|
44560
|
-
new Promise((
|
|
44561
|
-
timer = setTimeout(
|
|
44686
|
+
new Promise((resolve2) => {
|
|
44687
|
+
timer = setTimeout(resolve2, _BridgeAgent.GRACEFUL_DRAIN_MS);
|
|
44562
44688
|
})
|
|
44563
44689
|
]);
|
|
44564
44690
|
if (timer) clearTimeout(timer);
|
|
@@ -44567,8 +44693,8 @@ ${channelId}`;
|
|
|
44567
44693
|
let timer;
|
|
44568
44694
|
await Promise.race([
|
|
44569
44695
|
this.recallPrewarmWork,
|
|
44570
|
-
new Promise((
|
|
44571
|
-
timer = setTimeout(
|
|
44696
|
+
new Promise((resolve2) => {
|
|
44697
|
+
timer = setTimeout(resolve2, _BridgeAgent.GRACEFUL_DRAIN_MS);
|
|
44572
44698
|
})
|
|
44573
44699
|
]);
|
|
44574
44700
|
if (timer) clearTimeout(timer);
|
|
@@ -44578,8 +44704,8 @@ ${channelId}`;
|
|
|
44578
44704
|
let timer;
|
|
44579
44705
|
await Promise.race([
|
|
44580
44706
|
Promise.allSettled([...this.replyWork]),
|
|
44581
|
-
new Promise((
|
|
44582
|
-
timer = setTimeout(
|
|
44707
|
+
new Promise((resolve2) => {
|
|
44708
|
+
timer = setTimeout(resolve2, _BridgeAgent.GRACEFUL_DRAIN_MS);
|
|
44583
44709
|
})
|
|
44584
44710
|
]);
|
|
44585
44711
|
if (timer) clearTimeout(timer);
|
|
@@ -44592,7 +44718,7 @@ ${channelId}`;
|
|
|
44592
44718
|
|
|
44593
44719
|
// src/config.ts
|
|
44594
44720
|
import { readFileSync as readFileSync11, statSync as statSync5 } from "node:fs";
|
|
44595
|
-
import { dirname as
|
|
44721
|
+
import { dirname as dirname7, join as join19 } from "node:path";
|
|
44596
44722
|
var REQUIRED = ["api_key", "identity_id", "device_id", "signing_private_key", "enclave_id", "api_base"];
|
|
44597
44723
|
var CONFIG_ERROR_MESSAGE = {
|
|
44598
44724
|
credential_not_found: "credential file not found",
|
|
@@ -44630,7 +44756,7 @@ function loadConfig(opts) {
|
|
|
44630
44756
|
throw new ConfigError("credential_not_json");
|
|
44631
44757
|
}
|
|
44632
44758
|
for (const k of REQUIRED) if (typeof json2[k] !== "string" || !json2[k]) throw new ConfigError("credential_missing_field", k);
|
|
44633
|
-
const storePath = opts.storePath ??
|
|
44759
|
+
const storePath = opts.storePath ?? join19(dirname7(opts.credentialPath), "bridge-state.db");
|
|
44634
44760
|
const ownerGrantPin = loadOwnerGrantPin({ credentialPath: opts.credentialPath, credentialJson: json2 });
|
|
44635
44761
|
writeServiceLog2(ownerGrantPin.state === "ok" || ownerGrantPin.state === "no_pin" ? "info" : "warn", "authz.pin", {
|
|
44636
44762
|
state: ServiceLogEnum.of(ownerGrantPin.state, ["ok", "no_pin", "pin_conflict", "malformed", "unsupported_algo", "symlink_refused", "unreadable"])
|
|
@@ -44818,6 +44944,10 @@ var BRIDGE_ERRORS = {
|
|
|
44818
44944
|
// Weather/currency Task 17 (OQ-P1): a send frame's credit is not the closed value, or rides an a2a frame. TERMINAL:
|
|
44819
44945
|
// the inbound is retired, so the model (and the weather call) never runs again for it.
|
|
44820
44946
|
reply_credit_unknown: { http: 400, message: "reply credit not recognised; not sent" },
|
|
44947
|
+
// Security fix 2026-10-30: an upload route was given a path that is not a
|
|
44948
|
+
// regular file directly inside the bridge's vault outbox (`vault_outbox` on
|
|
44949
|
+
// /healthz). Fixed and content-free: the path is never echoed or logged.
|
|
44950
|
+
path_outside_outbox: { http: 400, message: "uploads must come from the bridge vault outbox; copy the file there first" },
|
|
44821
44951
|
internal: { http: 500, message: "internal error" }
|
|
44822
44952
|
};
|
|
44823
44953
|
function errorBody(code, detail) {
|
|
@@ -44857,10 +44987,10 @@ function withManifestCapability(m, manifestConsumer) {
|
|
|
44857
44987
|
if (manifestConsumer) return m;
|
|
44858
44988
|
const a = m.authorization;
|
|
44859
44989
|
if (!a || !a.tool_grants.some(isManifestGrant)) return m;
|
|
44860
|
-
const
|
|
44990
|
+
const constants5 = new Set(a.audience === "owner_dm" || a.audience === "team_room" ? CONSTANT_TOOL_NAMES[a.audience] : []);
|
|
44861
44991
|
const narrowed = a.tool_grants.flatMap((g) => {
|
|
44862
44992
|
if (!isManifestGrant(g)) return [g];
|
|
44863
|
-
return
|
|
44993
|
+
return constants5.has(g.tool) ? [Object.freeze({ tool: g.tool, mode: "read" })] : [];
|
|
44864
44994
|
});
|
|
44865
44995
|
return { ...m, authorization: Object.freeze({ ...a, tool_grants: Object.freeze(narrowed) }) };
|
|
44866
44996
|
}
|
|
@@ -45018,7 +45148,7 @@ function jsonError(res, code, detail) {
|
|
|
45018
45148
|
json(res, httpStatus(code), errorBody(code, detail));
|
|
45019
45149
|
}
|
|
45020
45150
|
function readBody(req, cap) {
|
|
45021
|
-
return new Promise((
|
|
45151
|
+
return new Promise((resolve2, reject) => {
|
|
45022
45152
|
let size = 0;
|
|
45023
45153
|
let done = false;
|
|
45024
45154
|
const chunks = [];
|
|
@@ -45038,7 +45168,7 @@ function readBody(req, cap) {
|
|
|
45038
45168
|
req.on("end", () => {
|
|
45039
45169
|
if (!done) {
|
|
45040
45170
|
done = true;
|
|
45041
|
-
|
|
45171
|
+
resolve2(Buffer.concat(chunks).toString("utf8"));
|
|
45042
45172
|
}
|
|
45043
45173
|
});
|
|
45044
45174
|
req.on("error", (e) => {
|
|
@@ -45116,6 +45246,9 @@ function createHttpServer(agent, opts) {
|
|
|
45116
45246
|
}
|
|
45117
45247
|
return json(res, 200, r);
|
|
45118
45248
|
}
|
|
45249
|
+
if (method === "GET" && path === "/v1/vault-outbox") {
|
|
45250
|
+
return json(res, 200, { path: agent.vaultOutboxPath() });
|
|
45251
|
+
}
|
|
45119
45252
|
if (method === "POST" && path === "/v1/send-attachment") {
|
|
45120
45253
|
const parsed = sendAttachmentSchema.safeParse(JSON.parse(await readBody(req, OTHER_CAP)));
|
|
45121
45254
|
if (!parsed.success) return jsonError(res, "invalid_request", parsed.error.issues);
|
|
@@ -45227,6 +45360,10 @@ function createHttpServer(agent, opts) {
|
|
|
45227
45360
|
if (e instanceof SendForbiddenError) return jsonError(res, "send_forbidden");
|
|
45228
45361
|
if (e instanceof GroupSupersededSendError) return jsonError(res, "group_superseded");
|
|
45229
45362
|
if (e instanceof IdempotencyConflictError) return jsonError(res, "invalid_request", e.message);
|
|
45363
|
+
if (e instanceof PathOutsideOutboxError) {
|
|
45364
|
+
writeServiceLog2("warn", "vault_outbox.refused");
|
|
45365
|
+
return jsonError(res, "path_outside_outbox");
|
|
45366
|
+
}
|
|
45230
45367
|
if (e instanceof InvalidPathError) return jsonError(res, "invalid_request", e.message);
|
|
45231
45368
|
if (e instanceof VaultPinMismatchError) return jsonError(res, "vault_ref_changed", { pin: e.pin });
|
|
45232
45369
|
if (e instanceof VaultIntegrityError) return jsonError(res, "vault_integrity_failed", e.message);
|