@atbash/sdk 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -2995,8 +2995,8 @@ var HttpClient = class {
2995
2995
  this.baseUrl = baseUrl.replace(/\/+$/, "");
2996
2996
  this.timeoutMs = timeoutMs;
2997
2997
  }
2998
- buildUrl(path3, query) {
2999
- const url = new URL(this.baseUrl + path3);
2998
+ buildUrl(path6, query) {
2999
+ const url = new URL(this.baseUrl + path6);
3000
3000
  if (query) {
3001
3001
  for (const [k, v] of Object.entries(query)) {
3002
3002
  if (v !== void 0 && v !== null && v !== "") {
@@ -3006,14 +3006,14 @@ var HttpClient = class {
3006
3006
  }
3007
3007
  return url.toString();
3008
3008
  }
3009
- async get(path3, query, headers) {
3010
- return this.fetch(this.buildUrl(path3, query), {
3009
+ async get(path6, query, headers) {
3010
+ return this.fetch(this.buildUrl(path6, query), {
3011
3011
  method: "GET",
3012
3012
  ...headers && { headers }
3013
3013
  });
3014
3014
  }
3015
- async post(path3, body, headers) {
3016
- return this.fetch(this.buildUrl(path3), {
3015
+ async post(path6, body, headers) {
3016
+ return this.fetch(this.buildUrl(path6), {
3017
3017
  method: "POST",
3018
3018
  headers: { "Content-Type": "application/json", ...headers },
3019
3019
  body: JSON.stringify(body)
@@ -3326,13 +3326,22 @@ var Atbash = class _Atbash {
3326
3326
  return this.auth.privkey;
3327
3327
  }
3328
3328
  /* ── agent existence (/api/ai/exists) ──────────────────────────────────── */
3329
- /** GET /api/ai/exists?pubkey=… — defaults to this client's pubkey. */
3330
- async checkAgentExists(pubkey) {
3329
+ /**
3330
+ * `GET /api/ai/exists?pubkey=…[&network=…]` — defaults to this client's
3331
+ * pubkey. Pass `opts.network` when the caller already knows which
3332
+ * network the agent lives on (e.g. after resolving via `orgName`) so
3333
+ * the dashboard queries that chain directly instead of falling back
3334
+ * across public → private, which double-round-trips and can return
3335
+ * false negatives when the fallback chain client is misconfigured.
3336
+ */
3337
+ async checkAgentExists(pubkey, opts) {
3331
3338
  const pk = pubkey ?? this.auth.pubkey;
3332
3339
  return this.track("checkAgentExists", pk, async () => {
3340
+ const query = { pubkey: pk };
3341
+ if (opts?.network) query.network = opts.network;
3333
3342
  const resp = await this.http.get(
3334
3343
  "/api/ai/exists",
3335
- { pubkey: pk },
3344
+ query,
3336
3345
  this.authHeaders()
3337
3346
  );
3338
3347
  await this.raiseIfError(resp);
@@ -3350,7 +3359,9 @@ var Atbash = class _Atbash {
3350
3359
  recordCall("logToolCall", void 0, this.auth.pubkey);
3351
3360
  let exists;
3352
3361
  try {
3353
- exists = await this.checkAgentExists();
3362
+ exists = await this.checkAgentExists(this.auth.pubkey, {
3363
+ network: options.chainOpts?.network
3364
+ });
3354
3365
  } catch (err) {
3355
3366
  recordDuration("logToolCall", performance.now() - start, "error");
3356
3367
  return { success: false, toolCallId: null, error: errorMessage(err) };
@@ -3364,7 +3375,7 @@ var Atbash = class _Atbash {
3364
3375
  };
3365
3376
  }
3366
3377
  const toolCallId = generateToolCallId();
3367
- const brid = options.chainOpts?.blockchainRid ?? this.blockchainRid;
3378
+ const brid = this.bridFromChainOpts(options.chainOpts);
3368
3379
  try {
3369
3380
  const signedHex = native.signLogToolCall(
3370
3381
  toolCallId,
@@ -3475,6 +3486,8 @@ var Atbash = class _Atbash {
3475
3486
  }
3476
3487
  }
3477
3488
  const data = parseJson(bodyBytes);
3489
+ const rawScore = data.score;
3490
+ const score = typeof rawScore === "number" && Number.isInteger(rawScore) && rawScore >= 1 && rawScore <= 10 ? rawScore : void 0;
3478
3491
  return {
3479
3492
  verdict: normalizeVerdict(data.verdict),
3480
3493
  actionType: String(data.action_type ?? ""),
@@ -3485,7 +3498,8 @@ var Atbash = class _Atbash {
3485
3498
  toolCallId: String(data.tool_call_id ?? logResult.toolCallId),
3486
3499
  onChain: Boolean(data.on_chain),
3487
3500
  enforced: Boolean(data.enforced),
3488
- enforcementMode: String(data.enforcement_mode ?? "")
3501
+ enforcementMode: String(data.enforcement_mode ?? ""),
3502
+ score
3489
3503
  };
3490
3504
  }
3491
3505
  /* ── audit_tool_call (redact → judge → decision) ───────────────────────── */
@@ -4113,13 +4127,13 @@ function verifyJudgeResponseSignature(bodyBytes, signatureHex, pubKeyHex) {
4113
4127
  }
4114
4128
 
4115
4129
  // src-ts/memory/crypto.ts
4116
- function deriveMemoryKey(privkey) {
4130
+ async function deriveMemoryKey(privkey) {
4117
4131
  return native.deriveMemoryKey(privkey);
4118
4132
  }
4119
- function encryptMemoryContent(plaintext, key3) {
4133
+ async function encryptMemoryContent(plaintext, key3) {
4120
4134
  return native.encryptMemoryContent(plaintext, key3);
4121
4135
  }
4122
- function decryptMemoryContent(ciphertext, nonce, key3) {
4136
+ async function decryptMemoryContent(ciphertext, nonce, key3) {
4123
4137
  return native.decryptMemoryContent(ciphertext, nonce, key3);
4124
4138
  }
4125
4139
 
@@ -4213,7 +4227,7 @@ async function scanMemory(entry, auth, opts) {
4213
4227
  });
4214
4228
  const verdict = mapVerdict(result.actionType, result.confidence, threshold);
4215
4229
  const { score: parsedScore, cleanReason } = parseScoreFromReason(result.reason);
4216
- const score = parsedScore ?? defaultScoreForVerdict(verdict);
4230
+ const score = result.score ?? parsedScore ?? defaultScoreForVerdict(verdict);
4217
4231
  if (prefilter && prefilter.verdict === "yellow" && verdict === "green") {
4218
4232
  return {
4219
4233
  safe: false,
@@ -9127,8 +9141,8 @@ Reporter$3.prototype.wrapResult = function wrapResult(result) {
9127
9141
  errors: state2.errors
9128
9142
  };
9129
9143
  };
9130
- function ReporterError$1(path3, msg) {
9131
- this.path = path3;
9144
+ function ReporterError$1(path6, msg) {
9145
+ this.path = path6;
9132
9146
  this.rethrow(msg);
9133
9147
  }
9134
9148
  inherits$v(ReporterError$1, Error);
@@ -29349,8 +29363,8 @@ Reporter.prototype.wrapResult = function wrapResult2(result) {
29349
29363
  errors: state2.errors
29350
29364
  };
29351
29365
  };
29352
- function ReporterError(path3, msg) {
29353
- this.path = path3;
29366
+ function ReporterError(path6, msg) {
29367
+ this.path = path6;
29354
29368
  this.rethrow(msg);
29355
29369
  }
29356
29370
  inherits(ReporterError, Error);
@@ -32380,8 +32394,8 @@ var parseUtil = {};
32380
32394
  const errors_js_12 = errors$3;
32381
32395
  const en_js_12 = __importDefault2(en);
32382
32396
  const makeIssue = (params) => {
32383
- const { data, path: path3, errorMaps, issueData } = params;
32384
- const fullPath = [...path3, ...issueData.path || []];
32397
+ const { data, path: path6, errorMaps, issueData } = params;
32398
+ const fullPath = [...path6, ...issueData.path || []];
32385
32399
  const fullIssue = {
32386
32400
  ...issueData,
32387
32401
  path: fullPath
@@ -32518,11 +32532,11 @@ var errorUtil_js_1 = errorUtil$1;
32518
32532
  var parseUtil_js_1 = parseUtil;
32519
32533
  var util_js_1 = util;
32520
32534
  var ParseInputLazyPath = class {
32521
- constructor(parent, value, path3, key3) {
32535
+ constructor(parent, value, path6, key3) {
32522
32536
  this._cachedPath = [];
32523
32537
  this.parent = parent;
32524
32538
  this.data = value;
32525
- this._path = path3;
32539
+ this._path = path6;
32526
32540
  this._key = key3;
32527
32541
  }
32528
32542
  get path() {
@@ -39428,21 +39442,21 @@ function createTimeoutController(timeout) {
39428
39442
  const timeoutId = setTimeout(() => controller.abort(timeoutError), timeout);
39429
39443
  return { controller, timeoutId };
39430
39444
  }
39431
- function handleRequest(method, path3, endpoint, timeout, postObject) {
39445
+ function handleRequest(method, path6, endpoint, timeout, postObject) {
39432
39446
  return __awaiter$2(this, void 0, void 0, function* () {
39433
39447
  if (method == enums_1$2.Method.GET) {
39434
- return yield get(path3, endpoint, timeout);
39448
+ return yield get(path6, endpoint, timeout);
39435
39449
  } else {
39436
- return yield post(path3, endpoint, timeout, postObject);
39450
+ return yield post(path6, endpoint, timeout, postObject);
39437
39451
  }
39438
39452
  });
39439
39453
  }
39440
- function get(path3, endpoint, timeout) {
39454
+ function get(path6, endpoint, timeout) {
39441
39455
  return __awaiter$2(this, void 0, void 0, function* () {
39442
- logger.debug(`GET URL ${new URL(path3, endpoint).href}`);
39456
+ logger.debug(`GET URL ${new URL(path6, endpoint).href}`);
39443
39457
  try {
39444
39458
  const { controller, timeoutId } = createTimeoutController(timeout);
39445
- const response = yield fetch(new URL(path3, endpoint).href, {
39459
+ const response = yield fetch(new URL(path6, endpoint).href, {
39446
39460
  signal: controller === null || controller === void 0 ? void 0 : controller.signal
39447
39461
  });
39448
39462
  if (timeoutId)
@@ -39480,9 +39494,9 @@ function constructBufferResponseBody(response) {
39480
39494
  return responseText ? responseText : response.statusText;
39481
39495
  });
39482
39496
  }
39483
- function post(path3, endpoint, timeout, requestBody) {
39497
+ function post(path6, endpoint, timeout, requestBody) {
39484
39498
  return __awaiter$2(this, void 0, void 0, function* () {
39485
- logger.debug(`POST URL ${new URL(path3, endpoint).href}`);
39499
+ logger.debug(`POST URL ${new URL(path6, endpoint).href}`);
39486
39500
  logger.debug(`POST body ${JSON.stringify(requestBody)}`);
39487
39501
  if (buffer_1.Buffer.isBuffer(requestBody)) {
39488
39502
  try {
@@ -39496,7 +39510,7 @@ function post(path3, endpoint, timeout, requestBody) {
39496
39510
  },
39497
39511
  signal: controller === null || controller === void 0 ? void 0 : controller.signal
39498
39512
  };
39499
- const response = yield fetch(new URL(path3, endpoint).href, requestOptions);
39513
+ const response = yield fetch(new URL(path6, endpoint).href, requestOptions);
39500
39514
  if (timeoutId)
39501
39515
  clearTimeout(timeoutId);
39502
39516
  const transactionTimestamp = response.headers.get("X-Transaction-Timestamp");
@@ -39507,7 +39521,7 @@ function post(path3, endpoint, timeout, requestBody) {
39507
39521
  } else {
39508
39522
  try {
39509
39523
  const { controller, timeoutId } = createTimeoutController(timeout);
39510
- const response = yield fetch(new URL(path3, endpoint).href, {
39524
+ const response = yield fetch(new URL(path6, endpoint).href, {
39511
39525
  method: "post",
39512
39526
  body: JSON.stringify(requestBody),
39513
39527
  headers: {
@@ -39687,10 +39701,10 @@ function requireFailoverStrategies() {
39687
39701
  }
39688
39702
  }
39689
39703
  function abortOnError(_a2) {
39690
- return __awaiter2(this, arguments, void 0, function* ({ method, path: path3, config: config2, postObject, timeoutOverride }) {
39704
+ return __awaiter2(this, arguments, void 0, function* ({ method, path: path6, config: config2, postObject, timeoutOverride }) {
39691
39705
  return yield retryRequest({
39692
39706
  method,
39693
- path: path3,
39707
+ path: path6,
39694
39708
  config: config2,
39695
39709
  postObject,
39696
39710
  timeoutOverride,
@@ -39701,10 +39715,10 @@ function requireFailoverStrategies() {
39701
39715
  });
39702
39716
  }
39703
39717
  function tryNextOnError(_a2) {
39704
- return __awaiter2(this, arguments, void 0, function* ({ method, path: path3, config: config2, postObject, timeoutOverride }) {
39718
+ return __awaiter2(this, arguments, void 0, function* ({ method, path: path6, config: config2, postObject, timeoutOverride }) {
39705
39719
  return yield retryRequest({
39706
39720
  method,
39707
- path: path3,
39721
+ path: path6,
39708
39722
  config: config2,
39709
39723
  postObject,
39710
39724
  timeoutOverride,
@@ -39720,7 +39734,7 @@ function requireFailoverStrategies() {
39720
39734
  return endpointPoolLength - (endpointPoolLength - 1) / 3;
39721
39735
  }
39722
39736
  function queryMajority(_a2) {
39723
- return __awaiter2(this, arguments, void 0, function* ({ method, path: path3, config: config2, postObject, timeoutOverride }) {
39737
+ return __awaiter2(this, arguments, void 0, function* ({ method, path: path6, config: config2, postObject, timeoutOverride }) {
39724
39738
  var _b;
39725
39739
  const bftMajorityThreshold = calculateBftMajorityThreshold(config2.endpointPool.length);
39726
39740
  const failureThreshold = config2.endpointPool.length - bftMajorityThreshold + 1;
@@ -39731,7 +39745,7 @@ function requireFailoverStrategies() {
39731
39745
  const promises = availableNodes.map((node2) => __awaiter2(this, void 0, void 0, function* () {
39732
39746
  try {
39733
39747
  const requestTimeout = timeoutOverride !== null && timeoutOverride !== void 0 ? timeoutOverride : config2.responseTimeout;
39734
- const response = yield (0, httpUtil_1.handleRequest)(method, path3, node2.url, requestTimeout, postObject);
39748
+ const response = yield (0, httpUtil_1.handleRequest)(method, path6, node2.url, requestTimeout, postObject);
39735
39749
  const { statusCode } = response;
39736
39750
  if (statusCode && (0, http_utils_1.isSuccessfulStatusCode)(statusCode)) {
39737
39751
  outcomes.push({ type: "SUCCESS", result: response });
@@ -39778,7 +39792,7 @@ function requireFailoverStrategies() {
39778
39792
  });
39779
39793
  }
39780
39794
  function singleEndpoint(_a2) {
39781
- return __awaiter2(this, arguments, void 0, function* ({ method, path: path3, config: config2, postObject, timeoutOverride }) {
39795
+ return __awaiter2(this, arguments, void 0, function* ({ method, path: path6, config: config2, postObject, timeoutOverride }) {
39782
39796
  let statusCode = null;
39783
39797
  let rspBody = null;
39784
39798
  let error4 = null;
@@ -39789,7 +39803,7 @@ function requireFailoverStrategies() {
39789
39803
  }
39790
39804
  for (let attempt = 0; attempt < config2.attemptsPerEndpoint; attempt++) {
39791
39805
  const requestTimeout = timeoutOverride !== null && timeoutOverride !== void 0 ? timeoutOverride : config2.responseTimeout;
39792
- const response = yield (0, httpUtil_1.handleRequest)(method, path3, endpoint.url, requestTimeout, postObject);
39806
+ const response = yield (0, httpUtil_1.handleRequest)(method, path6, endpoint.url, requestTimeout, postObject);
39793
39807
  if (response) {
39794
39808
  ({ error: error4, statusCode, rspBody, transactionTimestamp } = response);
39795
39809
  }
@@ -39804,7 +39818,7 @@ function requireFailoverStrategies() {
39804
39818
  });
39805
39819
  }
39806
39820
  function retryRequest(_a2) {
39807
- return __awaiter2(this, arguments, void 0, function* ({ method, path: path3, config: config2, postObject, useNextNodeOnError, recoveryThreshold, timeoutOverride }) {
39821
+ return __awaiter2(this, arguments, void 0, function* ({ method, path: path6, config: config2, postObject, useNextNodeOnError, recoveryThreshold, timeoutOverride }) {
39808
39822
  var _b, _c, _d;
39809
39823
  let statusCode = null;
39810
39824
  let rspBody = null;
@@ -39815,7 +39829,7 @@ function requireFailoverStrategies() {
39815
39829
  for (const node2 of availableNodes) {
39816
39830
  for (let attempt = 0; attempt < config2.attemptsPerEndpoint; attempt++) {
39817
39831
  const requestTimeout = timeoutOverride !== null && timeoutOverride !== void 0 ? timeoutOverride : config2.responseTimeout;
39818
- const response = yield (0, httpUtil_1.handleRequest)(method, path3, node2.url, requestTimeout, postObject);
39832
+ const response = yield (0, httpUtil_1.handleRequest)(method, path6, node2.url, requestTimeout, postObject);
39819
39833
  error4 = (_b = response === null || response === void 0 ? void 0 : response.error) !== null && _b !== void 0 ? _b : null;
39820
39834
  statusCode = (_c = response === null || response === void 0 ? void 0 : response.statusCode) !== null && _c !== void 0 ? _c : null;
39821
39835
  rspBody = (_d = response === null || response === void 0 ? void 0 : response.rspBody) !== null && _d !== void 0 ? _d : null;
@@ -39958,19 +39972,19 @@ function requireRequestWithFailoverStrategy() {
39958
39972
  const enums_12 = enums;
39959
39973
  const failoverStrategies_1 = requireFailoverStrategies();
39960
39974
  function requestWithFailoverStrategy$1(method_1, path_1, config_1, postObject_1) {
39961
- return __awaiter2(this, arguments, void 0, function* (method, path3, config2, postObject, forceSingleEndpoint = false, timeoutOverride) {
39975
+ return __awaiter2(this, arguments, void 0, function* (method, path6, config2, postObject, forceSingleEndpoint = false, timeoutOverride) {
39962
39976
  switch (config2.failoverStrategy) {
39963
39977
  case enums_12.FailoverStrategy.AbortOnError:
39964
- return yield (0, failoverStrategies_1.abortOnError)({ method, path: path3, config: config2, postObject, timeoutOverride });
39978
+ return yield (0, failoverStrategies_1.abortOnError)({ method, path: path6, config: config2, postObject, timeoutOverride });
39965
39979
  case enums_12.FailoverStrategy.TryNextOnError:
39966
- return yield (0, failoverStrategies_1.tryNextOnError)({ method, path: path3, config: config2, postObject, timeoutOverride });
39980
+ return yield (0, failoverStrategies_1.tryNextOnError)({ method, path: path6, config: config2, postObject, timeoutOverride });
39967
39981
  case enums_12.FailoverStrategy.SingleEndpoint:
39968
- return yield (0, failoverStrategies_1.singleEndpoint)({ method, path: path3, config: config2, postObject, timeoutOverride });
39982
+ return yield (0, failoverStrategies_1.singleEndpoint)({ method, path: path6, config: config2, postObject, timeoutOverride });
39969
39983
  case enums_12.FailoverStrategy.QueryMajority:
39970
39984
  if (forceSingleEndpoint) {
39971
- return yield (0, failoverStrategies_1.singleEndpoint)({ method, path: path3, config: config2, postObject, timeoutOverride });
39985
+ return yield (0, failoverStrategies_1.singleEndpoint)({ method, path: path6, config: config2, postObject, timeoutOverride });
39972
39986
  }
39973
- return yield (0, failoverStrategies_1.queryMajority)({ method, path: path3, config: config2, postObject, timeoutOverride });
39987
+ return yield (0, failoverStrategies_1.queryMajority)({ method, path: path6, config: config2, postObject, timeoutOverride });
39974
39988
  default:
39975
39989
  throw new Error(`Unsupported failover strategy: ${config2.failoverStrategy}`);
39976
39990
  }
@@ -41169,7 +41183,7 @@ var networkSettings = {};
41169
41183
  const restNetworkSettingsValidationContext = RestNetworkSettingsSchema.safeParse(networkSettings2);
41170
41184
  if ("error" in restNetworkSettingsValidationContext) {
41171
41185
  const { error: { issues } = {} } = restNetworkSettingsValidationContext;
41172
- const errorMessage2 = issues === null || issues === void 0 ? void 0 : issues.map(({ message, path: path3 }) => `${path3[0]}: ${message}`).join(", ");
41186
+ const errorMessage2 = issues === null || issues === void 0 ? void 0 : issues.map(({ message, path: path6 }) => `${path6[0]}: ${message}`).join(", ");
41173
41187
  if (throwOnError) {
41174
41188
  throw new Error(errorMessage2);
41175
41189
  }
@@ -42414,8 +42428,8 @@ async function commitMemoryVersion(plaintext, auth, opts) {
42414
42428
  "commitMemoryVersion: score must be an integer in [1, 10]"
42415
42429
  );
42416
42430
  }
42417
- const key3 = deriveMemoryKey(auth.privkey);
42418
- const { ciphertext, nonce } = encryptMemoryContent(plaintext, key3);
42431
+ const key3 = await deriveMemoryKey(auth.privkey);
42432
+ const { ciphertext, nonce } = await encryptMemoryContent(plaintext, key3);
42419
42433
  const chainOpts = await resolveChainOptsForOrg(opts, auth);
42420
42434
  const client = await buildChainClient(chainOpts);
42421
42435
  const { keyPair, sigProvider } = buildSigner(auth);
@@ -42441,13 +42455,13 @@ function toBuf(val) {
42441
42455
  }
42442
42456
  throw new Error("toBuf: unsupported byte_array shape from chain");
42443
42457
  }
42444
- function decryptRow(row, key3) {
42458
+ async function decryptRow(row, key3) {
42445
42459
  const ciphertext = toBuf(row.content_cipher);
42446
42460
  const nonce = toBuf(row.nonce);
42447
42461
  let content;
42448
42462
  let decryptError;
42449
42463
  try {
42450
- content = decryptMemoryContent(ciphertext, nonce, key3);
42464
+ content = await decryptMemoryContent(ciphertext, nonce, key3);
42451
42465
  } catch (err) {
42452
42466
  content = "";
42453
42467
  decryptError = err instanceof Error ? err.message : String(err);
@@ -42464,36 +42478,43 @@ function decryptRow(row, key3) {
42464
42478
  updatedAt: row.updated_at ?? row.created_at
42465
42479
  };
42466
42480
  }
42481
+ async function getActiveMemoryId(auth, chainOpts) {
42482
+ const client = await buildChainClient(chainOpts);
42483
+ const raw2 = await client.query("get_active_memory_id", {
42484
+ agent_pubkey: auth.pubkey
42485
+ });
42486
+ return raw2 ?? null;
42487
+ }
42467
42488
  async function getActiveMemory(auth, chainOpts) {
42468
42489
  const client = await buildChainClient(chainOpts);
42469
- const key3 = deriveMemoryKey(auth.privkey);
42490
+ const key3 = await deriveMemoryKey(auth.privkey);
42470
42491
  const rows = await client.query("get_agent_memory", {
42471
42492
  agent_pubkey: auth.pubkey
42472
42493
  });
42473
- return rows.map((r2) => decryptRow(r2, key3));
42494
+ return Promise.all(rows.map((r2) => decryptRow(r2, key3)));
42474
42495
  }
42475
42496
  async function getAllAgentMemory(auth, chainOpts) {
42476
42497
  const client = await buildChainClient(chainOpts);
42477
- const key3 = deriveMemoryKey(auth.privkey);
42498
+ const key3 = await deriveMemoryKey(auth.privkey);
42478
42499
  const rows = await client.query("get_all_agent_memory", {
42479
42500
  agent_pubkey: auth.pubkey
42480
42501
  });
42481
- return rows.map((r2) => decryptRow(r2, key3));
42502
+ return Promise.all(rows.map((r2) => decryptRow(r2, key3)));
42482
42503
  }
42483
42504
  async function getMemoryHistory(auth, chainOpts) {
42484
42505
  const client = await buildChainClient(chainOpts);
42485
- const key3 = deriveMemoryKey(auth.privkey);
42506
+ const key3 = await deriveMemoryKey(auth.privkey);
42486
42507
  const rows = await client.query("get_agent_memory_history", {
42487
42508
  agent_pubkey: auth.pubkey
42488
42509
  });
42489
- return rows.map((r2) => decryptRow(r2, key3));
42510
+ return Promise.all(rows.map((r2) => decryptRow(r2, key3)));
42490
42511
  }
42491
42512
  async function getMemoryById(id, auth, chainOpts) {
42492
42513
  if (!Number.isInteger(id) || id < 1) {
42493
42514
  throw new Error("getMemoryById: id must be a positive integer");
42494
42515
  }
42495
42516
  const client = await buildChainClient(chainOpts);
42496
- const key3 = deriveMemoryKey(auth.privkey);
42517
+ const key3 = await deriveMemoryKey(auth.privkey);
42497
42518
  const row = await client.query("get_agent_memory_by_id", {
42498
42519
  agent_pubkey: auth.pubkey,
42499
42520
  id
@@ -42543,7 +42564,10 @@ var DEFAULT_MEMORY_PATH_PATTERNS = [
42543
42564
  "/.openclaw/memory/",
42544
42565
  "/.claude/projects/",
42545
42566
  "/memory/",
42567
+ // Also match workspace-relative writes like `memory/2026-07-29.md`.
42568
+ "memory/",
42546
42569
  "Memory.md",
42570
+ "DREAMS.md",
42547
42571
  "CLAUDE.md",
42548
42572
  "AGENTS.md"
42549
42573
  ];
@@ -42593,8 +42617,8 @@ function pickContent(toolName, args) {
42593
42617
  }
42594
42618
  return "";
42595
42619
  }
42596
- function matchesMemoryPath(path3, patterns) {
42597
- const pLower = path3.toLowerCase();
42620
+ function matchesMemoryPath(path6, patterns) {
42621
+ const pLower = path6.toLowerCase();
42598
42622
  for (const p of patterns) {
42599
42623
  if (p && pLower.includes(p.toLowerCase())) return true;
42600
42624
  }
@@ -42610,13 +42634,13 @@ function classifyMemoryWrite(event, ctx, opts = {}) {
42610
42634
  const toolNamesLower = toolNames.map((t) => t.toLowerCase());
42611
42635
  if (!toolNamesLower.includes(toolNameLower)) return null;
42612
42636
  const args = ev.params ?? c.params ?? ev.args ?? c.args ?? ev.arguments ?? c.arguments;
42613
- const path3 = pickPath(args);
42614
- if (!path3) return null;
42615
- if (!matchesMemoryPath(path3, patterns)) return null;
42637
+ const path6 = pickPath(args);
42638
+ if (!path6) return null;
42639
+ if (!matchesMemoryPath(path6, patterns)) return null;
42616
42640
  const value = pickContent(toolName, args);
42617
42641
  if (!value) return null;
42618
42642
  return {
42619
- key: path3,
42643
+ key: path6,
42620
42644
  value,
42621
42645
  source: `plugin:${toolName}`
42622
42646
  };
@@ -42718,6 +42742,349 @@ async function guardMemoryWrite(input) {
42718
42742
  };
42719
42743
  }
42720
42744
 
42745
+ // src-ts/memory/sync.ts
42746
+ var MemoryIntegrityError = class extends Error {
42747
+ constructor(id, reason) {
42748
+ super(`memory integrity check failed on id ${id}: ${reason}`);
42749
+ this.id = id;
42750
+ this.name = "MemoryIntegrityError";
42751
+ }
42752
+ id;
42753
+ };
42754
+ var DEFAULT_TTL_MS = 3e4;
42755
+ async function syncLocalMemory(auth, pointer, opts = {}) {
42756
+ const ttl = opts.ttlMs ?? DEFAULT_TTL_MS;
42757
+ const now = Date.now();
42758
+ const withinTtl = !opts.force && now - pointer.checkedAt < ttl;
42759
+ if (withinTtl) {
42760
+ return { drifted: false, pointer };
42761
+ }
42762
+ const currentId = await getActiveMemoryId(auth, opts.chainOpts);
42763
+ const nextPointer = { activeId: currentId, checkedAt: now };
42764
+ if (currentId === pointer.activeId) {
42765
+ return { drifted: false, pointer: nextPointer };
42766
+ }
42767
+ if (currentId === null) {
42768
+ return { drifted: true, current: null, pointer: nextPointer };
42769
+ }
42770
+ const row = await getMemoryById(currentId, auth, opts.chainOpts);
42771
+ if (row.decryptError) {
42772
+ throw new MemoryIntegrityError(currentId, row.decryptError);
42773
+ }
42774
+ return { drifted: true, current: row, pointer: nextPointer };
42775
+ }
42776
+
42777
+ // src-ts/memory/pointer-store.ts
42778
+ import { promises as fs } from "fs";
42779
+ import path3 from "path";
42780
+ var EMPTY = { version: 1, agents: {} };
42781
+ var PointerStore = class {
42782
+ constructor(filePath) {
42783
+ this.filePath = filePath;
42784
+ }
42785
+ filePath;
42786
+ cache = null;
42787
+ loading = null;
42788
+ /** Resolves the pointer for `agentPubkeyHex`, or a zero-pointer that will force a sync on first use. */
42789
+ async get(agentPubkeyHex) {
42790
+ await this.ensureLoaded();
42791
+ return this.cache.agents[agentPubkeyHex] ?? { activeId: null, checkedAt: 0 };
42792
+ }
42793
+ /** Persists an updated pointer. Failures are swallowed to a logger callback (if provided) so sync never blocks the caller. */
42794
+ async set(agentPubkeyHex, pointer, onError) {
42795
+ await this.ensureLoaded();
42796
+ this.cache.agents[agentPubkeyHex] = pointer;
42797
+ try {
42798
+ await this.persist(this.cache);
42799
+ } catch (err) {
42800
+ onError?.(err instanceof Error ? err : new Error(String(err)));
42801
+ }
42802
+ }
42803
+ async ensureLoaded() {
42804
+ if (this.cache) return;
42805
+ if (!this.loading) this.loading = this.loadOnce();
42806
+ await this.loading;
42807
+ }
42808
+ async loadOnce() {
42809
+ try {
42810
+ const raw2 = await fs.readFile(this.filePath, "utf8");
42811
+ const parsed = JSON.parse(raw2);
42812
+ if (parsed && parsed.version === 1 && parsed.agents && typeof parsed.agents === "object") {
42813
+ this.cache = parsed;
42814
+ return;
42815
+ }
42816
+ } catch {
42817
+ }
42818
+ this.cache = { ...EMPTY, agents: {} };
42819
+ }
42820
+ async persist(file) {
42821
+ await fs.mkdir(path3.dirname(this.filePath), { recursive: true });
42822
+ const tmp = `${this.filePath}.${process.pid}.tmp`;
42823
+ await fs.writeFile(tmp, JSON.stringify(file, null, 2), "utf8");
42824
+ await fs.rename(tmp, this.filePath);
42825
+ }
42826
+ };
42827
+ function defaultPointerPath(workspaceDir = process.cwd()) {
42828
+ return path3.join(workspaceDir, ".atbash", "memory-pointer.json");
42829
+ }
42830
+
42831
+ // src-ts/memory/file-logger.ts
42832
+ import { promises as fs2 } from "fs";
42833
+ import path4 from "path";
42834
+ function formatMeta(meta) {
42835
+ if (!meta || Object.keys(meta).length === 0) return "";
42836
+ try {
42837
+ return " " + JSON.stringify(meta);
42838
+ } catch {
42839
+ return "";
42840
+ }
42841
+ }
42842
+ function createFileLogger(filePath, upstream) {
42843
+ let queue = Promise.resolve();
42844
+ async function ensureDir() {
42845
+ await fs2.mkdir(path4.dirname(filePath), { recursive: true });
42846
+ }
42847
+ function append(level, message, meta) {
42848
+ const line = `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${message}${formatMeta(meta)}
42849
+ `;
42850
+ queue = queue.then(ensureDir).then(() => fs2.appendFile(filePath, line, "utf8")).catch(() => {
42851
+ });
42852
+ }
42853
+ return {
42854
+ info(message, meta) {
42855
+ upstream?.info(message, meta ?? {});
42856
+ append("info", message, meta);
42857
+ },
42858
+ warn(message, meta) {
42859
+ upstream?.warn(message, meta ?? {});
42860
+ append("warn", message, meta);
42861
+ }
42862
+ };
42863
+ }
42864
+ function defaultPluginLogPath(workspaceDir = process.cwd()) {
42865
+ return path4.join(workspaceDir, ".atbash", "plugin.log");
42866
+ }
42867
+
42868
+ // src-ts/memory/read-classifier.ts
42869
+ var DEFAULT_MEMORY_READ_TOOL_NAMES = [
42870
+ "memory_search",
42871
+ "memory_get"
42872
+ ];
42873
+ var DEFAULT_READ_TOOL_NAMES = [
42874
+ "read",
42875
+ "read_file"
42876
+ ];
42877
+ function extractToolName(event, ctx) {
42878
+ const ev = event ?? {};
42879
+ const c = ctx ?? {};
42880
+ return (ev.toolName ?? c.tool?.name ?? c.toolName ?? c.name ?? "").toString();
42881
+ }
42882
+ function extractPath(event, ctx) {
42883
+ const ev = event ?? {};
42884
+ const c = ctx ?? {};
42885
+ const args = ev.args ?? ev.params ?? ev.arguments ?? c.args ?? c.params ?? {};
42886
+ for (const k of ["path", "file_path", "filePath", "target", "file"]) {
42887
+ const v = args[k];
42888
+ if (typeof v === "string" && v.length > 0) return v;
42889
+ }
42890
+ return "";
42891
+ }
42892
+ function matchesMemoryPath2(path6, patterns) {
42893
+ const p = path6.toLowerCase();
42894
+ for (const pat of patterns) {
42895
+ if (pat && p.includes(pat.toLowerCase())) return true;
42896
+ }
42897
+ return false;
42898
+ }
42899
+ function classifyMemoryRead(event, ctx, opts = {}) {
42900
+ const toolName = extractToolName(event, ctx).toLowerCase();
42901
+ if (!toolName) return false;
42902
+ const readTools = new Set(
42903
+ (opts.readToolNames ?? DEFAULT_MEMORY_READ_TOOL_NAMES).map((s2) => s2.toLowerCase())
42904
+ );
42905
+ if (readTools.has(toolName)) return true;
42906
+ const genericReadTools = new Set(
42907
+ (opts.genericReadToolNames ?? DEFAULT_READ_TOOL_NAMES).map((s2) => s2.toLowerCase())
42908
+ );
42909
+ if (genericReadTools.has(toolName)) {
42910
+ const path6 = extractPath(event, ctx);
42911
+ if (!path6) return false;
42912
+ const patterns = opts.patterns ? [...DEFAULT_MEMORY_PATH_PATTERNS, ...opts.patterns] : DEFAULT_MEMORY_PATH_PATTERNS;
42913
+ return matchesMemoryPath2(path6, patterns);
42914
+ }
42915
+ return false;
42916
+ }
42917
+
42918
+ // src-ts/memory/guard-manager.ts
42919
+ import { promises as fs3 } from "fs";
42920
+ import path5 from "path";
42921
+ var DEFAULT_SYNC_TTL_MS = 3e4;
42922
+ var MemoryGuardManager = class {
42923
+ constructor(opts) {
42924
+ this.opts = opts;
42925
+ const workspaceDir = opts.workspaceDir;
42926
+ this.memoryFilePath = opts.memoryFilePath ?? path5.join(workspaceDir, "MEMORY.md");
42927
+ this.pointerStore = new PointerStore(opts.pointerFilePath ?? defaultPointerPath(workspaceDir));
42928
+ this.logger = createFileLogger(
42929
+ opts.logFilePath ?? defaultPluginLogPath(workspaceDir),
42930
+ opts.hostLogger
42931
+ );
42932
+ this.ttlMs = opts.ttlMs ?? DEFAULT_SYNC_TTL_MS;
42933
+ this.rollbackMinScore = opts.rollbackMinScore ?? 1;
42934
+ this.enforce = opts.enforce !== false;
42935
+ this.agentPubkeyHex = opts.auth.pubkey;
42936
+ this.logger.info(
42937
+ `[atbash] guard manager ready \u2014 agent=${this.agentPubkeyHex.slice(0, 16)}\u2026 org=${opts.orgName ?? "(none)"} memoryFilePath=${this.memoryFilePath} ttl=${this.ttlMs}ms minScore=${this.rollbackMinScore}`
42938
+ );
42939
+ }
42940
+ opts;
42941
+ pointerStore;
42942
+ logger;
42943
+ memoryFilePath;
42944
+ ttlMs;
42945
+ rollbackMinScore;
42946
+ enforce;
42947
+ agentPubkeyHex;
42948
+ /**
42949
+ * One-shot chain probe at plugin registration. Refreshes MEMORY.md
42950
+ * from chain when drifted and score passes threshold. Fire-and-forget
42951
+ * — errors are logged, never thrown.
42952
+ */
42953
+ async runBootProbe() {
42954
+ try {
42955
+ const seed = { activeId: null, checkedAt: 0 };
42956
+ const result = await syncLocalMemory(this.opts.auth, seed, { ttlMs: 0, force: true });
42957
+ if (!result.drifted && result.pointer.activeId == null) {
42958
+ this.logger.info(
42959
+ `[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.`
42960
+ );
42961
+ } else if (result.drifted && result.current) {
42962
+ if (result.current.score < this.rollbackMinScore) {
42963
+ this.logger.warn(
42964
+ `[atbash] boot sync REFUSED refresh \u2014 id=${result.current.id} score=${result.current.score} below threshold ${this.rollbackMinScore}. Leaving MEMORY.md and pointer untouched; next memory read will be blocked.`
42965
+ );
42966
+ return;
42967
+ }
42968
+ this.logger.info(
42969
+ `[atbash] boot sync: refreshing local memory \u2014 id=${result.current.id} score=${result.current.score}`
42970
+ );
42971
+ try {
42972
+ await this.writeMemoryAtomic(result.current.content);
42973
+ } catch (err) {
42974
+ const msg = err instanceof Error ? err.message : String(err);
42975
+ this.logger.warn("[atbash] boot sync write failed (serving whatever's on disk)", { error: msg });
42976
+ }
42977
+ }
42978
+ await this.pointerStore.set(this.agentPubkeyHex, result.pointer);
42979
+ } catch (err) {
42980
+ const msg = err instanceof Error ? err.message : String(err);
42981
+ this.logger.warn("[atbash] boot memory sync failed \u2014 check chain endpoint / orgName", { error: msg });
42982
+ }
42983
+ }
42984
+ /**
42985
+ * Returns a `HookDecision` when the event is a memory read or write
42986
+ * (host returns it verbatim to its runtime). Returns `null` when the
42987
+ * event isn't memory-related — host falls through to its own audit.
42988
+ */
42989
+ async handleBeforeToolCall(event, ctx) {
42990
+ if (classifyMemoryRead(event, ctx, this.opts.memoryReadClassifier)) {
42991
+ this.logger.info("[atbash] memory read intercepted \u2014 running sync check");
42992
+ return this.handleMemoryRead();
42993
+ }
42994
+ const guardLogger = {
42995
+ info: (msg, meta) => this.logger.info(msg, meta && typeof meta === "object" ? meta : void 0),
42996
+ warn: (msg, meta) => this.logger.warn(msg, meta && typeof meta === "object" ? meta : void 0)
42997
+ };
42998
+ const guard = await guardMemoryWrite({
42999
+ event,
43000
+ ctx,
43001
+ auth: this.opts.auth,
43002
+ endpoint: this.opts.judgeEndpoint,
43003
+ verifyPubKey: this.opts.judgeVerifyPubKey,
43004
+ orgName: this.opts.orgName,
43005
+ patterns: this.opts.memoryPathPatterns,
43006
+ toolNames: this.opts.memoryWriteToolNames,
43007
+ enforce: this.enforce,
43008
+ debug: this.opts.debug,
43009
+ logger: guardLogger
43010
+ });
43011
+ return this.mapGuardResult(guard);
43012
+ }
43013
+ mapGuardResult(guard) {
43014
+ if (!guard.handled) return null;
43015
+ const d = guard.decision;
43016
+ const sr2 = guard.scanResult;
43017
+ const verdict = sr2?.verdict ?? "?";
43018
+ const score = sr2?.score ?? "?";
43019
+ if (d.block) {
43020
+ this.logger.warn(
43021
+ `[atbash] guardMemoryWrite BLOCKED \u2014 verdict=${verdict} score=${score} reason=${(d.reason ?? "").slice(0, 200)}`
43022
+ );
43023
+ return {
43024
+ block: true,
43025
+ blockReason: d.reason ?? "",
43026
+ allow: false,
43027
+ reason: d.reason
43028
+ };
43029
+ }
43030
+ this.logger.info(
43031
+ `[atbash] guardMemoryWrite ALLOWED \u2014 verdict=${verdict} score=${score} committed=${guard.committed === true}`
43032
+ );
43033
+ return { allow: true };
43034
+ }
43035
+ async handleMemoryRead() {
43036
+ const pointer = await this.pointerStore.get(this.agentPubkeyHex);
43037
+ let result;
43038
+ try {
43039
+ result = await syncLocalMemory(this.opts.auth, pointer, { ttlMs: this.ttlMs });
43040
+ } catch (err) {
43041
+ if (err instanceof MemoryIntegrityError) {
43042
+ const reason = `Memory integrity check failed on id ${err.id} \u2014 read blocked.`;
43043
+ this.logger.warn("[atbash] MEMORY INTEGRITY FAILURE", { id: err.id, error: err.message });
43044
+ if (!this.enforce) return null;
43045
+ return { block: true, blockReason: reason, allow: false, reason };
43046
+ }
43047
+ const msg = err instanceof Error ? err.message : String(err);
43048
+ this.logger.warn("[atbash] memory sync failed (serving local copy)", { error: msg });
43049
+ return null;
43050
+ }
43051
+ if (result.drifted) {
43052
+ const fresh = result.current;
43053
+ if (fresh) {
43054
+ if (fresh.score < this.rollbackMinScore) {
43055
+ const reason = `Rolled-back memory version #${fresh.id} scored ${fresh.score} (below threshold ${this.rollbackMinScore}) \u2014 read blocked.`;
43056
+ this.logger.warn("[atbash] blocking read on low-score rollback", { id: fresh.id, score: fresh.score });
43057
+ if (!this.enforce) return null;
43058
+ return { block: true, blockReason: reason, allow: false, reason };
43059
+ }
43060
+ this.logger.info("[atbash] memory drift detected \u2014 refreshing local file", {
43061
+ id: fresh.id,
43062
+ score: fresh.score
43063
+ });
43064
+ try {
43065
+ await this.writeMemoryAtomic(fresh.content);
43066
+ } catch (err) {
43067
+ const msg = err instanceof Error ? err.message : String(err);
43068
+ this.logger.warn("[atbash] failed to write refreshed memory (serving old)", { error: msg });
43069
+ }
43070
+ } else {
43071
+ this.logger.info("[atbash] active memory removed on chain", { pubkey: this.agentPubkeyHex });
43072
+ }
43073
+ }
43074
+ await this.pointerStore.set(this.agentPubkeyHex, result.pointer);
43075
+ return null;
43076
+ }
43077
+ async writeMemoryAtomic(content) {
43078
+ await fs3.mkdir(path5.dirname(this.memoryFilePath), { recursive: true });
43079
+ const tmp = `${this.memoryFilePath}.${process.pid}.tmp`;
43080
+ await fs3.writeFile(tmp, content, "utf8");
43081
+ await fs3.rename(tmp, this.memoryFilePath);
43082
+ }
43083
+ };
43084
+ function createMemoryGuardManager(opts) {
43085
+ return new MemoryGuardManager(opts);
43086
+ }
43087
+
42721
43088
  // src-ts/index.ts
42722
43089
  function isValidPrivateKey(hex) {
42723
43090
  return native.isValidPrivateKey(hex);
@@ -42780,14 +43147,23 @@ export {
42780
43147
  DEFAULT_CHROMIA_NODE_URLS,
42781
43148
  DEFAULT_ENDPOINT,
42782
43149
  DEFAULT_MEMORY_PATH_PATTERNS,
43150
+ DEFAULT_MEMORY_READ_TOOL_NAMES,
42783
43151
  DEFAULT_MEMORY_WRITE_TOOL_NAMES,
43152
+ MemoryGuardManager,
43153
+ MemoryIntegrityError,
43154
+ PointerStore,
42784
43155
  SignatureVerificationError,
43156
+ classifyMemoryRead,
42785
43157
  classifyMemoryWrite,
42786
43158
  commitMemoryVersion,
42787
43159
  containsEvasionCharacters,
42788
43160
  containsSecret,
43161
+ createFileLogger,
43162
+ createMemoryGuardManager,
42789
43163
  createMemorySnapshot,
42790
43164
  decryptMemoryContent,
43165
+ defaultPluginLogPath,
43166
+ defaultPointerPath,
42791
43167
  deriveMemoryKey,
42792
43168
  derivePublicKey,
42793
43169
  diffMemorySnapshots,
@@ -42795,6 +43171,7 @@ export {
42795
43171
  flushTelemetry,
42796
43172
  generateKeypair,
42797
43173
  getActiveMemory,
43174
+ getActiveMemoryId,
42798
43175
  getAllAgentMemory,
42799
43176
  getConfigDir,
42800
43177
  getConfigPath,
@@ -42824,6 +43201,7 @@ export {
42824
43201
  shutdownTelemetry,
42825
43202
  signJudgeAction,
42826
43203
  signLogToolCall,
43204
+ syncLocalMemory,
42827
43205
  validateJudgeEndpoint,
42828
43206
  verifyJudgeResponseSignature,
42829
43207
  verifySignature