@atbash/sdk 0.10.7-dev.0 → 0.10.10-dev.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/dist/browser.d.mts +128 -19
- package/dist/browser.mjs +204 -70
- package/dist/browser.mjs.map +1 -1
- package/dist/index.d.mts +128 -19
- package/dist/index.d.ts +128 -19
- package/dist/index.js +320 -108
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +318 -108
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -2864,6 +2864,8 @@ __export(src_ts_exports, {
|
|
|
2864
2864
|
DEFAULT_MEMORY_READ_TOOL_NAMES: () => DEFAULT_MEMORY_READ_TOOL_NAMES,
|
|
2865
2865
|
DEFAULT_MEMORY_WRITE_TOOL_NAMES: () => DEFAULT_MEMORY_WRITE_TOOL_NAMES,
|
|
2866
2866
|
EciesDomain: () => EciesDomain,
|
|
2867
|
+
HttpClient: () => HttpClient,
|
|
2868
|
+
HttpTransportError: () => HttpTransportError,
|
|
2867
2869
|
KEY_FILENAMES: () => KEY_FILENAMES,
|
|
2868
2870
|
MemoryGuardManager: () => MemoryGuardManager,
|
|
2869
2871
|
MemoryIntegrityError: () => MemoryIntegrityError,
|
|
@@ -3109,8 +3111,8 @@ var HttpClient = class {
|
|
|
3109
3111
|
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
3110
3112
|
this.timeoutMs = timeoutMs;
|
|
3111
3113
|
}
|
|
3112
|
-
buildUrl(
|
|
3113
|
-
const url = new URL(this.baseUrl +
|
|
3114
|
+
buildUrl(path7, query) {
|
|
3115
|
+
const url = new URL(this.baseUrl + path7);
|
|
3114
3116
|
if (query) {
|
|
3115
3117
|
for (const [k, v] of Object.entries(query)) {
|
|
3116
3118
|
if (v !== void 0 && v !== null && v !== "") {
|
|
@@ -3120,23 +3122,83 @@ var HttpClient = class {
|
|
|
3120
3122
|
}
|
|
3121
3123
|
return url.toString();
|
|
3122
3124
|
}
|
|
3123
|
-
async get(
|
|
3124
|
-
return this.fetch(this.buildUrl(
|
|
3125
|
+
async get(path7, query, headers) {
|
|
3126
|
+
return this.fetch(this.buildUrl(path7, query), {
|
|
3125
3127
|
method: "GET",
|
|
3126
3128
|
...headers && { headers }
|
|
3127
3129
|
});
|
|
3128
3130
|
}
|
|
3129
|
-
async post(
|
|
3130
|
-
return this.fetch(this.buildUrl(
|
|
3131
|
+
async post(path7, body, headers) {
|
|
3132
|
+
return this.fetch(this.buildUrl(path7), {
|
|
3131
3133
|
method: "POST",
|
|
3132
3134
|
headers: { "Content-Type": "application/json", ...headers },
|
|
3133
3135
|
body: JSON.stringify(body)
|
|
3134
3136
|
});
|
|
3135
3137
|
}
|
|
3136
3138
|
async fetch(url, init4) {
|
|
3137
|
-
|
|
3139
|
+
try {
|
|
3140
|
+
return await fetch(url, {
|
|
3141
|
+
...init4,
|
|
3142
|
+
signal: AbortSignal.timeout(this.timeoutMs)
|
|
3143
|
+
});
|
|
3144
|
+
} catch (err) {
|
|
3145
|
+
throw classifyTransportError(err, url, init4.method ?? "GET", this.timeoutMs);
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
};
|
|
3149
|
+
var HttpTransportError = class extends Error {
|
|
3150
|
+
kind;
|
|
3151
|
+
constructor(kind, message, options) {
|
|
3152
|
+
super(message, options);
|
|
3153
|
+
this.name = "HttpTransportError";
|
|
3154
|
+
this.kind = kind;
|
|
3138
3155
|
}
|
|
3139
3156
|
};
|
|
3157
|
+
function classifyTransportError(err, url, method, timeoutMs) {
|
|
3158
|
+
const name2 = err instanceof Error ? err.name : "";
|
|
3159
|
+
const cause = err instanceof Error ? err.cause : void 0;
|
|
3160
|
+
const code2 = cause && typeof cause === "object" && "code" in cause ? String(cause.code) : "";
|
|
3161
|
+
if (name2 === "TimeoutError") {
|
|
3162
|
+
return new HttpTransportError(
|
|
3163
|
+
"timeout",
|
|
3164
|
+
`${method} ${url} did not respond within ${timeoutMs} ms \u2014 the judge may be slow to boot or the LLM is under load; retry in a moment`,
|
|
3165
|
+
{ cause: err }
|
|
3166
|
+
);
|
|
3167
|
+
}
|
|
3168
|
+
if (name2 === "AbortError") {
|
|
3169
|
+
return new HttpTransportError(
|
|
3170
|
+
"aborted",
|
|
3171
|
+
`${method} ${url} was cancelled by the caller`,
|
|
3172
|
+
{ cause: err }
|
|
3173
|
+
);
|
|
3174
|
+
}
|
|
3175
|
+
if (code2 === "ENOTFOUND" || code2 === "EAI_AGAIN") {
|
|
3176
|
+
return new HttpTransportError(
|
|
3177
|
+
"dns",
|
|
3178
|
+
`could not resolve the judge hostname (${url}) \u2014 check the endpoint and DNS`,
|
|
3179
|
+
{ cause: err }
|
|
3180
|
+
);
|
|
3181
|
+
}
|
|
3182
|
+
if (code2 === "ECONNREFUSED") {
|
|
3183
|
+
return new HttpTransportError(
|
|
3184
|
+
"connect_refused",
|
|
3185
|
+
`judge refused the connection (${url}) \u2014 the service may be down or restarting`,
|
|
3186
|
+
{ cause: err }
|
|
3187
|
+
);
|
|
3188
|
+
}
|
|
3189
|
+
if (code2 === "ECONNRESET" || code2 === "EPIPE") {
|
|
3190
|
+
return new HttpTransportError(
|
|
3191
|
+
"connection_reset",
|
|
3192
|
+
`judge dropped the connection mid-request (${url}) \u2014 retry once`,
|
|
3193
|
+
{ cause: err }
|
|
3194
|
+
);
|
|
3195
|
+
}
|
|
3196
|
+
return new HttpTransportError(
|
|
3197
|
+
"unknown",
|
|
3198
|
+
`${method} ${url} failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
3199
|
+
{ cause: err }
|
|
3200
|
+
);
|
|
3201
|
+
}
|
|
3140
3202
|
|
|
3141
3203
|
// src-ts/keyLoader.ts
|
|
3142
3204
|
var import_node_fs = require("fs");
|
|
@@ -3400,6 +3462,16 @@ var Atbash = class _Atbash {
|
|
|
3400
3462
|
* calls don't re-hit the dashboard. Cleared by `clearChainCache()`.
|
|
3401
3463
|
*/
|
|
3402
3464
|
_chainCache = /* @__PURE__ */ new Map();
|
|
3465
|
+
/**
|
|
3466
|
+
* Short-TTL cache for `/api/ai/exists`. The `registered` field is
|
|
3467
|
+
* monotonic (once true, stays true), so most calls in a burst re-fetch
|
|
3468
|
+
* data that hasn't changed. The `org_encryption_pubkey` field CAN change
|
|
3469
|
+
* — an org toggling encryption mid-session — so the TTL is deliberately
|
|
3470
|
+
* short (see `AGENT_EXISTS_TTL_MS`). Keyed by (pubkey, network) so
|
|
3471
|
+
* cross-agent / cross-network calls don't collide.
|
|
3472
|
+
*/
|
|
3473
|
+
_agentExistsCache = null;
|
|
3474
|
+
static AGENT_EXISTS_TTL_MS = 5e3;
|
|
3403
3475
|
/**
|
|
3404
3476
|
* Cached bearer token for risk-engine / insurance read calls. Built
|
|
3405
3477
|
* lazily as a signed `log_tool_call` tx and refreshed every 4 min so
|
|
@@ -3419,7 +3491,7 @@ var Atbash = class _Atbash {
|
|
|
3419
3491
|
this.failClosed = options.failClosed !== false;
|
|
3420
3492
|
this.debug = options.debug === true;
|
|
3421
3493
|
this.logger = options.logger ?? {};
|
|
3422
|
-
this.http = new HttpClient(this.endpoint, options.timeoutMs ??
|
|
3494
|
+
this.http = new HttpClient(this.endpoint, options.timeoutMs ?? 6e4);
|
|
3423
3495
|
this.logEnvironmentOnce();
|
|
3424
3496
|
if (this.endpoint !== DEFAULT_ENDPOINT) {
|
|
3425
3497
|
this.logger.warn?.("[atbash] running on non-default judge endpoint", {
|
|
@@ -3499,9 +3571,18 @@ var Atbash = class _Atbash {
|
|
|
3499
3571
|
*/
|
|
3500
3572
|
async checkAgentExists(pubkey, opts) {
|
|
3501
3573
|
const pk = pubkey ?? this.auth.pubkey;
|
|
3574
|
+
const network = opts?.network;
|
|
3575
|
+
const now = Date.now();
|
|
3576
|
+
const cached = this._agentExistsCache;
|
|
3577
|
+
if (cached && cached.pubkey === pk && cached.network === network && cached.expiresAt > now) {
|
|
3578
|
+
if (pk === this.auth.pubkey) {
|
|
3579
|
+
this._orgKeyFromChain = cached.orgKey;
|
|
3580
|
+
}
|
|
3581
|
+
return cached.registered;
|
|
3582
|
+
}
|
|
3502
3583
|
return this.track("checkAgentExists", pk, async () => {
|
|
3503
3584
|
const query = { pubkey: pk };
|
|
3504
|
-
if (
|
|
3585
|
+
if (network) query.network = network;
|
|
3505
3586
|
const resp = await this.http.get(
|
|
3506
3587
|
"/api/ai/exists",
|
|
3507
3588
|
query,
|
|
@@ -3509,11 +3590,21 @@ var Atbash = class _Atbash {
|
|
|
3509
3590
|
);
|
|
3510
3591
|
await this.raiseIfError(resp);
|
|
3511
3592
|
const data = await this.json(resp);
|
|
3593
|
+
const registered = Boolean(data?.registered);
|
|
3594
|
+
const orgKey = typeof data?.org_encryption_pubkey === "string" && data.org_encryption_pubkey ? data.org_encryption_pubkey : null;
|
|
3595
|
+
if (registered) {
|
|
3596
|
+
this._agentExistsCache = {
|
|
3597
|
+
pubkey: pk,
|
|
3598
|
+
network,
|
|
3599
|
+
expiresAt: Date.now() + _Atbash.AGENT_EXISTS_TTL_MS,
|
|
3600
|
+
registered,
|
|
3601
|
+
orgKey
|
|
3602
|
+
};
|
|
3603
|
+
}
|
|
3512
3604
|
if (pk === this.auth.pubkey) {
|
|
3513
|
-
|
|
3514
|
-
this._orgKeyFromChain = typeof key3 === "string" && key3 ? key3 : null;
|
|
3605
|
+
this._orgKeyFromChain = orgKey;
|
|
3515
3606
|
}
|
|
3516
|
-
return
|
|
3607
|
+
return registered;
|
|
3517
3608
|
});
|
|
3518
3609
|
}
|
|
3519
3610
|
/* ── log_tool_call (sign-only) ─────────────────────────────────────────── */
|
|
@@ -3594,12 +3685,19 @@ var Atbash = class _Atbash {
|
|
|
3594
3685
|
}
|
|
3595
3686
|
let chainOpts = options.chainOpts;
|
|
3596
3687
|
if (options.orgName) {
|
|
3597
|
-
const
|
|
3598
|
-
if (
|
|
3599
|
-
chainOpts = { network:
|
|
3600
|
-
} else
|
|
3601
|
-
const
|
|
3602
|
-
|
|
3688
|
+
const cached = this._chainCache.get(options.orgName);
|
|
3689
|
+
if (cached) {
|
|
3690
|
+
chainOpts = { network: cached.network };
|
|
3691
|
+
} else {
|
|
3692
|
+
const mapNetwork = await this.getActiveNetworkForOrg(options.orgName);
|
|
3693
|
+
if (mapNetwork) {
|
|
3694
|
+
const chain = mapNetwork === "private" ? PRIVATE_CHAIN : PUBLIC_CHAIN;
|
|
3695
|
+
this._chainCache.set(options.orgName, chain);
|
|
3696
|
+
chainOpts = { network: mapNetwork };
|
|
3697
|
+
} else if (!chainOpts?.blockchainRid) {
|
|
3698
|
+
const resolved = await this.resolveChainFromMap(options.orgName, null);
|
|
3699
|
+
chainOpts = { ...chainOpts, network: resolved.network };
|
|
3700
|
+
}
|
|
3603
3701
|
}
|
|
3604
3702
|
}
|
|
3605
3703
|
const brid = this.bridFromChainOpts(chainOpts);
|
|
@@ -4048,6 +4146,10 @@ var Atbash = class _Atbash {
|
|
|
4048
4146
|
clearChainCache() {
|
|
4049
4147
|
this._chainCache.clear();
|
|
4050
4148
|
}
|
|
4149
|
+
/** Drop the short-TTL `/api/ai/exists` cache. Useful in tests. */
|
|
4150
|
+
clearAgentExistsCache() {
|
|
4151
|
+
this._agentExistsCache = null;
|
|
4152
|
+
}
|
|
4051
4153
|
/* ── internals ─────────────────────────────────────────────────────────── */
|
|
4052
4154
|
/**
|
|
4053
4155
|
* Wrap an SDK method body in telemetry — records the call at start
|
|
@@ -4150,8 +4252,27 @@ var Atbash = class _Atbash {
|
|
|
4150
4252
|
this.endpoint
|
|
4151
4253
|
);
|
|
4152
4254
|
}
|
|
4153
|
-
/**
|
|
4255
|
+
/**
|
|
4256
|
+
* Wrap a transport failure (fetch threw, no response) as an AtbashAPIError.
|
|
4257
|
+
*
|
|
4258
|
+
* `HttpTransportError.kind` names the cause; the message is already
|
|
4259
|
+
* human-readable. `debug` echoes the original exception so operators can
|
|
4260
|
+
* cross-reference with node / undici logs when a class doesn't match.
|
|
4261
|
+
*/
|
|
4154
4262
|
transportError(err) {
|
|
4263
|
+
if (err instanceof HttpTransportError) {
|
|
4264
|
+
if (this.debug) {
|
|
4265
|
+
this.logger.warn?.(
|
|
4266
|
+
`[atbash] transport failed \u2014 kind=${err.kind}`,
|
|
4267
|
+
{
|
|
4268
|
+
kind: err.kind,
|
|
4269
|
+
cause: err.cause instanceof Error ? err.cause.message : String(err.cause ?? ""),
|
|
4270
|
+
endpoint: this.endpoint
|
|
4271
|
+
}
|
|
4272
|
+
);
|
|
4273
|
+
}
|
|
4274
|
+
return new AtbashAPIError(0, err.message, "", this.endpoint);
|
|
4275
|
+
}
|
|
4155
4276
|
return new AtbashAPIError(0, errorMessage(err), "", this.endpoint);
|
|
4156
4277
|
}
|
|
4157
4278
|
async json(resp) {
|
|
@@ -4378,24 +4499,29 @@ async function scanMemory(entry, auth, opts) {
|
|
|
4378
4499
|
toolArgsJson: opts?.toolArgsJson ?? JSON.stringify({ key: entry.key, source: entry.source }),
|
|
4379
4500
|
mode: "memory-scan"
|
|
4380
4501
|
});
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
return {
|
|
4386
|
-
safe: false,
|
|
4387
|
-
verdict: "red",
|
|
4388
|
-
reason: unknownAction ? `judge returned unrecognised action_type "${result.actionType}"` : "judge returned no verdict",
|
|
4389
|
-
confidence: result.confidence,
|
|
4390
|
-
score: native.defaultScoreForVerdict("red"),
|
|
4391
|
-
toolCallId: result.toolCallId
|
|
4392
|
-
};
|
|
4502
|
+
if (result.verdict === "No verdict" && result.status !== "logged") {
|
|
4503
|
+
throw new Error(
|
|
4504
|
+
`memory scan: judge returned no verdict without an audit-tier marker (status: ${result.status || "absent"})`
|
|
4505
|
+
);
|
|
4393
4506
|
}
|
|
4394
|
-
const
|
|
4395
|
-
|
|
4507
|
+
const KNOWN_ACTIONS = ["allow", "block", "hold_for_user_confirm"];
|
|
4508
|
+
const action = result.actionType.trim().toLowerCase();
|
|
4509
|
+
if (result.verdict !== "No verdict" && !KNOWN_ACTIONS.includes(action)) {
|
|
4510
|
+
throw new Error(
|
|
4511
|
+
`memory scan: unrecognized action_type from judge (${result.actionType || "absent"})`
|
|
4512
|
+
);
|
|
4513
|
+
}
|
|
4514
|
+
const mapped = native.mapVerdict(
|
|
4515
|
+
action,
|
|
4396
4516
|
result.confidence,
|
|
4397
4517
|
threshold
|
|
4398
4518
|
);
|
|
4519
|
+
let verdict = mapped;
|
|
4520
|
+
if (result.verdict === "BLOCK") {
|
|
4521
|
+
verdict = "red";
|
|
4522
|
+
} else if (result.verdict === "HOLD" && mapped === "green") {
|
|
4523
|
+
verdict = "yellow";
|
|
4524
|
+
}
|
|
4399
4525
|
const parsed = native.parseScoreFromReason(result.reason);
|
|
4400
4526
|
const score = result.score ?? parsed.score ?? native.defaultScoreForVerdict(verdict);
|
|
4401
4527
|
return {
|
|
@@ -9301,8 +9427,8 @@ Reporter$3.prototype.wrapResult = function wrapResult(result) {
|
|
|
9301
9427
|
errors: state2.errors
|
|
9302
9428
|
};
|
|
9303
9429
|
};
|
|
9304
|
-
function ReporterError$1(
|
|
9305
|
-
this.path =
|
|
9430
|
+
function ReporterError$1(path7, msg) {
|
|
9431
|
+
this.path = path7;
|
|
9306
9432
|
this.rethrow(msg);
|
|
9307
9433
|
}
|
|
9308
9434
|
inherits$v(ReporterError$1, Error);
|
|
@@ -29523,8 +29649,8 @@ Reporter.prototype.wrapResult = function wrapResult2(result) {
|
|
|
29523
29649
|
errors: state2.errors
|
|
29524
29650
|
};
|
|
29525
29651
|
};
|
|
29526
|
-
function ReporterError(
|
|
29527
|
-
this.path =
|
|
29652
|
+
function ReporterError(path7, msg) {
|
|
29653
|
+
this.path = path7;
|
|
29528
29654
|
this.rethrow(msg);
|
|
29529
29655
|
}
|
|
29530
29656
|
inherits(ReporterError, Error);
|
|
@@ -32554,8 +32680,8 @@ var parseUtil = {};
|
|
|
32554
32680
|
const errors_js_12 = errors$3;
|
|
32555
32681
|
const en_js_12 = __importDefault2(en);
|
|
32556
32682
|
const makeIssue = (params) => {
|
|
32557
|
-
const { data, path:
|
|
32558
|
-
const fullPath = [...
|
|
32683
|
+
const { data, path: path7, errorMaps, issueData } = params;
|
|
32684
|
+
const fullPath = [...path7, ...issueData.path || []];
|
|
32559
32685
|
const fullIssue = {
|
|
32560
32686
|
...issueData,
|
|
32561
32687
|
path: fullPath
|
|
@@ -32692,11 +32818,11 @@ var errorUtil_js_1 = errorUtil$1;
|
|
|
32692
32818
|
var parseUtil_js_1 = parseUtil;
|
|
32693
32819
|
var util_js_1 = util;
|
|
32694
32820
|
var ParseInputLazyPath = class {
|
|
32695
|
-
constructor(parent, value,
|
|
32821
|
+
constructor(parent, value, path7, key3) {
|
|
32696
32822
|
this._cachedPath = [];
|
|
32697
32823
|
this.parent = parent;
|
|
32698
32824
|
this.data = value;
|
|
32699
|
-
this._path =
|
|
32825
|
+
this._path = path7;
|
|
32700
32826
|
this._key = key3;
|
|
32701
32827
|
}
|
|
32702
32828
|
get path() {
|
|
@@ -39602,21 +39728,21 @@ function createTimeoutController(timeout) {
|
|
|
39602
39728
|
const timeoutId = setTimeout(() => controller.abort(timeoutError), timeout);
|
|
39603
39729
|
return { controller, timeoutId };
|
|
39604
39730
|
}
|
|
39605
|
-
function handleRequest(method,
|
|
39731
|
+
function handleRequest(method, path7, endpoint, timeout, postObject) {
|
|
39606
39732
|
return __awaiter$2(this, void 0, void 0, function* () {
|
|
39607
39733
|
if (method == enums_1$2.Method.GET) {
|
|
39608
|
-
return yield get(
|
|
39734
|
+
return yield get(path7, endpoint, timeout);
|
|
39609
39735
|
} else {
|
|
39610
|
-
return yield post(
|
|
39736
|
+
return yield post(path7, endpoint, timeout, postObject);
|
|
39611
39737
|
}
|
|
39612
39738
|
});
|
|
39613
39739
|
}
|
|
39614
|
-
function get(
|
|
39740
|
+
function get(path7, endpoint, timeout) {
|
|
39615
39741
|
return __awaiter$2(this, void 0, void 0, function* () {
|
|
39616
|
-
logger.debug(`GET URL ${new URL(
|
|
39742
|
+
logger.debug(`GET URL ${new URL(path7, endpoint).href}`);
|
|
39617
39743
|
try {
|
|
39618
39744
|
const { controller, timeoutId } = createTimeoutController(timeout);
|
|
39619
|
-
const response = yield fetch(new URL(
|
|
39745
|
+
const response = yield fetch(new URL(path7, endpoint).href, {
|
|
39620
39746
|
signal: controller === null || controller === void 0 ? void 0 : controller.signal
|
|
39621
39747
|
});
|
|
39622
39748
|
if (timeoutId)
|
|
@@ -39654,9 +39780,9 @@ function constructBufferResponseBody(response) {
|
|
|
39654
39780
|
return responseText ? responseText : response.statusText;
|
|
39655
39781
|
});
|
|
39656
39782
|
}
|
|
39657
|
-
function post(
|
|
39783
|
+
function post(path7, endpoint, timeout, requestBody) {
|
|
39658
39784
|
return __awaiter$2(this, void 0, void 0, function* () {
|
|
39659
|
-
logger.debug(`POST URL ${new URL(
|
|
39785
|
+
logger.debug(`POST URL ${new URL(path7, endpoint).href}`);
|
|
39660
39786
|
logger.debug(`POST body ${JSON.stringify(requestBody)}`);
|
|
39661
39787
|
if (buffer_1.Buffer.isBuffer(requestBody)) {
|
|
39662
39788
|
try {
|
|
@@ -39670,7 +39796,7 @@ function post(path6, endpoint, timeout, requestBody) {
|
|
|
39670
39796
|
},
|
|
39671
39797
|
signal: controller === null || controller === void 0 ? void 0 : controller.signal
|
|
39672
39798
|
};
|
|
39673
|
-
const response = yield fetch(new URL(
|
|
39799
|
+
const response = yield fetch(new URL(path7, endpoint).href, requestOptions);
|
|
39674
39800
|
if (timeoutId)
|
|
39675
39801
|
clearTimeout(timeoutId);
|
|
39676
39802
|
const transactionTimestamp = response.headers.get("X-Transaction-Timestamp");
|
|
@@ -39681,7 +39807,7 @@ function post(path6, endpoint, timeout, requestBody) {
|
|
|
39681
39807
|
} else {
|
|
39682
39808
|
try {
|
|
39683
39809
|
const { controller, timeoutId } = createTimeoutController(timeout);
|
|
39684
|
-
const response = yield fetch(new URL(
|
|
39810
|
+
const response = yield fetch(new URL(path7, endpoint).href, {
|
|
39685
39811
|
method: "post",
|
|
39686
39812
|
body: JSON.stringify(requestBody),
|
|
39687
39813
|
headers: {
|
|
@@ -39861,10 +39987,10 @@ function requireFailoverStrategies() {
|
|
|
39861
39987
|
}
|
|
39862
39988
|
}
|
|
39863
39989
|
function abortOnError(_a2) {
|
|
39864
|
-
return __awaiter2(this, arguments, void 0, function* ({ method, path:
|
|
39990
|
+
return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, timeoutOverride }) {
|
|
39865
39991
|
return yield retryRequest({
|
|
39866
39992
|
method,
|
|
39867
|
-
path:
|
|
39993
|
+
path: path7,
|
|
39868
39994
|
config: config2,
|
|
39869
39995
|
postObject,
|
|
39870
39996
|
timeoutOverride,
|
|
@@ -39875,10 +40001,10 @@ function requireFailoverStrategies() {
|
|
|
39875
40001
|
});
|
|
39876
40002
|
}
|
|
39877
40003
|
function tryNextOnError(_a2) {
|
|
39878
|
-
return __awaiter2(this, arguments, void 0, function* ({ method, path:
|
|
40004
|
+
return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, timeoutOverride }) {
|
|
39879
40005
|
return yield retryRequest({
|
|
39880
40006
|
method,
|
|
39881
|
-
path:
|
|
40007
|
+
path: path7,
|
|
39882
40008
|
config: config2,
|
|
39883
40009
|
postObject,
|
|
39884
40010
|
timeoutOverride,
|
|
@@ -39894,7 +40020,7 @@ function requireFailoverStrategies() {
|
|
|
39894
40020
|
return endpointPoolLength - (endpointPoolLength - 1) / 3;
|
|
39895
40021
|
}
|
|
39896
40022
|
function queryMajority(_a2) {
|
|
39897
|
-
return __awaiter2(this, arguments, void 0, function* ({ method, path:
|
|
40023
|
+
return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, timeoutOverride }) {
|
|
39898
40024
|
var _b;
|
|
39899
40025
|
const bftMajorityThreshold = calculateBftMajorityThreshold(config2.endpointPool.length);
|
|
39900
40026
|
const failureThreshold = config2.endpointPool.length - bftMajorityThreshold + 1;
|
|
@@ -39905,7 +40031,7 @@ function requireFailoverStrategies() {
|
|
|
39905
40031
|
const promises = availableNodes.map((node2) => __awaiter2(this, void 0, void 0, function* () {
|
|
39906
40032
|
try {
|
|
39907
40033
|
const requestTimeout = timeoutOverride !== null && timeoutOverride !== void 0 ? timeoutOverride : config2.responseTimeout;
|
|
39908
|
-
const response = yield (0, httpUtil_1.handleRequest)(method,
|
|
40034
|
+
const response = yield (0, httpUtil_1.handleRequest)(method, path7, node2.url, requestTimeout, postObject);
|
|
39909
40035
|
const { statusCode } = response;
|
|
39910
40036
|
if (statusCode && (0, http_utils_1.isSuccessfulStatusCode)(statusCode)) {
|
|
39911
40037
|
outcomes.push({ type: "SUCCESS", result: response });
|
|
@@ -39952,7 +40078,7 @@ function requireFailoverStrategies() {
|
|
|
39952
40078
|
});
|
|
39953
40079
|
}
|
|
39954
40080
|
function singleEndpoint(_a2) {
|
|
39955
|
-
return __awaiter2(this, arguments, void 0, function* ({ method, path:
|
|
40081
|
+
return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, timeoutOverride }) {
|
|
39956
40082
|
let statusCode = null;
|
|
39957
40083
|
let rspBody = null;
|
|
39958
40084
|
let error4 = null;
|
|
@@ -39963,7 +40089,7 @@ function requireFailoverStrategies() {
|
|
|
39963
40089
|
}
|
|
39964
40090
|
for (let attempt = 0; attempt < config2.attemptsPerEndpoint; attempt++) {
|
|
39965
40091
|
const requestTimeout = timeoutOverride !== null && timeoutOverride !== void 0 ? timeoutOverride : config2.responseTimeout;
|
|
39966
|
-
const response = yield (0, httpUtil_1.handleRequest)(method,
|
|
40092
|
+
const response = yield (0, httpUtil_1.handleRequest)(method, path7, endpoint.url, requestTimeout, postObject);
|
|
39967
40093
|
if (response) {
|
|
39968
40094
|
({ error: error4, statusCode, rspBody, transactionTimestamp } = response);
|
|
39969
40095
|
}
|
|
@@ -39978,7 +40104,7 @@ function requireFailoverStrategies() {
|
|
|
39978
40104
|
});
|
|
39979
40105
|
}
|
|
39980
40106
|
function retryRequest(_a2) {
|
|
39981
|
-
return __awaiter2(this, arguments, void 0, function* ({ method, path:
|
|
40107
|
+
return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, useNextNodeOnError, recoveryThreshold, timeoutOverride }) {
|
|
39982
40108
|
var _b, _c, _d;
|
|
39983
40109
|
let statusCode = null;
|
|
39984
40110
|
let rspBody = null;
|
|
@@ -39989,7 +40115,7 @@ function requireFailoverStrategies() {
|
|
|
39989
40115
|
for (const node2 of availableNodes) {
|
|
39990
40116
|
for (let attempt = 0; attempt < config2.attemptsPerEndpoint; attempt++) {
|
|
39991
40117
|
const requestTimeout = timeoutOverride !== null && timeoutOverride !== void 0 ? timeoutOverride : config2.responseTimeout;
|
|
39992
|
-
const response = yield (0, httpUtil_1.handleRequest)(method,
|
|
40118
|
+
const response = yield (0, httpUtil_1.handleRequest)(method, path7, node2.url, requestTimeout, postObject);
|
|
39993
40119
|
error4 = (_b = response === null || response === void 0 ? void 0 : response.error) !== null && _b !== void 0 ? _b : null;
|
|
39994
40120
|
statusCode = (_c = response === null || response === void 0 ? void 0 : response.statusCode) !== null && _c !== void 0 ? _c : null;
|
|
39995
40121
|
rspBody = (_d = response === null || response === void 0 ? void 0 : response.rspBody) !== null && _d !== void 0 ? _d : null;
|
|
@@ -40132,19 +40258,19 @@ function requireRequestWithFailoverStrategy() {
|
|
|
40132
40258
|
const enums_12 = enums;
|
|
40133
40259
|
const failoverStrategies_1 = requireFailoverStrategies();
|
|
40134
40260
|
function requestWithFailoverStrategy$1(method_1, path_1, config_1, postObject_1) {
|
|
40135
|
-
return __awaiter2(this, arguments, void 0, function* (method,
|
|
40261
|
+
return __awaiter2(this, arguments, void 0, function* (method, path7, config2, postObject, forceSingleEndpoint = false, timeoutOverride) {
|
|
40136
40262
|
switch (config2.failoverStrategy) {
|
|
40137
40263
|
case enums_12.FailoverStrategy.AbortOnError:
|
|
40138
|
-
return yield (0, failoverStrategies_1.abortOnError)({ method, path:
|
|
40264
|
+
return yield (0, failoverStrategies_1.abortOnError)({ method, path: path7, config: config2, postObject, timeoutOverride });
|
|
40139
40265
|
case enums_12.FailoverStrategy.TryNextOnError:
|
|
40140
|
-
return yield (0, failoverStrategies_1.tryNextOnError)({ method, path:
|
|
40266
|
+
return yield (0, failoverStrategies_1.tryNextOnError)({ method, path: path7, config: config2, postObject, timeoutOverride });
|
|
40141
40267
|
case enums_12.FailoverStrategy.SingleEndpoint:
|
|
40142
|
-
return yield (0, failoverStrategies_1.singleEndpoint)({ method, path:
|
|
40268
|
+
return yield (0, failoverStrategies_1.singleEndpoint)({ method, path: path7, config: config2, postObject, timeoutOverride });
|
|
40143
40269
|
case enums_12.FailoverStrategy.QueryMajority:
|
|
40144
40270
|
if (forceSingleEndpoint) {
|
|
40145
|
-
return yield (0, failoverStrategies_1.singleEndpoint)({ method, path:
|
|
40271
|
+
return yield (0, failoverStrategies_1.singleEndpoint)({ method, path: path7, config: config2, postObject, timeoutOverride });
|
|
40146
40272
|
}
|
|
40147
|
-
return yield (0, failoverStrategies_1.queryMajority)({ method, path:
|
|
40273
|
+
return yield (0, failoverStrategies_1.queryMajority)({ method, path: path7, config: config2, postObject, timeoutOverride });
|
|
40148
40274
|
default:
|
|
40149
40275
|
throw new Error(`Unsupported failover strategy: ${config2.failoverStrategy}`);
|
|
40150
40276
|
}
|
|
@@ -41343,7 +41469,7 @@ var networkSettings = {};
|
|
|
41343
41469
|
const restNetworkSettingsValidationContext = RestNetworkSettingsSchema.safeParse(networkSettings2);
|
|
41344
41470
|
if ("error" in restNetworkSettingsValidationContext) {
|
|
41345
41471
|
const { error: { issues } = {} } = restNetworkSettingsValidationContext;
|
|
41346
|
-
const errorMessage2 = issues === null || issues === void 0 ? void 0 : issues.map(({ message, path:
|
|
41472
|
+
const errorMessage2 = issues === null || issues === void 0 ? void 0 : issues.map(({ message, path: path7 }) => `${path7[0]}: ${message}`).join(", ");
|
|
41347
41473
|
if (throwOnError) {
|
|
41348
41474
|
throw new Error(errorMessage2);
|
|
41349
41475
|
}
|
|
@@ -42725,6 +42851,7 @@ function classifyMemoryWrite(event, ctx, opts = {}) {
|
|
|
42725
42851
|
}
|
|
42726
42852
|
|
|
42727
42853
|
// src-ts/memory/guard.ts
|
|
42854
|
+
var import_node_path4 = __toESM(require("path"));
|
|
42728
42855
|
function emitDebugProbe(event, ctx, memEntry, logger2) {
|
|
42729
42856
|
if (!logger2?.info) return;
|
|
42730
42857
|
const ev = event ?? {};
|
|
@@ -42761,7 +42888,8 @@ async function guardMemoryWrite(input) {
|
|
|
42761
42888
|
toolNames,
|
|
42762
42889
|
enforce = true,
|
|
42763
42890
|
debug: debug2 = false,
|
|
42764
|
-
logger: logger2
|
|
42891
|
+
logger: logger2,
|
|
42892
|
+
memoryFilePath
|
|
42765
42893
|
} = input;
|
|
42766
42894
|
const memEntry = classifyMemoryWrite(event, ctx, { patterns, toolNames });
|
|
42767
42895
|
if (debug2) emitDebugProbe(event, ctx, memEntry, logger2);
|
|
@@ -42797,17 +42925,28 @@ async function guardMemoryWrite(input) {
|
|
|
42797
42925
|
committed: false
|
|
42798
42926
|
};
|
|
42799
42927
|
}
|
|
42800
|
-
|
|
42801
|
-
|
|
42802
|
-
|
|
42803
|
-
|
|
42804
|
-
|
|
42805
|
-
|
|
42806
|
-
|
|
42807
|
-
|
|
42808
|
-
|
|
42928
|
+
const isManagedMemoryFile = memoryFilePath !== void 0 && import_node_path4.default.resolve(memEntry.key) === import_node_path4.default.resolve(memoryFilePath);
|
|
42929
|
+
if (isManagedMemoryFile) {
|
|
42930
|
+
commitMemoryVersion(memEntry.value, auth, {
|
|
42931
|
+
score: scanResult.score,
|
|
42932
|
+
orgName,
|
|
42933
|
+
endpoint
|
|
42934
|
+
}).catch((err) => {
|
|
42935
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
42936
|
+
logger2?.warn?.("[atbash] memory commit to chain failed", {
|
|
42937
|
+
path: memEntry.key,
|
|
42938
|
+
reason
|
|
42939
|
+
});
|
|
42809
42940
|
});
|
|
42810
|
-
}
|
|
42941
|
+
} else {
|
|
42942
|
+
logger2?.info?.(
|
|
42943
|
+
"[atbash] scanned but not committed \u2014 not the managed memory file",
|
|
42944
|
+
{
|
|
42945
|
+
path: memEntry.key,
|
|
42946
|
+
memoryFilePath: memoryFilePath ?? "(not configured)"
|
|
42947
|
+
}
|
|
42948
|
+
);
|
|
42949
|
+
}
|
|
42811
42950
|
logger2?.info?.(
|
|
42812
42951
|
scanResult.verdict === "yellow" ? "[atbash] memory HOLD" : "[atbash] memory ALLOW",
|
|
42813
42952
|
{ path: memEntry.key, score: scanResult.score, reason: scanResult.reason }
|
|
@@ -42816,7 +42955,7 @@ async function guardMemoryWrite(input) {
|
|
|
42816
42955
|
handled: true,
|
|
42817
42956
|
decision: { allow: true },
|
|
42818
42957
|
scanResult,
|
|
42819
|
-
committed:
|
|
42958
|
+
committed: isManagedMemoryFile
|
|
42820
42959
|
};
|
|
42821
42960
|
}
|
|
42822
42961
|
|
|
@@ -42835,26 +42974,26 @@ async function syncLocalMemory(auth, pointer, opts = {}) {
|
|
|
42835
42974
|
const now = Date.now();
|
|
42836
42975
|
const withinTtl = !opts.force && now - pointer.checkedAt < ttl;
|
|
42837
42976
|
if (withinTtl) {
|
|
42838
|
-
return { drifted: false, pointer };
|
|
42977
|
+
return { drifted: false, checked: false, pointer };
|
|
42839
42978
|
}
|
|
42840
42979
|
const currentId = await getActiveMemoryId(auth, opts.chainOpts);
|
|
42841
42980
|
const nextPointer = { activeId: currentId, checkedAt: now };
|
|
42842
42981
|
if (currentId === pointer.activeId) {
|
|
42843
|
-
return { drifted: false, pointer: nextPointer };
|
|
42982
|
+
return { drifted: false, checked: true, pointer: nextPointer };
|
|
42844
42983
|
}
|
|
42845
42984
|
if (currentId === null) {
|
|
42846
|
-
return { drifted: true, current: null, pointer: nextPointer };
|
|
42985
|
+
return { drifted: true, checked: true, current: null, pointer: nextPointer };
|
|
42847
42986
|
}
|
|
42848
42987
|
const row = await getMemoryById(currentId, auth, opts.chainOpts);
|
|
42849
42988
|
if (row.decryptError) {
|
|
42850
42989
|
throw new MemoryIntegrityError(currentId, row.decryptError);
|
|
42851
42990
|
}
|
|
42852
|
-
return { drifted: true, current: row, pointer: nextPointer };
|
|
42991
|
+
return { drifted: true, checked: true, current: row, pointer: nextPointer };
|
|
42853
42992
|
}
|
|
42854
42993
|
|
|
42855
42994
|
// src-ts/memory/pointer-store.ts
|
|
42856
42995
|
var import_node_fs4 = require("fs");
|
|
42857
|
-
var
|
|
42996
|
+
var import_node_path5 = __toESM(require("path"));
|
|
42858
42997
|
var EMPTY = { version: 1, agents: {} };
|
|
42859
42998
|
var PointerStore = class {
|
|
42860
42999
|
constructor(filePath) {
|
|
@@ -42896,19 +43035,19 @@ var PointerStore = class {
|
|
|
42896
43035
|
this.cache = { ...EMPTY, agents: {} };
|
|
42897
43036
|
}
|
|
42898
43037
|
async persist(file) {
|
|
42899
|
-
await import_node_fs4.promises.mkdir(
|
|
43038
|
+
await import_node_fs4.promises.mkdir(import_node_path5.default.dirname(this.filePath), { recursive: true });
|
|
42900
43039
|
const tmp = `${this.filePath}.${process.pid}.tmp`;
|
|
42901
43040
|
await import_node_fs4.promises.writeFile(tmp, JSON.stringify(file, null, 2), "utf8");
|
|
42902
43041
|
await import_node_fs4.promises.rename(tmp, this.filePath);
|
|
42903
43042
|
}
|
|
42904
43043
|
};
|
|
42905
43044
|
function defaultPointerPath(workspaceDir = process.cwd()) {
|
|
42906
|
-
return
|
|
43045
|
+
return import_node_path5.default.join(workspaceDir, ".atbash", "memory-pointer.json");
|
|
42907
43046
|
}
|
|
42908
43047
|
|
|
42909
43048
|
// src-ts/memory/file-logger.ts
|
|
42910
43049
|
var import_node_fs5 = require("fs");
|
|
42911
|
-
var
|
|
43050
|
+
var import_node_path6 = __toESM(require("path"));
|
|
42912
43051
|
function formatMeta(meta) {
|
|
42913
43052
|
if (!meta || Object.keys(meta).length === 0) return "";
|
|
42914
43053
|
try {
|
|
@@ -42920,7 +43059,7 @@ function formatMeta(meta) {
|
|
|
42920
43059
|
function createFileLogger(filePath, upstream) {
|
|
42921
43060
|
let queue = Promise.resolve();
|
|
42922
43061
|
async function ensureDir() {
|
|
42923
|
-
await import_node_fs5.promises.mkdir(
|
|
43062
|
+
await import_node_fs5.promises.mkdir(import_node_path6.default.dirname(filePath), { recursive: true });
|
|
42924
43063
|
}
|
|
42925
43064
|
function append(level, message, meta) {
|
|
42926
43065
|
const line = `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${message}${formatMeta(meta)}
|
|
@@ -42940,7 +43079,7 @@ function createFileLogger(filePath, upstream) {
|
|
|
42940
43079
|
};
|
|
42941
43080
|
}
|
|
42942
43081
|
function defaultPluginLogPath(workspaceDir = process.cwd()) {
|
|
42943
|
-
return
|
|
43082
|
+
return import_node_path6.default.join(workspaceDir, ".atbash", "plugin.log");
|
|
42944
43083
|
}
|
|
42945
43084
|
|
|
42946
43085
|
// src-ts/memory/read-classifier.ts
|
|
@@ -42955,13 +43094,13 @@ function classifyMemoryRead(event, ctx, opts = {}) {
|
|
|
42955
43094
|
|
|
42956
43095
|
// src-ts/memory/guard-manager.ts
|
|
42957
43096
|
var import_node_fs6 = require("fs");
|
|
42958
|
-
var
|
|
43097
|
+
var import_node_path7 = __toESM(require("path"));
|
|
42959
43098
|
var DEFAULT_SYNC_TTL_MS = 3e4;
|
|
42960
43099
|
var MemoryGuardManager = class {
|
|
42961
43100
|
constructor(opts) {
|
|
42962
43101
|
this.opts = opts;
|
|
42963
43102
|
const workspaceDir = opts.workspaceDir;
|
|
42964
|
-
this.memoryFilePath = opts.memoryFilePath ??
|
|
43103
|
+
this.memoryFilePath = opts.memoryFilePath ?? import_node_path7.default.join(workspaceDir, "MEMORY.md");
|
|
42965
43104
|
this.pointerStore = new PointerStore(opts.pointerFilePath ?? defaultPointerPath(workspaceDir));
|
|
42966
43105
|
this.logger = createFileLogger(
|
|
42967
43106
|
opts.logFilePath ?? defaultPluginLogPath(workspaceDir),
|
|
@@ -42991,7 +43130,11 @@ var MemoryGuardManager = class {
|
|
|
42991
43130
|
async runBootProbe() {
|
|
42992
43131
|
try {
|
|
42993
43132
|
const seed = { activeId: null, checkedAt: 0 };
|
|
42994
|
-
const result = await syncLocalMemory(this.opts.auth, seed, {
|
|
43133
|
+
const result = await syncLocalMemory(this.opts.auth, seed, {
|
|
43134
|
+
ttlMs: 0,
|
|
43135
|
+
force: true,
|
|
43136
|
+
chainOpts: this.opts.chainOpts
|
|
43137
|
+
});
|
|
42995
43138
|
if (!result.drifted && result.pointer.activeId == null) {
|
|
42996
43139
|
this.logger.info(
|
|
42997
43140
|
`[atbash] no active memory on chain for agent=${this.agentPubkeyHex.slice(0, 16)}\u2026 org=${this.opts.orgName ?? "(none)"} \u2014 either the agent isn't registered on this chain or hasn't written any memory. Sync will remain a no-op until a write lands.`
|
|
@@ -43023,15 +43166,19 @@ var MemoryGuardManager = class {
|
|
|
43023
43166
|
}
|
|
43024
43167
|
}
|
|
43025
43168
|
/**
|
|
43026
|
-
* Returns a `HookDecision` when the
|
|
43027
|
-
*
|
|
43028
|
-
*
|
|
43169
|
+
* Returns a `HookDecision` when the guard reached a decision about this event.
|
|
43170
|
+
* Returns `null` when it did not — either the event isn't memory-related, or it
|
|
43171
|
+
* is but the guard could not check it. In both cases the host falls through to
|
|
43172
|
+
* its own audit.
|
|
43173
|
+
*
|
|
43174
|
+
* A returned decision carries `audited` (see `HookDecision`). Only
|
|
43175
|
+
* `{ allow: true, audited: true }` means "checked and cleared"; anything else
|
|
43176
|
+
* that allows is a call the host still needs to judge.
|
|
43029
43177
|
*/
|
|
43030
43178
|
async handleBeforeToolCall(event, ctx) {
|
|
43031
43179
|
if (classifyMemoryRead(event, ctx, this.opts.memoryReadClassifier)) {
|
|
43032
43180
|
this.logger.info("[atbash] memory read intercepted \u2014 running sync check");
|
|
43033
|
-
|
|
43034
|
-
return readDecision ?? { allow: true };
|
|
43181
|
+
return await this.handleMemoryRead(event, ctx);
|
|
43035
43182
|
}
|
|
43036
43183
|
const guardLogger = {
|
|
43037
43184
|
info: (msg, meta) => this.logger.info(msg, meta && typeof meta === "object" ? meta : void 0),
|
|
@@ -43048,7 +43195,9 @@ var MemoryGuardManager = class {
|
|
|
43048
43195
|
toolNames: this.opts.memoryWriteToolNames,
|
|
43049
43196
|
enforce: this.enforce,
|
|
43050
43197
|
debug: this.opts.debug,
|
|
43051
|
-
logger: guardLogger
|
|
43198
|
+
logger: guardLogger,
|
|
43199
|
+
// Only this file may reach the single, path-less chain memory slot.
|
|
43200
|
+
memoryFilePath: this.memoryFilePath
|
|
43052
43201
|
});
|
|
43053
43202
|
return this.mapGuardResult(guard);
|
|
43054
43203
|
}
|
|
@@ -43066,30 +43215,81 @@ var MemoryGuardManager = class {
|
|
|
43066
43215
|
block: true,
|
|
43067
43216
|
blockReason: d.reason ?? "",
|
|
43068
43217
|
allow: false,
|
|
43069
|
-
reason: d.reason
|
|
43218
|
+
reason: d.reason,
|
|
43219
|
+
// A block IS a decision — the most thoroughly checked one the guard
|
|
43220
|
+
// makes. Without this a host following the documented `!audited ->
|
|
43221
|
+
// judge it yourself` rule would re-judge its way past a red scan.
|
|
43222
|
+
audited: true,
|
|
43223
|
+
...sr2 ? { verdict: sr2.verdict } : {}
|
|
43070
43224
|
};
|
|
43071
43225
|
}
|
|
43072
43226
|
this.logger.info(
|
|
43073
43227
|
`[atbash] guardMemoryWrite ALLOWED \u2014 verdict=${verdict} score=${score} committed=${guard.committed === true}`
|
|
43074
43228
|
);
|
|
43075
|
-
|
|
43229
|
+
if (sr2 === void 0) {
|
|
43230
|
+
return { allow: true, audited: false, reason: "memory scan did not run (observe mode)" };
|
|
43231
|
+
}
|
|
43232
|
+
if (sr2.verdict !== "green") {
|
|
43233
|
+
return {
|
|
43234
|
+
allow: true,
|
|
43235
|
+
audited: false,
|
|
43236
|
+
verdict: sr2.verdict,
|
|
43237
|
+
reason: `memory scan returned ${sr2.verdict} but this guard is not enforcing it`
|
|
43238
|
+
};
|
|
43239
|
+
}
|
|
43240
|
+
return { allow: true, audited: true, verdict: sr2.verdict };
|
|
43076
43241
|
}
|
|
43077
|
-
|
|
43242
|
+
/**
|
|
43243
|
+
* Whether the pointer state this manager tracks actually describes the file
|
|
43244
|
+
* this call is about to read.
|
|
43245
|
+
*
|
|
43246
|
+
* The classifier fires on nine patterns — including the bare tokens
|
|
43247
|
+
* `"memory/"`, `"CLAUDE.md"` and `"AGENTS.md"` — but the sync path only ever
|
|
43248
|
+
* reads, refreshes, or vouches for `this.memoryFilePath`. Without this check a
|
|
43249
|
+
* read of `/repo/CLAUDE.md` (or any path merely containing `memory/`) would
|
|
43250
|
+
* receive an `audited: true` for a file the guard never opened.
|
|
43251
|
+
*
|
|
43252
|
+
* Conservative on purpose: every path-shaped value found must resolve to the
|
|
43253
|
+
* managed file. If none is found, or any one differs, the answer is no. That
|
|
43254
|
+
* also covers events carrying two different path keys, where the classifier
|
|
43255
|
+
* and the host could otherwise disagree about which one is authoritative.
|
|
43256
|
+
*/
|
|
43257
|
+
vouchesForTarget(event, ctx) {
|
|
43258
|
+
const KEYS = ["path", "file_path", "filePath", "notebook_path", "notebookPath", "target"];
|
|
43259
|
+
const found = [];
|
|
43260
|
+
for (const src of [event, ctx]) {
|
|
43261
|
+
for (const bag of [src, src?.params]) {
|
|
43262
|
+
if (!bag || typeof bag !== "object") continue;
|
|
43263
|
+
const rec = bag;
|
|
43264
|
+
for (const k of KEYS) {
|
|
43265
|
+
if (typeof rec[k] === "string" && rec[k]) found.push(rec[k]);
|
|
43266
|
+
}
|
|
43267
|
+
}
|
|
43268
|
+
}
|
|
43269
|
+
if (found.length === 0) return false;
|
|
43270
|
+
const managed = import_node_path7.default.resolve(this.memoryFilePath);
|
|
43271
|
+
return found.every((p) => import_node_path7.default.resolve(p) === managed);
|
|
43272
|
+
}
|
|
43273
|
+
async handleMemoryRead(event, ctx) {
|
|
43078
43274
|
const pointer = await this.pointerStore.get(this.agentPubkeyHex);
|
|
43079
43275
|
let result;
|
|
43080
43276
|
try {
|
|
43081
|
-
result = await syncLocalMemory(this.opts.auth, pointer, {
|
|
43277
|
+
result = await syncLocalMemory(this.opts.auth, pointer, {
|
|
43278
|
+
ttlMs: this.ttlMs,
|
|
43279
|
+
chainOpts: this.opts.chainOpts
|
|
43280
|
+
});
|
|
43082
43281
|
} catch (err) {
|
|
43083
43282
|
if (err instanceof MemoryIntegrityError) {
|
|
43084
43283
|
const reason = `Memory integrity check failed on id ${err.id} \u2014 read blocked.`;
|
|
43085
43284
|
this.logger.warn("[atbash] MEMORY INTEGRITY FAILURE", { id: err.id, error: err.message });
|
|
43086
43285
|
if (!this.enforce) return null;
|
|
43087
|
-
return { block: true, blockReason: reason, allow: false, reason };
|
|
43286
|
+
return { block: true, blockReason: reason, allow: false, reason, audited: true };
|
|
43088
43287
|
}
|
|
43089
43288
|
const msg = err instanceof Error ? err.message : String(err);
|
|
43090
43289
|
this.logger.warn("[atbash] memory sync failed (serving local copy)", { error: msg });
|
|
43091
43290
|
return null;
|
|
43092
43291
|
}
|
|
43292
|
+
let onDiskIsCurrent = result.checked;
|
|
43093
43293
|
if (result.drifted) {
|
|
43094
43294
|
const fresh = result.current;
|
|
43095
43295
|
if (fresh) {
|
|
@@ -43097,7 +43297,7 @@ var MemoryGuardManager = class {
|
|
|
43097
43297
|
const reason = `Rolled-back memory version #${fresh.id} scored ${fresh.score} (below threshold ${this.rollbackMinScore}) \u2014 read blocked.`;
|
|
43098
43298
|
this.logger.warn("[atbash] blocking read on low-score rollback", { id: fresh.id, score: fresh.score });
|
|
43099
43299
|
if (!this.enforce) return null;
|
|
43100
|
-
return { block: true, blockReason: reason, allow: false, reason };
|
|
43300
|
+
return { block: true, blockReason: reason, allow: false, reason, audited: true };
|
|
43101
43301
|
}
|
|
43102
43302
|
this.logger.info("[atbash] memory drift detected \u2014 refreshing local file", {
|
|
43103
43303
|
id: fresh.id,
|
|
@@ -43108,16 +43308,26 @@ var MemoryGuardManager = class {
|
|
|
43108
43308
|
} catch (err) {
|
|
43109
43309
|
const msg = err instanceof Error ? err.message : String(err);
|
|
43110
43310
|
this.logger.warn("[atbash] failed to write refreshed memory (serving old)", { error: msg });
|
|
43311
|
+
onDiskIsCurrent = false;
|
|
43111
43312
|
}
|
|
43112
43313
|
} else {
|
|
43113
43314
|
this.logger.info("[atbash] active memory removed on chain", { pubkey: this.agentPubkeyHex });
|
|
43315
|
+
onDiskIsCurrent = false;
|
|
43114
43316
|
}
|
|
43115
43317
|
}
|
|
43116
|
-
|
|
43117
|
-
|
|
43318
|
+
if (onDiskIsCurrent) {
|
|
43319
|
+
await this.pointerStore.set(this.agentPubkeyHex, result.pointer);
|
|
43320
|
+
} else {
|
|
43321
|
+
this.logger.warn(
|
|
43322
|
+
"[atbash] not advancing memory pointer \u2014 local file is stale or revoked; reads stay unaudited until it is refreshed"
|
|
43323
|
+
);
|
|
43324
|
+
}
|
|
43325
|
+
if (!onDiskIsCurrent) return null;
|
|
43326
|
+
if (!this.vouchesForTarget(event, ctx)) return null;
|
|
43327
|
+
return { allow: true, audited: true };
|
|
43118
43328
|
}
|
|
43119
43329
|
async writeMemoryAtomic(content) {
|
|
43120
|
-
await import_node_fs6.promises.mkdir(
|
|
43330
|
+
await import_node_fs6.promises.mkdir(import_node_path7.default.dirname(this.memoryFilePath), { recursive: true });
|
|
43121
43331
|
const tmp = `${this.memoryFilePath}.${process.pid}.tmp`;
|
|
43122
43332
|
await import_node_fs6.promises.writeFile(tmp, content, "utf8");
|
|
43123
43333
|
await import_node_fs6.promises.rename(tmp, this.memoryFilePath);
|
|
@@ -43256,6 +43466,8 @@ function diffMemorySnapshots(before, after) {
|
|
|
43256
43466
|
DEFAULT_MEMORY_READ_TOOL_NAMES,
|
|
43257
43467
|
DEFAULT_MEMORY_WRITE_TOOL_NAMES,
|
|
43258
43468
|
EciesDomain,
|
|
43469
|
+
HttpClient,
|
|
43470
|
+
HttpTransportError,
|
|
43259
43471
|
KEY_FILENAMES,
|
|
43260
43472
|
MemoryGuardManager,
|
|
43261
43473
|
MemoryIntegrityError,
|