@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/index.mjs CHANGED
@@ -3021,8 +3021,8 @@ var HttpClient = class {
3021
3021
  this.baseUrl = baseUrl.replace(/\/+$/, "");
3022
3022
  this.timeoutMs = timeoutMs;
3023
3023
  }
3024
- buildUrl(path6, query) {
3025
- const url = new URL(this.baseUrl + path6);
3024
+ buildUrl(path7, query) {
3025
+ const url = new URL(this.baseUrl + path7);
3026
3026
  if (query) {
3027
3027
  for (const [k, v] of Object.entries(query)) {
3028
3028
  if (v !== void 0 && v !== null && v !== "") {
@@ -3032,23 +3032,83 @@ var HttpClient = class {
3032
3032
  }
3033
3033
  return url.toString();
3034
3034
  }
3035
- async get(path6, query, headers) {
3036
- return this.fetch(this.buildUrl(path6, query), {
3035
+ async get(path7, query, headers) {
3036
+ return this.fetch(this.buildUrl(path7, query), {
3037
3037
  method: "GET",
3038
3038
  ...headers && { headers }
3039
3039
  });
3040
3040
  }
3041
- async post(path6, body, headers) {
3042
- return this.fetch(this.buildUrl(path6), {
3041
+ async post(path7, body, headers) {
3042
+ return this.fetch(this.buildUrl(path7), {
3043
3043
  method: "POST",
3044
3044
  headers: { "Content-Type": "application/json", ...headers },
3045
3045
  body: JSON.stringify(body)
3046
3046
  });
3047
3047
  }
3048
3048
  async fetch(url, init4) {
3049
- return fetch(url, { ...init4, signal: AbortSignal.timeout(this.timeoutMs) });
3049
+ try {
3050
+ return await fetch(url, {
3051
+ ...init4,
3052
+ signal: AbortSignal.timeout(this.timeoutMs)
3053
+ });
3054
+ } catch (err) {
3055
+ throw classifyTransportError(err, url, init4.method ?? "GET", this.timeoutMs);
3056
+ }
3057
+ }
3058
+ };
3059
+ var HttpTransportError = class extends Error {
3060
+ kind;
3061
+ constructor(kind, message, options) {
3062
+ super(message, options);
3063
+ this.name = "HttpTransportError";
3064
+ this.kind = kind;
3050
3065
  }
3051
3066
  };
3067
+ function classifyTransportError(err, url, method, timeoutMs) {
3068
+ const name2 = err instanceof Error ? err.name : "";
3069
+ const cause = err instanceof Error ? err.cause : void 0;
3070
+ const code2 = cause && typeof cause === "object" && "code" in cause ? String(cause.code) : "";
3071
+ if (name2 === "TimeoutError") {
3072
+ return new HttpTransportError(
3073
+ "timeout",
3074
+ `${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`,
3075
+ { cause: err }
3076
+ );
3077
+ }
3078
+ if (name2 === "AbortError") {
3079
+ return new HttpTransportError(
3080
+ "aborted",
3081
+ `${method} ${url} was cancelled by the caller`,
3082
+ { cause: err }
3083
+ );
3084
+ }
3085
+ if (code2 === "ENOTFOUND" || code2 === "EAI_AGAIN") {
3086
+ return new HttpTransportError(
3087
+ "dns",
3088
+ `could not resolve the judge hostname (${url}) \u2014 check the endpoint and DNS`,
3089
+ { cause: err }
3090
+ );
3091
+ }
3092
+ if (code2 === "ECONNREFUSED") {
3093
+ return new HttpTransportError(
3094
+ "connect_refused",
3095
+ `judge refused the connection (${url}) \u2014 the service may be down or restarting`,
3096
+ { cause: err }
3097
+ );
3098
+ }
3099
+ if (code2 === "ECONNRESET" || code2 === "EPIPE") {
3100
+ return new HttpTransportError(
3101
+ "connection_reset",
3102
+ `judge dropped the connection mid-request (${url}) \u2014 retry once`,
3103
+ { cause: err }
3104
+ );
3105
+ }
3106
+ return new HttpTransportError(
3107
+ "unknown",
3108
+ `${method} ${url} failed: ${err instanceof Error ? err.message : String(err)}`,
3109
+ { cause: err }
3110
+ );
3111
+ }
3052
3112
 
3053
3113
  // src-ts/keyLoader.ts
3054
3114
  import { existsSync, readFileSync } from "fs";
@@ -3321,6 +3381,16 @@ var Atbash = class _Atbash {
3321
3381
  * calls don't re-hit the dashboard. Cleared by `clearChainCache()`.
3322
3382
  */
3323
3383
  _chainCache = /* @__PURE__ */ new Map();
3384
+ /**
3385
+ * Short-TTL cache for `/api/ai/exists`. The `registered` field is
3386
+ * monotonic (once true, stays true), so most calls in a burst re-fetch
3387
+ * data that hasn't changed. The `org_encryption_pubkey` field CAN change
3388
+ * — an org toggling encryption mid-session — so the TTL is deliberately
3389
+ * short (see `AGENT_EXISTS_TTL_MS`). Keyed by (pubkey, network) so
3390
+ * cross-agent / cross-network calls don't collide.
3391
+ */
3392
+ _agentExistsCache = null;
3393
+ static AGENT_EXISTS_TTL_MS = 5e3;
3324
3394
  /**
3325
3395
  * Cached bearer token for risk-engine / insurance read calls. Built
3326
3396
  * lazily as a signed `log_tool_call` tx and refreshed every 4 min so
@@ -3340,7 +3410,7 @@ var Atbash = class _Atbash {
3340
3410
  this.failClosed = options.failClosed !== false;
3341
3411
  this.debug = options.debug === true;
3342
3412
  this.logger = options.logger ?? {};
3343
- this.http = new HttpClient(this.endpoint, options.timeoutMs ?? 3e4);
3413
+ this.http = new HttpClient(this.endpoint, options.timeoutMs ?? 6e4);
3344
3414
  this.logEnvironmentOnce();
3345
3415
  if (this.endpoint !== DEFAULT_ENDPOINT) {
3346
3416
  this.logger.warn?.("[atbash] running on non-default judge endpoint", {
@@ -3420,9 +3490,18 @@ var Atbash = class _Atbash {
3420
3490
  */
3421
3491
  async checkAgentExists(pubkey, opts) {
3422
3492
  const pk = pubkey ?? this.auth.pubkey;
3493
+ const network = opts?.network;
3494
+ const now = Date.now();
3495
+ const cached = this._agentExistsCache;
3496
+ if (cached && cached.pubkey === pk && cached.network === network && cached.expiresAt > now) {
3497
+ if (pk === this.auth.pubkey) {
3498
+ this._orgKeyFromChain = cached.orgKey;
3499
+ }
3500
+ return cached.registered;
3501
+ }
3423
3502
  return this.track("checkAgentExists", pk, async () => {
3424
3503
  const query = { pubkey: pk };
3425
- if (opts?.network) query.network = opts.network;
3504
+ if (network) query.network = network;
3426
3505
  const resp = await this.http.get(
3427
3506
  "/api/ai/exists",
3428
3507
  query,
@@ -3430,11 +3509,21 @@ var Atbash = class _Atbash {
3430
3509
  );
3431
3510
  await this.raiseIfError(resp);
3432
3511
  const data = await this.json(resp);
3512
+ const registered = Boolean(data?.registered);
3513
+ const orgKey = typeof data?.org_encryption_pubkey === "string" && data.org_encryption_pubkey ? data.org_encryption_pubkey : null;
3514
+ if (registered) {
3515
+ this._agentExistsCache = {
3516
+ pubkey: pk,
3517
+ network,
3518
+ expiresAt: Date.now() + _Atbash.AGENT_EXISTS_TTL_MS,
3519
+ registered,
3520
+ orgKey
3521
+ };
3522
+ }
3433
3523
  if (pk === this.auth.pubkey) {
3434
- const key3 = data?.org_encryption_pubkey;
3435
- this._orgKeyFromChain = typeof key3 === "string" && key3 ? key3 : null;
3524
+ this._orgKeyFromChain = orgKey;
3436
3525
  }
3437
- return Boolean(data?.registered);
3526
+ return registered;
3438
3527
  });
3439
3528
  }
3440
3529
  /* ── log_tool_call (sign-only) ─────────────────────────────────────────── */
@@ -3515,12 +3604,19 @@ var Atbash = class _Atbash {
3515
3604
  }
3516
3605
  let chainOpts = options.chainOpts;
3517
3606
  if (options.orgName) {
3518
- const mapNetwork = await this.getActiveNetworkForOrg(options.orgName);
3519
- if (mapNetwork) {
3520
- chainOpts = { network: mapNetwork };
3521
- } else if (!chainOpts?.blockchainRid) {
3522
- const resolved = await this.resolveChainFromMap(options.orgName, null);
3523
- chainOpts = { ...chainOpts, network: resolved.network };
3607
+ const cached = this._chainCache.get(options.orgName);
3608
+ if (cached) {
3609
+ chainOpts = { network: cached.network };
3610
+ } else {
3611
+ const mapNetwork = await this.getActiveNetworkForOrg(options.orgName);
3612
+ if (mapNetwork) {
3613
+ const chain = mapNetwork === "private" ? PRIVATE_CHAIN : PUBLIC_CHAIN;
3614
+ this._chainCache.set(options.orgName, chain);
3615
+ chainOpts = { network: mapNetwork };
3616
+ } else if (!chainOpts?.blockchainRid) {
3617
+ const resolved = await this.resolveChainFromMap(options.orgName, null);
3618
+ chainOpts = { ...chainOpts, network: resolved.network };
3619
+ }
3524
3620
  }
3525
3621
  }
3526
3622
  const brid = this.bridFromChainOpts(chainOpts);
@@ -3969,6 +4065,10 @@ var Atbash = class _Atbash {
3969
4065
  clearChainCache() {
3970
4066
  this._chainCache.clear();
3971
4067
  }
4068
+ /** Drop the short-TTL `/api/ai/exists` cache. Useful in tests. */
4069
+ clearAgentExistsCache() {
4070
+ this._agentExistsCache = null;
4071
+ }
3972
4072
  /* ── internals ─────────────────────────────────────────────────────────── */
3973
4073
  /**
3974
4074
  * Wrap an SDK method body in telemetry — records the call at start
@@ -4071,8 +4171,27 @@ var Atbash = class _Atbash {
4071
4171
  this.endpoint
4072
4172
  );
4073
4173
  }
4074
- /** Wrap a *transport* failure (fetch threw, no response) as an AtbashAPIError. */
4174
+ /**
4175
+ * Wrap a transport failure (fetch threw, no response) as an AtbashAPIError.
4176
+ *
4177
+ * `HttpTransportError.kind` names the cause; the message is already
4178
+ * human-readable. `debug` echoes the original exception so operators can
4179
+ * cross-reference with node / undici logs when a class doesn't match.
4180
+ */
4075
4181
  transportError(err) {
4182
+ if (err instanceof HttpTransportError) {
4183
+ if (this.debug) {
4184
+ this.logger.warn?.(
4185
+ `[atbash] transport failed \u2014 kind=${err.kind}`,
4186
+ {
4187
+ kind: err.kind,
4188
+ cause: err.cause instanceof Error ? err.cause.message : String(err.cause ?? ""),
4189
+ endpoint: this.endpoint
4190
+ }
4191
+ );
4192
+ }
4193
+ return new AtbashAPIError(0, err.message, "", this.endpoint);
4194
+ }
4076
4195
  return new AtbashAPIError(0, errorMessage(err), "", this.endpoint);
4077
4196
  }
4078
4197
  async json(resp) {
@@ -4299,24 +4418,29 @@ async function scanMemory(entry, auth, opts) {
4299
4418
  toolArgsJson: opts?.toolArgsJson ?? JSON.stringify({ key: entry.key, source: entry.source }),
4300
4419
  mode: "memory-scan"
4301
4420
  });
4302
- const knownAction = result.actionType === "allow" || result.actionType === "block" || result.actionType === "hold_for_user_confirm";
4303
- const missingVerdict = result.verdict === "No verdict" && result.status !== "logged";
4304
- const unknownAction = result.actionType !== "" && !knownAction;
4305
- if (missingVerdict || unknownAction) {
4306
- return {
4307
- safe: false,
4308
- verdict: "red",
4309
- reason: unknownAction ? `judge returned unrecognised action_type "${result.actionType}"` : "judge returned no verdict",
4310
- confidence: result.confidence,
4311
- score: native.defaultScoreForVerdict("red"),
4312
- toolCallId: result.toolCallId
4313
- };
4421
+ if (result.verdict === "No verdict" && result.status !== "logged") {
4422
+ throw new Error(
4423
+ `memory scan: judge returned no verdict without an audit-tier marker (status: ${result.status || "absent"})`
4424
+ );
4314
4425
  }
4315
- const verdict = native.mapVerdict(
4316
- result.actionType,
4426
+ const KNOWN_ACTIONS = ["allow", "block", "hold_for_user_confirm"];
4427
+ const action = result.actionType.trim().toLowerCase();
4428
+ if (result.verdict !== "No verdict" && !KNOWN_ACTIONS.includes(action)) {
4429
+ throw new Error(
4430
+ `memory scan: unrecognized action_type from judge (${result.actionType || "absent"})`
4431
+ );
4432
+ }
4433
+ const mapped = native.mapVerdict(
4434
+ action,
4317
4435
  result.confidence,
4318
4436
  threshold
4319
4437
  );
4438
+ let verdict = mapped;
4439
+ if (result.verdict === "BLOCK") {
4440
+ verdict = "red";
4441
+ } else if (result.verdict === "HOLD" && mapped === "green") {
4442
+ verdict = "yellow";
4443
+ }
4320
4444
  const parsed = native.parseScoreFromReason(result.reason);
4321
4445
  const score = result.score ?? parsed.score ?? native.defaultScoreForVerdict(verdict);
4322
4446
  return {
@@ -9222,8 +9346,8 @@ Reporter$3.prototype.wrapResult = function wrapResult(result) {
9222
9346
  errors: state2.errors
9223
9347
  };
9224
9348
  };
9225
- function ReporterError$1(path6, msg) {
9226
- this.path = path6;
9349
+ function ReporterError$1(path7, msg) {
9350
+ this.path = path7;
9227
9351
  this.rethrow(msg);
9228
9352
  }
9229
9353
  inherits$v(ReporterError$1, Error);
@@ -29444,8 +29568,8 @@ Reporter.prototype.wrapResult = function wrapResult2(result) {
29444
29568
  errors: state2.errors
29445
29569
  };
29446
29570
  };
29447
- function ReporterError(path6, msg) {
29448
- this.path = path6;
29571
+ function ReporterError(path7, msg) {
29572
+ this.path = path7;
29449
29573
  this.rethrow(msg);
29450
29574
  }
29451
29575
  inherits(ReporterError, Error);
@@ -32475,8 +32599,8 @@ var parseUtil = {};
32475
32599
  const errors_js_12 = errors$3;
32476
32600
  const en_js_12 = __importDefault2(en);
32477
32601
  const makeIssue = (params) => {
32478
- const { data, path: path6, errorMaps, issueData } = params;
32479
- const fullPath = [...path6, ...issueData.path || []];
32602
+ const { data, path: path7, errorMaps, issueData } = params;
32603
+ const fullPath = [...path7, ...issueData.path || []];
32480
32604
  const fullIssue = {
32481
32605
  ...issueData,
32482
32606
  path: fullPath
@@ -32613,11 +32737,11 @@ var errorUtil_js_1 = errorUtil$1;
32613
32737
  var parseUtil_js_1 = parseUtil;
32614
32738
  var util_js_1 = util;
32615
32739
  var ParseInputLazyPath = class {
32616
- constructor(parent, value, path6, key3) {
32740
+ constructor(parent, value, path7, key3) {
32617
32741
  this._cachedPath = [];
32618
32742
  this.parent = parent;
32619
32743
  this.data = value;
32620
- this._path = path6;
32744
+ this._path = path7;
32621
32745
  this._key = key3;
32622
32746
  }
32623
32747
  get path() {
@@ -39523,21 +39647,21 @@ function createTimeoutController(timeout) {
39523
39647
  const timeoutId = setTimeout(() => controller.abort(timeoutError), timeout);
39524
39648
  return { controller, timeoutId };
39525
39649
  }
39526
- function handleRequest(method, path6, endpoint, timeout, postObject) {
39650
+ function handleRequest(method, path7, endpoint, timeout, postObject) {
39527
39651
  return __awaiter$2(this, void 0, void 0, function* () {
39528
39652
  if (method == enums_1$2.Method.GET) {
39529
- return yield get(path6, endpoint, timeout);
39653
+ return yield get(path7, endpoint, timeout);
39530
39654
  } else {
39531
- return yield post(path6, endpoint, timeout, postObject);
39655
+ return yield post(path7, endpoint, timeout, postObject);
39532
39656
  }
39533
39657
  });
39534
39658
  }
39535
- function get(path6, endpoint, timeout) {
39659
+ function get(path7, endpoint, timeout) {
39536
39660
  return __awaiter$2(this, void 0, void 0, function* () {
39537
- logger.debug(`GET URL ${new URL(path6, endpoint).href}`);
39661
+ logger.debug(`GET URL ${new URL(path7, endpoint).href}`);
39538
39662
  try {
39539
39663
  const { controller, timeoutId } = createTimeoutController(timeout);
39540
- const response = yield fetch(new URL(path6, endpoint).href, {
39664
+ const response = yield fetch(new URL(path7, endpoint).href, {
39541
39665
  signal: controller === null || controller === void 0 ? void 0 : controller.signal
39542
39666
  });
39543
39667
  if (timeoutId)
@@ -39575,9 +39699,9 @@ function constructBufferResponseBody(response) {
39575
39699
  return responseText ? responseText : response.statusText;
39576
39700
  });
39577
39701
  }
39578
- function post(path6, endpoint, timeout, requestBody) {
39702
+ function post(path7, endpoint, timeout, requestBody) {
39579
39703
  return __awaiter$2(this, void 0, void 0, function* () {
39580
- logger.debug(`POST URL ${new URL(path6, endpoint).href}`);
39704
+ logger.debug(`POST URL ${new URL(path7, endpoint).href}`);
39581
39705
  logger.debug(`POST body ${JSON.stringify(requestBody)}`);
39582
39706
  if (buffer_1.Buffer.isBuffer(requestBody)) {
39583
39707
  try {
@@ -39591,7 +39715,7 @@ function post(path6, endpoint, timeout, requestBody) {
39591
39715
  },
39592
39716
  signal: controller === null || controller === void 0 ? void 0 : controller.signal
39593
39717
  };
39594
- const response = yield fetch(new URL(path6, endpoint).href, requestOptions);
39718
+ const response = yield fetch(new URL(path7, endpoint).href, requestOptions);
39595
39719
  if (timeoutId)
39596
39720
  clearTimeout(timeoutId);
39597
39721
  const transactionTimestamp = response.headers.get("X-Transaction-Timestamp");
@@ -39602,7 +39726,7 @@ function post(path6, endpoint, timeout, requestBody) {
39602
39726
  } else {
39603
39727
  try {
39604
39728
  const { controller, timeoutId } = createTimeoutController(timeout);
39605
- const response = yield fetch(new URL(path6, endpoint).href, {
39729
+ const response = yield fetch(new URL(path7, endpoint).href, {
39606
39730
  method: "post",
39607
39731
  body: JSON.stringify(requestBody),
39608
39732
  headers: {
@@ -39782,10 +39906,10 @@ function requireFailoverStrategies() {
39782
39906
  }
39783
39907
  }
39784
39908
  function abortOnError(_a2) {
39785
- return __awaiter2(this, arguments, void 0, function* ({ method, path: path6, config: config2, postObject, timeoutOverride }) {
39909
+ return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, timeoutOverride }) {
39786
39910
  return yield retryRequest({
39787
39911
  method,
39788
- path: path6,
39912
+ path: path7,
39789
39913
  config: config2,
39790
39914
  postObject,
39791
39915
  timeoutOverride,
@@ -39796,10 +39920,10 @@ function requireFailoverStrategies() {
39796
39920
  });
39797
39921
  }
39798
39922
  function tryNextOnError(_a2) {
39799
- return __awaiter2(this, arguments, void 0, function* ({ method, path: path6, config: config2, postObject, timeoutOverride }) {
39923
+ return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, timeoutOverride }) {
39800
39924
  return yield retryRequest({
39801
39925
  method,
39802
- path: path6,
39926
+ path: path7,
39803
39927
  config: config2,
39804
39928
  postObject,
39805
39929
  timeoutOverride,
@@ -39815,7 +39939,7 @@ function requireFailoverStrategies() {
39815
39939
  return endpointPoolLength - (endpointPoolLength - 1) / 3;
39816
39940
  }
39817
39941
  function queryMajority(_a2) {
39818
- return __awaiter2(this, arguments, void 0, function* ({ method, path: path6, config: config2, postObject, timeoutOverride }) {
39942
+ return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, timeoutOverride }) {
39819
39943
  var _b;
39820
39944
  const bftMajorityThreshold = calculateBftMajorityThreshold(config2.endpointPool.length);
39821
39945
  const failureThreshold = config2.endpointPool.length - bftMajorityThreshold + 1;
@@ -39826,7 +39950,7 @@ function requireFailoverStrategies() {
39826
39950
  const promises = availableNodes.map((node2) => __awaiter2(this, void 0, void 0, function* () {
39827
39951
  try {
39828
39952
  const requestTimeout = timeoutOverride !== null && timeoutOverride !== void 0 ? timeoutOverride : config2.responseTimeout;
39829
- const response = yield (0, httpUtil_1.handleRequest)(method, path6, node2.url, requestTimeout, postObject);
39953
+ const response = yield (0, httpUtil_1.handleRequest)(method, path7, node2.url, requestTimeout, postObject);
39830
39954
  const { statusCode } = response;
39831
39955
  if (statusCode && (0, http_utils_1.isSuccessfulStatusCode)(statusCode)) {
39832
39956
  outcomes.push({ type: "SUCCESS", result: response });
@@ -39873,7 +39997,7 @@ function requireFailoverStrategies() {
39873
39997
  });
39874
39998
  }
39875
39999
  function singleEndpoint(_a2) {
39876
- return __awaiter2(this, arguments, void 0, function* ({ method, path: path6, config: config2, postObject, timeoutOverride }) {
40000
+ return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, timeoutOverride }) {
39877
40001
  let statusCode = null;
39878
40002
  let rspBody = null;
39879
40003
  let error4 = null;
@@ -39884,7 +40008,7 @@ function requireFailoverStrategies() {
39884
40008
  }
39885
40009
  for (let attempt = 0; attempt < config2.attemptsPerEndpoint; attempt++) {
39886
40010
  const requestTimeout = timeoutOverride !== null && timeoutOverride !== void 0 ? timeoutOverride : config2.responseTimeout;
39887
- const response = yield (0, httpUtil_1.handleRequest)(method, path6, endpoint.url, requestTimeout, postObject);
40011
+ const response = yield (0, httpUtil_1.handleRequest)(method, path7, endpoint.url, requestTimeout, postObject);
39888
40012
  if (response) {
39889
40013
  ({ error: error4, statusCode, rspBody, transactionTimestamp } = response);
39890
40014
  }
@@ -39899,7 +40023,7 @@ function requireFailoverStrategies() {
39899
40023
  });
39900
40024
  }
39901
40025
  function retryRequest(_a2) {
39902
- return __awaiter2(this, arguments, void 0, function* ({ method, path: path6, config: config2, postObject, useNextNodeOnError, recoveryThreshold, timeoutOverride }) {
40026
+ return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, useNextNodeOnError, recoveryThreshold, timeoutOverride }) {
39903
40027
  var _b, _c, _d;
39904
40028
  let statusCode = null;
39905
40029
  let rspBody = null;
@@ -39910,7 +40034,7 @@ function requireFailoverStrategies() {
39910
40034
  for (const node2 of availableNodes) {
39911
40035
  for (let attempt = 0; attempt < config2.attemptsPerEndpoint; attempt++) {
39912
40036
  const requestTimeout = timeoutOverride !== null && timeoutOverride !== void 0 ? timeoutOverride : config2.responseTimeout;
39913
- const response = yield (0, httpUtil_1.handleRequest)(method, path6, node2.url, requestTimeout, postObject);
40037
+ const response = yield (0, httpUtil_1.handleRequest)(method, path7, node2.url, requestTimeout, postObject);
39914
40038
  error4 = (_b = response === null || response === void 0 ? void 0 : response.error) !== null && _b !== void 0 ? _b : null;
39915
40039
  statusCode = (_c = response === null || response === void 0 ? void 0 : response.statusCode) !== null && _c !== void 0 ? _c : null;
39916
40040
  rspBody = (_d = response === null || response === void 0 ? void 0 : response.rspBody) !== null && _d !== void 0 ? _d : null;
@@ -40053,19 +40177,19 @@ function requireRequestWithFailoverStrategy() {
40053
40177
  const enums_12 = enums;
40054
40178
  const failoverStrategies_1 = requireFailoverStrategies();
40055
40179
  function requestWithFailoverStrategy$1(method_1, path_1, config_1, postObject_1) {
40056
- return __awaiter2(this, arguments, void 0, function* (method, path6, config2, postObject, forceSingleEndpoint = false, timeoutOverride) {
40180
+ return __awaiter2(this, arguments, void 0, function* (method, path7, config2, postObject, forceSingleEndpoint = false, timeoutOverride) {
40057
40181
  switch (config2.failoverStrategy) {
40058
40182
  case enums_12.FailoverStrategy.AbortOnError:
40059
- return yield (0, failoverStrategies_1.abortOnError)({ method, path: path6, config: config2, postObject, timeoutOverride });
40183
+ return yield (0, failoverStrategies_1.abortOnError)({ method, path: path7, config: config2, postObject, timeoutOverride });
40060
40184
  case enums_12.FailoverStrategy.TryNextOnError:
40061
- return yield (0, failoverStrategies_1.tryNextOnError)({ method, path: path6, config: config2, postObject, timeoutOverride });
40185
+ return yield (0, failoverStrategies_1.tryNextOnError)({ method, path: path7, config: config2, postObject, timeoutOverride });
40062
40186
  case enums_12.FailoverStrategy.SingleEndpoint:
40063
- return yield (0, failoverStrategies_1.singleEndpoint)({ method, path: path6, config: config2, postObject, timeoutOverride });
40187
+ return yield (0, failoverStrategies_1.singleEndpoint)({ method, path: path7, config: config2, postObject, timeoutOverride });
40064
40188
  case enums_12.FailoverStrategy.QueryMajority:
40065
40189
  if (forceSingleEndpoint) {
40066
- return yield (0, failoverStrategies_1.singleEndpoint)({ method, path: path6, config: config2, postObject, timeoutOverride });
40190
+ return yield (0, failoverStrategies_1.singleEndpoint)({ method, path: path7, config: config2, postObject, timeoutOverride });
40067
40191
  }
40068
- return yield (0, failoverStrategies_1.queryMajority)({ method, path: path6, config: config2, postObject, timeoutOverride });
40192
+ return yield (0, failoverStrategies_1.queryMajority)({ method, path: path7, config: config2, postObject, timeoutOverride });
40069
40193
  default:
40070
40194
  throw new Error(`Unsupported failover strategy: ${config2.failoverStrategy}`);
40071
40195
  }
@@ -41264,7 +41388,7 @@ var networkSettings = {};
41264
41388
  const restNetworkSettingsValidationContext = RestNetworkSettingsSchema.safeParse(networkSettings2);
41265
41389
  if ("error" in restNetworkSettingsValidationContext) {
41266
41390
  const { error: { issues } = {} } = restNetworkSettingsValidationContext;
41267
- const errorMessage2 = issues === null || issues === void 0 ? void 0 : issues.map(({ message, path: path6 }) => `${path6[0]}: ${message}`).join(", ");
41391
+ const errorMessage2 = issues === null || issues === void 0 ? void 0 : issues.map(({ message, path: path7 }) => `${path7[0]}: ${message}`).join(", ");
41268
41392
  if (throwOnError) {
41269
41393
  throw new Error(errorMessage2);
41270
41394
  }
@@ -42646,6 +42770,7 @@ function classifyMemoryWrite(event, ctx, opts = {}) {
42646
42770
  }
42647
42771
 
42648
42772
  // src-ts/memory/guard.ts
42773
+ import path3 from "path";
42649
42774
  function emitDebugProbe(event, ctx, memEntry, logger2) {
42650
42775
  if (!logger2?.info) return;
42651
42776
  const ev = event ?? {};
@@ -42682,7 +42807,8 @@ async function guardMemoryWrite(input) {
42682
42807
  toolNames,
42683
42808
  enforce = true,
42684
42809
  debug: debug2 = false,
42685
- logger: logger2
42810
+ logger: logger2,
42811
+ memoryFilePath
42686
42812
  } = input;
42687
42813
  const memEntry = classifyMemoryWrite(event, ctx, { patterns, toolNames });
42688
42814
  if (debug2) emitDebugProbe(event, ctx, memEntry, logger2);
@@ -42718,17 +42844,28 @@ async function guardMemoryWrite(input) {
42718
42844
  committed: false
42719
42845
  };
42720
42846
  }
42721
- commitMemoryVersion(memEntry.value, auth, {
42722
- score: scanResult.score,
42723
- orgName,
42724
- endpoint
42725
- }).catch((err) => {
42726
- const reason = err instanceof Error ? err.message : String(err);
42727
- logger2?.warn?.("[atbash] memory commit to chain failed", {
42728
- path: memEntry.key,
42729
- reason
42847
+ const isManagedMemoryFile = memoryFilePath !== void 0 && path3.resolve(memEntry.key) === path3.resolve(memoryFilePath);
42848
+ if (isManagedMemoryFile) {
42849
+ commitMemoryVersion(memEntry.value, auth, {
42850
+ score: scanResult.score,
42851
+ orgName,
42852
+ endpoint
42853
+ }).catch((err) => {
42854
+ const reason = err instanceof Error ? err.message : String(err);
42855
+ logger2?.warn?.("[atbash] memory commit to chain failed", {
42856
+ path: memEntry.key,
42857
+ reason
42858
+ });
42730
42859
  });
42731
- });
42860
+ } else {
42861
+ logger2?.info?.(
42862
+ "[atbash] scanned but not committed \u2014 not the managed memory file",
42863
+ {
42864
+ path: memEntry.key,
42865
+ memoryFilePath: memoryFilePath ?? "(not configured)"
42866
+ }
42867
+ );
42868
+ }
42732
42869
  logger2?.info?.(
42733
42870
  scanResult.verdict === "yellow" ? "[atbash] memory HOLD" : "[atbash] memory ALLOW",
42734
42871
  { path: memEntry.key, score: scanResult.score, reason: scanResult.reason }
@@ -42737,7 +42874,7 @@ async function guardMemoryWrite(input) {
42737
42874
  handled: true,
42738
42875
  decision: { allow: true },
42739
42876
  scanResult,
42740
- committed: true
42877
+ committed: isManagedMemoryFile
42741
42878
  };
42742
42879
  }
42743
42880
 
@@ -42756,26 +42893,26 @@ async function syncLocalMemory(auth, pointer, opts = {}) {
42756
42893
  const now = Date.now();
42757
42894
  const withinTtl = !opts.force && now - pointer.checkedAt < ttl;
42758
42895
  if (withinTtl) {
42759
- return { drifted: false, pointer };
42896
+ return { drifted: false, checked: false, pointer };
42760
42897
  }
42761
42898
  const currentId = await getActiveMemoryId(auth, opts.chainOpts);
42762
42899
  const nextPointer = { activeId: currentId, checkedAt: now };
42763
42900
  if (currentId === pointer.activeId) {
42764
- return { drifted: false, pointer: nextPointer };
42901
+ return { drifted: false, checked: true, pointer: nextPointer };
42765
42902
  }
42766
42903
  if (currentId === null) {
42767
- return { drifted: true, current: null, pointer: nextPointer };
42904
+ return { drifted: true, checked: true, current: null, pointer: nextPointer };
42768
42905
  }
42769
42906
  const row = await getMemoryById(currentId, auth, opts.chainOpts);
42770
42907
  if (row.decryptError) {
42771
42908
  throw new MemoryIntegrityError(currentId, row.decryptError);
42772
42909
  }
42773
- return { drifted: true, current: row, pointer: nextPointer };
42910
+ return { drifted: true, checked: true, current: row, pointer: nextPointer };
42774
42911
  }
42775
42912
 
42776
42913
  // src-ts/memory/pointer-store.ts
42777
42914
  import { promises as fs } from "fs";
42778
- import path3 from "path";
42915
+ import path4 from "path";
42779
42916
  var EMPTY = { version: 1, agents: {} };
42780
42917
  var PointerStore = class {
42781
42918
  constructor(filePath) {
@@ -42817,19 +42954,19 @@ var PointerStore = class {
42817
42954
  this.cache = { ...EMPTY, agents: {} };
42818
42955
  }
42819
42956
  async persist(file) {
42820
- await fs.mkdir(path3.dirname(this.filePath), { recursive: true });
42957
+ await fs.mkdir(path4.dirname(this.filePath), { recursive: true });
42821
42958
  const tmp = `${this.filePath}.${process.pid}.tmp`;
42822
42959
  await fs.writeFile(tmp, JSON.stringify(file, null, 2), "utf8");
42823
42960
  await fs.rename(tmp, this.filePath);
42824
42961
  }
42825
42962
  };
42826
42963
  function defaultPointerPath(workspaceDir = process.cwd()) {
42827
- return path3.join(workspaceDir, ".atbash", "memory-pointer.json");
42964
+ return path4.join(workspaceDir, ".atbash", "memory-pointer.json");
42828
42965
  }
42829
42966
 
42830
42967
  // src-ts/memory/file-logger.ts
42831
42968
  import { promises as fs2 } from "fs";
42832
- import path4 from "path";
42969
+ import path5 from "path";
42833
42970
  function formatMeta(meta) {
42834
42971
  if (!meta || Object.keys(meta).length === 0) return "";
42835
42972
  try {
@@ -42841,7 +42978,7 @@ function formatMeta(meta) {
42841
42978
  function createFileLogger(filePath, upstream) {
42842
42979
  let queue = Promise.resolve();
42843
42980
  async function ensureDir() {
42844
- await fs2.mkdir(path4.dirname(filePath), { recursive: true });
42981
+ await fs2.mkdir(path5.dirname(filePath), { recursive: true });
42845
42982
  }
42846
42983
  function append(level, message, meta) {
42847
42984
  const line = `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${message}${formatMeta(meta)}
@@ -42861,7 +42998,7 @@ function createFileLogger(filePath, upstream) {
42861
42998
  };
42862
42999
  }
42863
43000
  function defaultPluginLogPath(workspaceDir = process.cwd()) {
42864
- return path4.join(workspaceDir, ".atbash", "plugin.log");
43001
+ return path5.join(workspaceDir, ".atbash", "plugin.log");
42865
43002
  }
42866
43003
 
42867
43004
  // src-ts/memory/read-classifier.ts
@@ -42876,13 +43013,13 @@ function classifyMemoryRead(event, ctx, opts = {}) {
42876
43013
 
42877
43014
  // src-ts/memory/guard-manager.ts
42878
43015
  import { promises as fs3 } from "fs";
42879
- import path5 from "path";
43016
+ import path6 from "path";
42880
43017
  var DEFAULT_SYNC_TTL_MS = 3e4;
42881
43018
  var MemoryGuardManager = class {
42882
43019
  constructor(opts) {
42883
43020
  this.opts = opts;
42884
43021
  const workspaceDir = opts.workspaceDir;
42885
- this.memoryFilePath = opts.memoryFilePath ?? path5.join(workspaceDir, "MEMORY.md");
43022
+ this.memoryFilePath = opts.memoryFilePath ?? path6.join(workspaceDir, "MEMORY.md");
42886
43023
  this.pointerStore = new PointerStore(opts.pointerFilePath ?? defaultPointerPath(workspaceDir));
42887
43024
  this.logger = createFileLogger(
42888
43025
  opts.logFilePath ?? defaultPluginLogPath(workspaceDir),
@@ -42912,7 +43049,11 @@ var MemoryGuardManager = class {
42912
43049
  async runBootProbe() {
42913
43050
  try {
42914
43051
  const seed = { activeId: null, checkedAt: 0 };
42915
- const result = await syncLocalMemory(this.opts.auth, seed, { ttlMs: 0, force: true });
43052
+ const result = await syncLocalMemory(this.opts.auth, seed, {
43053
+ ttlMs: 0,
43054
+ force: true,
43055
+ chainOpts: this.opts.chainOpts
43056
+ });
42916
43057
  if (!result.drifted && result.pointer.activeId == null) {
42917
43058
  this.logger.info(
42918
43059
  `[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.`
@@ -42944,15 +43085,19 @@ var MemoryGuardManager = class {
42944
43085
  }
42945
43086
  }
42946
43087
  /**
42947
- * Returns a `HookDecision` when the event is a memory read or write
42948
- * (host returns it verbatim to its runtime). Returns `null` when the
42949
- * event isn't memory-related — host falls through to its own audit.
43088
+ * Returns a `HookDecision` when the guard reached a decision about this event.
43089
+ * Returns `null` when it did not — either the event isn't memory-related, or it
43090
+ * is but the guard could not check it. In both cases the host falls through to
43091
+ * its own audit.
43092
+ *
43093
+ * A returned decision carries `audited` (see `HookDecision`). Only
43094
+ * `{ allow: true, audited: true }` means "checked and cleared"; anything else
43095
+ * that allows is a call the host still needs to judge.
42950
43096
  */
42951
43097
  async handleBeforeToolCall(event, ctx) {
42952
43098
  if (classifyMemoryRead(event, ctx, this.opts.memoryReadClassifier)) {
42953
43099
  this.logger.info("[atbash] memory read intercepted \u2014 running sync check");
42954
- const readDecision = await this.handleMemoryRead();
42955
- return readDecision ?? { allow: true };
43100
+ return await this.handleMemoryRead(event, ctx);
42956
43101
  }
42957
43102
  const guardLogger = {
42958
43103
  info: (msg, meta) => this.logger.info(msg, meta && typeof meta === "object" ? meta : void 0),
@@ -42969,7 +43114,9 @@ var MemoryGuardManager = class {
42969
43114
  toolNames: this.opts.memoryWriteToolNames,
42970
43115
  enforce: this.enforce,
42971
43116
  debug: this.opts.debug,
42972
- logger: guardLogger
43117
+ logger: guardLogger,
43118
+ // Only this file may reach the single, path-less chain memory slot.
43119
+ memoryFilePath: this.memoryFilePath
42973
43120
  });
42974
43121
  return this.mapGuardResult(guard);
42975
43122
  }
@@ -42987,30 +43134,81 @@ var MemoryGuardManager = class {
42987
43134
  block: true,
42988
43135
  blockReason: d.reason ?? "",
42989
43136
  allow: false,
42990
- reason: d.reason
43137
+ reason: d.reason,
43138
+ // A block IS a decision — the most thoroughly checked one the guard
43139
+ // makes. Without this a host following the documented `!audited ->
43140
+ // judge it yourself` rule would re-judge its way past a red scan.
43141
+ audited: true,
43142
+ ...sr2 ? { verdict: sr2.verdict } : {}
42991
43143
  };
42992
43144
  }
42993
43145
  this.logger.info(
42994
43146
  `[atbash] guardMemoryWrite ALLOWED \u2014 verdict=${verdict} score=${score} committed=${guard.committed === true}`
42995
43147
  );
42996
- return { allow: true };
43148
+ if (sr2 === void 0) {
43149
+ return { allow: true, audited: false, reason: "memory scan did not run (observe mode)" };
43150
+ }
43151
+ if (sr2.verdict !== "green") {
43152
+ return {
43153
+ allow: true,
43154
+ audited: false,
43155
+ verdict: sr2.verdict,
43156
+ reason: `memory scan returned ${sr2.verdict} but this guard is not enforcing it`
43157
+ };
43158
+ }
43159
+ return { allow: true, audited: true, verdict: sr2.verdict };
42997
43160
  }
42998
- async handleMemoryRead() {
43161
+ /**
43162
+ * Whether the pointer state this manager tracks actually describes the file
43163
+ * this call is about to read.
43164
+ *
43165
+ * The classifier fires on nine patterns — including the bare tokens
43166
+ * `"memory/"`, `"CLAUDE.md"` and `"AGENTS.md"` — but the sync path only ever
43167
+ * reads, refreshes, or vouches for `this.memoryFilePath`. Without this check a
43168
+ * read of `/repo/CLAUDE.md` (or any path merely containing `memory/`) would
43169
+ * receive an `audited: true` for a file the guard never opened.
43170
+ *
43171
+ * Conservative on purpose: every path-shaped value found must resolve to the
43172
+ * managed file. If none is found, or any one differs, the answer is no. That
43173
+ * also covers events carrying two different path keys, where the classifier
43174
+ * and the host could otherwise disagree about which one is authoritative.
43175
+ */
43176
+ vouchesForTarget(event, ctx) {
43177
+ const KEYS = ["path", "file_path", "filePath", "notebook_path", "notebookPath", "target"];
43178
+ const found = [];
43179
+ for (const src of [event, ctx]) {
43180
+ for (const bag of [src, src?.params]) {
43181
+ if (!bag || typeof bag !== "object") continue;
43182
+ const rec = bag;
43183
+ for (const k of KEYS) {
43184
+ if (typeof rec[k] === "string" && rec[k]) found.push(rec[k]);
43185
+ }
43186
+ }
43187
+ }
43188
+ if (found.length === 0) return false;
43189
+ const managed = path6.resolve(this.memoryFilePath);
43190
+ return found.every((p) => path6.resolve(p) === managed);
43191
+ }
43192
+ async handleMemoryRead(event, ctx) {
42999
43193
  const pointer = await this.pointerStore.get(this.agentPubkeyHex);
43000
43194
  let result;
43001
43195
  try {
43002
- result = await syncLocalMemory(this.opts.auth, pointer, { ttlMs: this.ttlMs });
43196
+ result = await syncLocalMemory(this.opts.auth, pointer, {
43197
+ ttlMs: this.ttlMs,
43198
+ chainOpts: this.opts.chainOpts
43199
+ });
43003
43200
  } catch (err) {
43004
43201
  if (err instanceof MemoryIntegrityError) {
43005
43202
  const reason = `Memory integrity check failed on id ${err.id} \u2014 read blocked.`;
43006
43203
  this.logger.warn("[atbash] MEMORY INTEGRITY FAILURE", { id: err.id, error: err.message });
43007
43204
  if (!this.enforce) return null;
43008
- return { block: true, blockReason: reason, allow: false, reason };
43205
+ return { block: true, blockReason: reason, allow: false, reason, audited: true };
43009
43206
  }
43010
43207
  const msg = err instanceof Error ? err.message : String(err);
43011
43208
  this.logger.warn("[atbash] memory sync failed (serving local copy)", { error: msg });
43012
43209
  return null;
43013
43210
  }
43211
+ let onDiskIsCurrent = result.checked;
43014
43212
  if (result.drifted) {
43015
43213
  const fresh = result.current;
43016
43214
  if (fresh) {
@@ -43018,7 +43216,7 @@ var MemoryGuardManager = class {
43018
43216
  const reason = `Rolled-back memory version #${fresh.id} scored ${fresh.score} (below threshold ${this.rollbackMinScore}) \u2014 read blocked.`;
43019
43217
  this.logger.warn("[atbash] blocking read on low-score rollback", { id: fresh.id, score: fresh.score });
43020
43218
  if (!this.enforce) return null;
43021
- return { block: true, blockReason: reason, allow: false, reason };
43219
+ return { block: true, blockReason: reason, allow: false, reason, audited: true };
43022
43220
  }
43023
43221
  this.logger.info("[atbash] memory drift detected \u2014 refreshing local file", {
43024
43222
  id: fresh.id,
@@ -43029,16 +43227,26 @@ var MemoryGuardManager = class {
43029
43227
  } catch (err) {
43030
43228
  const msg = err instanceof Error ? err.message : String(err);
43031
43229
  this.logger.warn("[atbash] failed to write refreshed memory (serving old)", { error: msg });
43230
+ onDiskIsCurrent = false;
43032
43231
  }
43033
43232
  } else {
43034
43233
  this.logger.info("[atbash] active memory removed on chain", { pubkey: this.agentPubkeyHex });
43234
+ onDiskIsCurrent = false;
43035
43235
  }
43036
43236
  }
43037
- await this.pointerStore.set(this.agentPubkeyHex, result.pointer);
43038
- return null;
43237
+ if (onDiskIsCurrent) {
43238
+ await this.pointerStore.set(this.agentPubkeyHex, result.pointer);
43239
+ } else {
43240
+ this.logger.warn(
43241
+ "[atbash] not advancing memory pointer \u2014 local file is stale or revoked; reads stay unaudited until it is refreshed"
43242
+ );
43243
+ }
43244
+ if (!onDiskIsCurrent) return null;
43245
+ if (!this.vouchesForTarget(event, ctx)) return null;
43246
+ return { allow: true, audited: true };
43039
43247
  }
43040
43248
  async writeMemoryAtomic(content) {
43041
- await fs3.mkdir(path5.dirname(this.memoryFilePath), { recursive: true });
43249
+ await fs3.mkdir(path6.dirname(this.memoryFilePath), { recursive: true });
43042
43250
  const tmp = `${this.memoryFilePath}.${process.pid}.tmp`;
43043
43251
  await fs3.writeFile(tmp, content, "utf8");
43044
43252
  await fs3.rename(tmp, this.memoryFilePath);
@@ -43176,6 +43384,8 @@ export {
43176
43384
  DEFAULT_MEMORY_READ_TOOL_NAMES,
43177
43385
  DEFAULT_MEMORY_WRITE_TOOL_NAMES,
43178
43386
  EciesDomain,
43387
+ HttpClient,
43388
+ HttpTransportError,
43179
43389
  KEY_FILENAMES,
43180
43390
  MemoryGuardManager,
43181
43391
  MemoryIntegrityError,