@atbash/sdk 0.10.9-dev.0 → 0.10.11-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/README.md +12 -2
- package/dist/browser.d.mts +116 -24
- package/dist/browser.mjs +164 -83
- package/dist/browser.mjs.map +1 -1
- package/dist/index.d.mts +116 -24
- package/dist/index.d.ts +116 -24
- package/dist/index.js +288 -124
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +288 -124
- package/dist/index.mjs.map +1 -1
- package/index.d.ts +0 -2
- package/index.js +0 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -3111,8 +3111,8 @@ var HttpClient = class {
|
|
|
3111
3111
|
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
3112
3112
|
this.timeoutMs = timeoutMs;
|
|
3113
3113
|
}
|
|
3114
|
-
buildUrl(
|
|
3115
|
-
const url = new URL(this.baseUrl +
|
|
3114
|
+
buildUrl(path7, query) {
|
|
3115
|
+
const url = new URL(this.baseUrl + path7);
|
|
3116
3116
|
if (query) {
|
|
3117
3117
|
for (const [k, v] of Object.entries(query)) {
|
|
3118
3118
|
if (v !== void 0 && v !== null && v !== "") {
|
|
@@ -3122,14 +3122,14 @@ var HttpClient = class {
|
|
|
3122
3122
|
}
|
|
3123
3123
|
return url.toString();
|
|
3124
3124
|
}
|
|
3125
|
-
async get(
|
|
3126
|
-
return this.fetch(this.buildUrl(
|
|
3125
|
+
async get(path7, query, headers) {
|
|
3126
|
+
return this.fetch(this.buildUrl(path7, query), {
|
|
3127
3127
|
method: "GET",
|
|
3128
3128
|
...headers && { headers }
|
|
3129
3129
|
});
|
|
3130
3130
|
}
|
|
3131
|
-
async post(
|
|
3132
|
-
return this.fetch(this.buildUrl(
|
|
3131
|
+
async post(path7, body, headers) {
|
|
3132
|
+
return this.fetch(this.buildUrl(path7), {
|
|
3133
3133
|
method: "POST",
|
|
3134
3134
|
headers: { "Content-Type": "application/json", ...headers },
|
|
3135
3135
|
body: JSON.stringify(body)
|
|
@@ -3303,6 +3303,10 @@ var callCounter = null;
|
|
|
3303
3303
|
var durationHistogram = null;
|
|
3304
3304
|
var defaultSource = "sdk";
|
|
3305
3305
|
function isTelemetryOptedOut() {
|
|
3306
|
+
const disabled = process.env.ATBASH_TELEMETRY_DISABLED?.trim().toLowerCase();
|
|
3307
|
+
if (disabled && ["1", "true", "yes", "on"].includes(disabled)) {
|
|
3308
|
+
return true;
|
|
3309
|
+
}
|
|
3306
3310
|
try {
|
|
3307
3311
|
const home2 = process.env.HOME || (0, import_node_os2.homedir)() || "";
|
|
3308
3312
|
const filePath = (0, import_node_path2.join)(home2, ".config", "atbash", "telemetry.json");
|
|
@@ -3323,14 +3327,14 @@ function setupTelemetry(config2) {
|
|
|
3323
3327
|
if (!config2.enabled) return;
|
|
3324
3328
|
if (meterProvider) return;
|
|
3325
3329
|
if (isTelemetryOptedOut()) return;
|
|
3330
|
+
if (!config2.endpoint || !config2.getAuthHeaders) return;
|
|
3331
|
+
if (/^https?:\/\/(localhost|127\.0\.0\.1|0\.0\.0\.0)(:|\/|$)/i.test(config2.endpoint)) return;
|
|
3326
3332
|
defaultSource = config2.source ?? "sdk";
|
|
3327
|
-
const
|
|
3328
|
-
|
|
3333
|
+
const proxyUrl = `${config2.endpoint.replace(/\/+$/, "")}/api/telemetry`;
|
|
3334
|
+
const getAuthHeaders = config2.getAuthHeaders;
|
|
3329
3335
|
const exporter = new import_exporter_metrics_otlp_http.OTLPMetricExporter({
|
|
3330
|
-
url:
|
|
3331
|
-
headers:
|
|
3332
|
-
"x-honeycomb-team": apiKey
|
|
3333
|
-
}
|
|
3336
|
+
url: proxyUrl,
|
|
3337
|
+
headers: async () => getAuthHeaders()
|
|
3334
3338
|
});
|
|
3335
3339
|
const reader = new import_sdk_metrics.PeriodicExportingMetricReader({
|
|
3336
3340
|
exporter,
|
|
@@ -3462,6 +3466,16 @@ var Atbash = class _Atbash {
|
|
|
3462
3466
|
* calls don't re-hit the dashboard. Cleared by `clearChainCache()`.
|
|
3463
3467
|
*/
|
|
3464
3468
|
_chainCache = /* @__PURE__ */ new Map();
|
|
3469
|
+
/**
|
|
3470
|
+
* Short-TTL cache for `/api/ai/exists`. The `registered` field is
|
|
3471
|
+
* monotonic (once true, stays true), so most calls in a burst re-fetch
|
|
3472
|
+
* data that hasn't changed. The `org_encryption_pubkey` field CAN change
|
|
3473
|
+
* — an org toggling encryption mid-session — so the TTL is deliberately
|
|
3474
|
+
* short (see `AGENT_EXISTS_TTL_MS`). Keyed by (pubkey, network) so
|
|
3475
|
+
* cross-agent / cross-network calls don't collide.
|
|
3476
|
+
*/
|
|
3477
|
+
_agentExistsCache = null;
|
|
3478
|
+
static AGENT_EXISTS_TTL_MS = 5e3;
|
|
3465
3479
|
/**
|
|
3466
3480
|
* Cached bearer token for risk-engine / insurance read calls. Built
|
|
3467
3481
|
* lazily as a signed `log_tool_call` tx and refreshed every 4 min so
|
|
@@ -3489,6 +3503,16 @@ var Atbash = class _Atbash {
|
|
|
3489
3503
|
verifying: this.verifyPubKey ? "with response-signature pubkey configured" : "without signature verification"
|
|
3490
3504
|
});
|
|
3491
3505
|
}
|
|
3506
|
+
try {
|
|
3507
|
+
setupTelemetry({
|
|
3508
|
+
enabled: true,
|
|
3509
|
+
source: "sdk",
|
|
3510
|
+
endpoint: this.endpoint,
|
|
3511
|
+
getAuthHeaders: () => this.authHeaders()
|
|
3512
|
+
});
|
|
3513
|
+
} catch (err) {
|
|
3514
|
+
this.logger.warn?.("[atbash] telemetry setup failed \u2014 continuing without metrics", { error: String(err) });
|
|
3515
|
+
}
|
|
3492
3516
|
}
|
|
3493
3517
|
/**
|
|
3494
3518
|
* Say which environment this build talks to, once per process.
|
|
@@ -3561,9 +3585,18 @@ var Atbash = class _Atbash {
|
|
|
3561
3585
|
*/
|
|
3562
3586
|
async checkAgentExists(pubkey, opts) {
|
|
3563
3587
|
const pk = pubkey ?? this.auth.pubkey;
|
|
3588
|
+
const network = opts?.network;
|
|
3589
|
+
const now = Date.now();
|
|
3590
|
+
const cached = this._agentExistsCache;
|
|
3591
|
+
if (cached && cached.pubkey === pk && cached.network === network && cached.expiresAt > now) {
|
|
3592
|
+
if (pk === this.auth.pubkey) {
|
|
3593
|
+
this._orgKeyFromChain = cached.orgKey;
|
|
3594
|
+
}
|
|
3595
|
+
return cached.registered;
|
|
3596
|
+
}
|
|
3564
3597
|
return this.track("checkAgentExists", pk, async () => {
|
|
3565
3598
|
const query = { pubkey: pk };
|
|
3566
|
-
if (
|
|
3599
|
+
if (network) query.network = network;
|
|
3567
3600
|
const resp = await this.http.get(
|
|
3568
3601
|
"/api/ai/exists",
|
|
3569
3602
|
query,
|
|
@@ -3571,11 +3604,21 @@ var Atbash = class _Atbash {
|
|
|
3571
3604
|
);
|
|
3572
3605
|
await this.raiseIfError(resp);
|
|
3573
3606
|
const data = await this.json(resp);
|
|
3607
|
+
const registered = Boolean(data?.registered);
|
|
3608
|
+
const orgKey = typeof data?.org_encryption_pubkey === "string" && data.org_encryption_pubkey ? data.org_encryption_pubkey : null;
|
|
3609
|
+
if (registered) {
|
|
3610
|
+
this._agentExistsCache = {
|
|
3611
|
+
pubkey: pk,
|
|
3612
|
+
network,
|
|
3613
|
+
expiresAt: Date.now() + _Atbash.AGENT_EXISTS_TTL_MS,
|
|
3614
|
+
registered,
|
|
3615
|
+
orgKey
|
|
3616
|
+
};
|
|
3617
|
+
}
|
|
3574
3618
|
if (pk === this.auth.pubkey) {
|
|
3575
|
-
|
|
3576
|
-
this._orgKeyFromChain = typeof key3 === "string" && key3 ? key3 : null;
|
|
3619
|
+
this._orgKeyFromChain = orgKey;
|
|
3577
3620
|
}
|
|
3578
|
-
return
|
|
3621
|
+
return registered;
|
|
3579
3622
|
});
|
|
3580
3623
|
}
|
|
3581
3624
|
/* ── log_tool_call (sign-only) ─────────────────────────────────────────── */
|
|
@@ -3656,12 +3699,19 @@ var Atbash = class _Atbash {
|
|
|
3656
3699
|
}
|
|
3657
3700
|
let chainOpts = options.chainOpts;
|
|
3658
3701
|
if (options.orgName) {
|
|
3659
|
-
const
|
|
3660
|
-
if (
|
|
3661
|
-
chainOpts = { network:
|
|
3662
|
-
} else
|
|
3663
|
-
const
|
|
3664
|
-
|
|
3702
|
+
const cached = this._chainCache.get(options.orgName);
|
|
3703
|
+
if (cached) {
|
|
3704
|
+
chainOpts = { network: cached.network };
|
|
3705
|
+
} else {
|
|
3706
|
+
const mapNetwork = await this.getActiveNetworkForOrg(options.orgName);
|
|
3707
|
+
if (mapNetwork) {
|
|
3708
|
+
const chain = mapNetwork === "private" ? PRIVATE_CHAIN : PUBLIC_CHAIN;
|
|
3709
|
+
this._chainCache.set(options.orgName, chain);
|
|
3710
|
+
chainOpts = { network: mapNetwork };
|
|
3711
|
+
} else if (!chainOpts?.blockchainRid) {
|
|
3712
|
+
const resolved = await this.resolveChainFromMap(options.orgName, null);
|
|
3713
|
+
chainOpts = { ...chainOpts, network: resolved.network };
|
|
3714
|
+
}
|
|
3665
3715
|
}
|
|
3666
3716
|
}
|
|
3667
3717
|
const brid = this.bridFromChainOpts(chainOpts);
|
|
@@ -3976,19 +4026,25 @@ var Atbash = class _Atbash {
|
|
|
3976
4026
|
});
|
|
3977
4027
|
}
|
|
3978
4028
|
/* ── risk-engine batched (action-dispatched POST) ──────────────────────── */
|
|
3979
|
-
getAgentDetail(agentPubkey) {
|
|
3980
|
-
return this.track(
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
4029
|
+
async getAgentDetail(agentPubkey, options = {}) {
|
|
4030
|
+
return this.track("getAgentDetail", agentPubkey, async () => {
|
|
4031
|
+
const network = await this.resolveAgentLookupNetwork(options);
|
|
4032
|
+
return this.riskEnginePost(
|
|
4033
|
+
{ action: "agent-detail-batch", agent: agentPubkey },
|
|
4034
|
+
network
|
|
4035
|
+
);
|
|
4036
|
+
});
|
|
3985
4037
|
}
|
|
3986
|
-
async getAgentPolicy(agentPubkey) {
|
|
4038
|
+
async getAgentPolicy(agentPubkey, options = {}) {
|
|
3987
4039
|
return this.track("getAgentPolicy", agentPubkey, async () => {
|
|
3988
|
-
const
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
4040
|
+
const network = await this.resolveAgentLookupNetwork(options);
|
|
4041
|
+
const raw2 = await this.riskEnginePost(
|
|
4042
|
+
{
|
|
4043
|
+
action: "agent-policy-batch",
|
|
4044
|
+
agent: agentPubkey
|
|
4045
|
+
},
|
|
4046
|
+
network
|
|
4047
|
+
);
|
|
3992
4048
|
return {
|
|
3993
4049
|
policy: String(raw2.policy ?? ""),
|
|
3994
4050
|
isJailed: Boolean(raw2.is_jailed),
|
|
@@ -4110,6 +4166,10 @@ var Atbash = class _Atbash {
|
|
|
4110
4166
|
clearChainCache() {
|
|
4111
4167
|
this._chainCache.clear();
|
|
4112
4168
|
}
|
|
4169
|
+
/** Drop the short-TTL `/api/ai/exists` cache. Useful in tests. */
|
|
4170
|
+
clearAgentExistsCache() {
|
|
4171
|
+
this._agentExistsCache = null;
|
|
4172
|
+
}
|
|
4113
4173
|
/* ── internals ─────────────────────────────────────────────────────────── */
|
|
4114
4174
|
/**
|
|
4115
4175
|
* Wrap an SDK method body in telemetry — records the call at start
|
|
@@ -4141,6 +4201,20 @@ var Atbash = class _Atbash {
|
|
|
4141
4201
|
if (chainOpts?.network === "public") return PUBLIC_CHAIN.blockchainRid;
|
|
4142
4202
|
return this.blockchainRid;
|
|
4143
4203
|
}
|
|
4204
|
+
/**
|
|
4205
|
+
* Resolve the dashboard chain used by agent metadata/policy reads.
|
|
4206
|
+
* Explicit per-call network overrides win; otherwise use the supplied org
|
|
4207
|
+
* or the client's configured default org. A custom BRID is intentionally
|
|
4208
|
+
* left untouched because it cannot be represented by the dashboard's
|
|
4209
|
+
* public/private query selector.
|
|
4210
|
+
*/
|
|
4211
|
+
async resolveAgentLookupNetwork(options) {
|
|
4212
|
+
if (options.chainOpts?.network) return options.chainOpts.network;
|
|
4213
|
+
if (options.chainOpts?.blockchainRid) return void 0;
|
|
4214
|
+
const orgName = options.orgName ?? this.orgName;
|
|
4215
|
+
if (!orgName) return void 0;
|
|
4216
|
+
return (await this.resolveChainForOrg(orgName)).network;
|
|
4217
|
+
}
|
|
4144
4218
|
/**
|
|
4145
4219
|
* Get-or-create a Bearer token for dashboard reads. The token is a
|
|
4146
4220
|
* signed `log_tool_call` op (locally signed, never submitted) — the
|
|
@@ -4183,10 +4257,11 @@ var Atbash = class _Atbash {
|
|
|
4183
4257
|
if (resp.status !== 200) throw await this.httpError(resp);
|
|
4184
4258
|
return this.json(resp);
|
|
4185
4259
|
}
|
|
4186
|
-
async riskEnginePost(body) {
|
|
4260
|
+
async riskEnginePost(body, network) {
|
|
4187
4261
|
let resp;
|
|
4188
4262
|
try {
|
|
4189
|
-
|
|
4263
|
+
const path7 = network ? `/api/risk-engine?network=${encodeURIComponent(network)}` : "/api/risk-engine";
|
|
4264
|
+
resp = await this.http.post(path7, body, this.authHeaders());
|
|
4190
4265
|
} catch (err) {
|
|
4191
4266
|
throw this.transportError(err);
|
|
4192
4267
|
}
|
|
@@ -4459,24 +4534,29 @@ async function scanMemory(entry, auth, opts) {
|
|
|
4459
4534
|
toolArgsJson: opts?.toolArgsJson ?? JSON.stringify({ key: entry.key, source: entry.source }),
|
|
4460
4535
|
mode: "memory-scan"
|
|
4461
4536
|
});
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
return {
|
|
4467
|
-
safe: false,
|
|
4468
|
-
verdict: "red",
|
|
4469
|
-
reason: unknownAction ? `judge returned unrecognised action_type "${result.actionType}"` : "judge returned no verdict",
|
|
4470
|
-
confidence: result.confidence,
|
|
4471
|
-
score: native.defaultScoreForVerdict("red"),
|
|
4472
|
-
toolCallId: result.toolCallId
|
|
4473
|
-
};
|
|
4537
|
+
if (result.verdict === "No verdict" && result.status !== "logged") {
|
|
4538
|
+
throw new Error(
|
|
4539
|
+
`memory scan: judge returned no verdict without an audit-tier marker (status: ${result.status || "absent"})`
|
|
4540
|
+
);
|
|
4474
4541
|
}
|
|
4475
|
-
const
|
|
4476
|
-
|
|
4542
|
+
const KNOWN_ACTIONS = ["allow", "block", "hold_for_user_confirm"];
|
|
4543
|
+
const action = result.actionType.trim().toLowerCase();
|
|
4544
|
+
if (result.verdict !== "No verdict" && !KNOWN_ACTIONS.includes(action)) {
|
|
4545
|
+
throw new Error(
|
|
4546
|
+
`memory scan: unrecognized action_type from judge (${result.actionType || "absent"})`
|
|
4547
|
+
);
|
|
4548
|
+
}
|
|
4549
|
+
const mapped = native.mapVerdict(
|
|
4550
|
+
action,
|
|
4477
4551
|
result.confidence,
|
|
4478
4552
|
threshold
|
|
4479
4553
|
);
|
|
4554
|
+
let verdict = mapped;
|
|
4555
|
+
if (result.verdict === "BLOCK") {
|
|
4556
|
+
verdict = "red";
|
|
4557
|
+
} else if (result.verdict === "HOLD" && mapped === "green") {
|
|
4558
|
+
verdict = "yellow";
|
|
4559
|
+
}
|
|
4480
4560
|
const parsed = native.parseScoreFromReason(result.reason);
|
|
4481
4561
|
const score = result.score ?? parsed.score ?? native.defaultScoreForVerdict(verdict);
|
|
4482
4562
|
return {
|
|
@@ -9382,8 +9462,8 @@ Reporter$3.prototype.wrapResult = function wrapResult(result) {
|
|
|
9382
9462
|
errors: state2.errors
|
|
9383
9463
|
};
|
|
9384
9464
|
};
|
|
9385
|
-
function ReporterError$1(
|
|
9386
|
-
this.path =
|
|
9465
|
+
function ReporterError$1(path7, msg) {
|
|
9466
|
+
this.path = path7;
|
|
9387
9467
|
this.rethrow(msg);
|
|
9388
9468
|
}
|
|
9389
9469
|
inherits$v(ReporterError$1, Error);
|
|
@@ -29604,8 +29684,8 @@ Reporter.prototype.wrapResult = function wrapResult2(result) {
|
|
|
29604
29684
|
errors: state2.errors
|
|
29605
29685
|
};
|
|
29606
29686
|
};
|
|
29607
|
-
function ReporterError(
|
|
29608
|
-
this.path =
|
|
29687
|
+
function ReporterError(path7, msg) {
|
|
29688
|
+
this.path = path7;
|
|
29609
29689
|
this.rethrow(msg);
|
|
29610
29690
|
}
|
|
29611
29691
|
inherits(ReporterError, Error);
|
|
@@ -32635,8 +32715,8 @@ var parseUtil = {};
|
|
|
32635
32715
|
const errors_js_12 = errors$3;
|
|
32636
32716
|
const en_js_12 = __importDefault2(en);
|
|
32637
32717
|
const makeIssue = (params) => {
|
|
32638
|
-
const { data, path:
|
|
32639
|
-
const fullPath = [...
|
|
32718
|
+
const { data, path: path7, errorMaps, issueData } = params;
|
|
32719
|
+
const fullPath = [...path7, ...issueData.path || []];
|
|
32640
32720
|
const fullIssue = {
|
|
32641
32721
|
...issueData,
|
|
32642
32722
|
path: fullPath
|
|
@@ -32773,11 +32853,11 @@ var errorUtil_js_1 = errorUtil$1;
|
|
|
32773
32853
|
var parseUtil_js_1 = parseUtil;
|
|
32774
32854
|
var util_js_1 = util;
|
|
32775
32855
|
var ParseInputLazyPath = class {
|
|
32776
|
-
constructor(parent, value,
|
|
32856
|
+
constructor(parent, value, path7, key3) {
|
|
32777
32857
|
this._cachedPath = [];
|
|
32778
32858
|
this.parent = parent;
|
|
32779
32859
|
this.data = value;
|
|
32780
|
-
this._path =
|
|
32860
|
+
this._path = path7;
|
|
32781
32861
|
this._key = key3;
|
|
32782
32862
|
}
|
|
32783
32863
|
get path() {
|
|
@@ -39683,21 +39763,21 @@ function createTimeoutController(timeout) {
|
|
|
39683
39763
|
const timeoutId = setTimeout(() => controller.abort(timeoutError), timeout);
|
|
39684
39764
|
return { controller, timeoutId };
|
|
39685
39765
|
}
|
|
39686
|
-
function handleRequest(method,
|
|
39766
|
+
function handleRequest(method, path7, endpoint, timeout, postObject) {
|
|
39687
39767
|
return __awaiter$2(this, void 0, void 0, function* () {
|
|
39688
39768
|
if (method == enums_1$2.Method.GET) {
|
|
39689
|
-
return yield get(
|
|
39769
|
+
return yield get(path7, endpoint, timeout);
|
|
39690
39770
|
} else {
|
|
39691
|
-
return yield post(
|
|
39771
|
+
return yield post(path7, endpoint, timeout, postObject);
|
|
39692
39772
|
}
|
|
39693
39773
|
});
|
|
39694
39774
|
}
|
|
39695
|
-
function get(
|
|
39775
|
+
function get(path7, endpoint, timeout) {
|
|
39696
39776
|
return __awaiter$2(this, void 0, void 0, function* () {
|
|
39697
|
-
logger.debug(`GET URL ${new URL(
|
|
39777
|
+
logger.debug(`GET URL ${new URL(path7, endpoint).href}`);
|
|
39698
39778
|
try {
|
|
39699
39779
|
const { controller, timeoutId } = createTimeoutController(timeout);
|
|
39700
|
-
const response = yield fetch(new URL(
|
|
39780
|
+
const response = yield fetch(new URL(path7, endpoint).href, {
|
|
39701
39781
|
signal: controller === null || controller === void 0 ? void 0 : controller.signal
|
|
39702
39782
|
});
|
|
39703
39783
|
if (timeoutId)
|
|
@@ -39735,9 +39815,9 @@ function constructBufferResponseBody(response) {
|
|
|
39735
39815
|
return responseText ? responseText : response.statusText;
|
|
39736
39816
|
});
|
|
39737
39817
|
}
|
|
39738
|
-
function post(
|
|
39818
|
+
function post(path7, endpoint, timeout, requestBody) {
|
|
39739
39819
|
return __awaiter$2(this, void 0, void 0, function* () {
|
|
39740
|
-
logger.debug(`POST URL ${new URL(
|
|
39820
|
+
logger.debug(`POST URL ${new URL(path7, endpoint).href}`);
|
|
39741
39821
|
logger.debug(`POST body ${JSON.stringify(requestBody)}`);
|
|
39742
39822
|
if (buffer_1.Buffer.isBuffer(requestBody)) {
|
|
39743
39823
|
try {
|
|
@@ -39751,7 +39831,7 @@ function post(path6, endpoint, timeout, requestBody) {
|
|
|
39751
39831
|
},
|
|
39752
39832
|
signal: controller === null || controller === void 0 ? void 0 : controller.signal
|
|
39753
39833
|
};
|
|
39754
|
-
const response = yield fetch(new URL(
|
|
39834
|
+
const response = yield fetch(new URL(path7, endpoint).href, requestOptions);
|
|
39755
39835
|
if (timeoutId)
|
|
39756
39836
|
clearTimeout(timeoutId);
|
|
39757
39837
|
const transactionTimestamp = response.headers.get("X-Transaction-Timestamp");
|
|
@@ -39762,7 +39842,7 @@ function post(path6, endpoint, timeout, requestBody) {
|
|
|
39762
39842
|
} else {
|
|
39763
39843
|
try {
|
|
39764
39844
|
const { controller, timeoutId } = createTimeoutController(timeout);
|
|
39765
|
-
const response = yield fetch(new URL(
|
|
39845
|
+
const response = yield fetch(new URL(path7, endpoint).href, {
|
|
39766
39846
|
method: "post",
|
|
39767
39847
|
body: JSON.stringify(requestBody),
|
|
39768
39848
|
headers: {
|
|
@@ -39942,10 +40022,10 @@ function requireFailoverStrategies() {
|
|
|
39942
40022
|
}
|
|
39943
40023
|
}
|
|
39944
40024
|
function abortOnError(_a2) {
|
|
39945
|
-
return __awaiter2(this, arguments, void 0, function* ({ method, path:
|
|
40025
|
+
return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, timeoutOverride }) {
|
|
39946
40026
|
return yield retryRequest({
|
|
39947
40027
|
method,
|
|
39948
|
-
path:
|
|
40028
|
+
path: path7,
|
|
39949
40029
|
config: config2,
|
|
39950
40030
|
postObject,
|
|
39951
40031
|
timeoutOverride,
|
|
@@ -39956,10 +40036,10 @@ function requireFailoverStrategies() {
|
|
|
39956
40036
|
});
|
|
39957
40037
|
}
|
|
39958
40038
|
function tryNextOnError(_a2) {
|
|
39959
|
-
return __awaiter2(this, arguments, void 0, function* ({ method, path:
|
|
40039
|
+
return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, timeoutOverride }) {
|
|
39960
40040
|
return yield retryRequest({
|
|
39961
40041
|
method,
|
|
39962
|
-
path:
|
|
40042
|
+
path: path7,
|
|
39963
40043
|
config: config2,
|
|
39964
40044
|
postObject,
|
|
39965
40045
|
timeoutOverride,
|
|
@@ -39975,7 +40055,7 @@ function requireFailoverStrategies() {
|
|
|
39975
40055
|
return endpointPoolLength - (endpointPoolLength - 1) / 3;
|
|
39976
40056
|
}
|
|
39977
40057
|
function queryMajority(_a2) {
|
|
39978
|
-
return __awaiter2(this, arguments, void 0, function* ({ method, path:
|
|
40058
|
+
return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, timeoutOverride }) {
|
|
39979
40059
|
var _b;
|
|
39980
40060
|
const bftMajorityThreshold = calculateBftMajorityThreshold(config2.endpointPool.length);
|
|
39981
40061
|
const failureThreshold = config2.endpointPool.length - bftMajorityThreshold + 1;
|
|
@@ -39986,7 +40066,7 @@ function requireFailoverStrategies() {
|
|
|
39986
40066
|
const promises = availableNodes.map((node2) => __awaiter2(this, void 0, void 0, function* () {
|
|
39987
40067
|
try {
|
|
39988
40068
|
const requestTimeout = timeoutOverride !== null && timeoutOverride !== void 0 ? timeoutOverride : config2.responseTimeout;
|
|
39989
|
-
const response = yield (0, httpUtil_1.handleRequest)(method,
|
|
40069
|
+
const response = yield (0, httpUtil_1.handleRequest)(method, path7, node2.url, requestTimeout, postObject);
|
|
39990
40070
|
const { statusCode } = response;
|
|
39991
40071
|
if (statusCode && (0, http_utils_1.isSuccessfulStatusCode)(statusCode)) {
|
|
39992
40072
|
outcomes.push({ type: "SUCCESS", result: response });
|
|
@@ -40033,7 +40113,7 @@ function requireFailoverStrategies() {
|
|
|
40033
40113
|
});
|
|
40034
40114
|
}
|
|
40035
40115
|
function singleEndpoint(_a2) {
|
|
40036
|
-
return __awaiter2(this, arguments, void 0, function* ({ method, path:
|
|
40116
|
+
return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, timeoutOverride }) {
|
|
40037
40117
|
let statusCode = null;
|
|
40038
40118
|
let rspBody = null;
|
|
40039
40119
|
let error4 = null;
|
|
@@ -40044,7 +40124,7 @@ function requireFailoverStrategies() {
|
|
|
40044
40124
|
}
|
|
40045
40125
|
for (let attempt = 0; attempt < config2.attemptsPerEndpoint; attempt++) {
|
|
40046
40126
|
const requestTimeout = timeoutOverride !== null && timeoutOverride !== void 0 ? timeoutOverride : config2.responseTimeout;
|
|
40047
|
-
const response = yield (0, httpUtil_1.handleRequest)(method,
|
|
40127
|
+
const response = yield (0, httpUtil_1.handleRequest)(method, path7, endpoint.url, requestTimeout, postObject);
|
|
40048
40128
|
if (response) {
|
|
40049
40129
|
({ error: error4, statusCode, rspBody, transactionTimestamp } = response);
|
|
40050
40130
|
}
|
|
@@ -40059,7 +40139,7 @@ function requireFailoverStrategies() {
|
|
|
40059
40139
|
});
|
|
40060
40140
|
}
|
|
40061
40141
|
function retryRequest(_a2) {
|
|
40062
|
-
return __awaiter2(this, arguments, void 0, function* ({ method, path:
|
|
40142
|
+
return __awaiter2(this, arguments, void 0, function* ({ method, path: path7, config: config2, postObject, useNextNodeOnError, recoveryThreshold, timeoutOverride }) {
|
|
40063
40143
|
var _b, _c, _d;
|
|
40064
40144
|
let statusCode = null;
|
|
40065
40145
|
let rspBody = null;
|
|
@@ -40070,7 +40150,7 @@ function requireFailoverStrategies() {
|
|
|
40070
40150
|
for (const node2 of availableNodes) {
|
|
40071
40151
|
for (let attempt = 0; attempt < config2.attemptsPerEndpoint; attempt++) {
|
|
40072
40152
|
const requestTimeout = timeoutOverride !== null && timeoutOverride !== void 0 ? timeoutOverride : config2.responseTimeout;
|
|
40073
|
-
const response = yield (0, httpUtil_1.handleRequest)(method,
|
|
40153
|
+
const response = yield (0, httpUtil_1.handleRequest)(method, path7, node2.url, requestTimeout, postObject);
|
|
40074
40154
|
error4 = (_b = response === null || response === void 0 ? void 0 : response.error) !== null && _b !== void 0 ? _b : null;
|
|
40075
40155
|
statusCode = (_c = response === null || response === void 0 ? void 0 : response.statusCode) !== null && _c !== void 0 ? _c : null;
|
|
40076
40156
|
rspBody = (_d = response === null || response === void 0 ? void 0 : response.rspBody) !== null && _d !== void 0 ? _d : null;
|
|
@@ -40213,19 +40293,19 @@ function requireRequestWithFailoverStrategy() {
|
|
|
40213
40293
|
const enums_12 = enums;
|
|
40214
40294
|
const failoverStrategies_1 = requireFailoverStrategies();
|
|
40215
40295
|
function requestWithFailoverStrategy$1(method_1, path_1, config_1, postObject_1) {
|
|
40216
|
-
return __awaiter2(this, arguments, void 0, function* (method,
|
|
40296
|
+
return __awaiter2(this, arguments, void 0, function* (method, path7, config2, postObject, forceSingleEndpoint = false, timeoutOverride) {
|
|
40217
40297
|
switch (config2.failoverStrategy) {
|
|
40218
40298
|
case enums_12.FailoverStrategy.AbortOnError:
|
|
40219
|
-
return yield (0, failoverStrategies_1.abortOnError)({ method, path:
|
|
40299
|
+
return yield (0, failoverStrategies_1.abortOnError)({ method, path: path7, config: config2, postObject, timeoutOverride });
|
|
40220
40300
|
case enums_12.FailoverStrategy.TryNextOnError:
|
|
40221
|
-
return yield (0, failoverStrategies_1.tryNextOnError)({ method, path:
|
|
40301
|
+
return yield (0, failoverStrategies_1.tryNextOnError)({ method, path: path7, config: config2, postObject, timeoutOverride });
|
|
40222
40302
|
case enums_12.FailoverStrategy.SingleEndpoint:
|
|
40223
|
-
return yield (0, failoverStrategies_1.singleEndpoint)({ method, path:
|
|
40303
|
+
return yield (0, failoverStrategies_1.singleEndpoint)({ method, path: path7, config: config2, postObject, timeoutOverride });
|
|
40224
40304
|
case enums_12.FailoverStrategy.QueryMajority:
|
|
40225
40305
|
if (forceSingleEndpoint) {
|
|
40226
|
-
return yield (0, failoverStrategies_1.singleEndpoint)({ method, path:
|
|
40306
|
+
return yield (0, failoverStrategies_1.singleEndpoint)({ method, path: path7, config: config2, postObject, timeoutOverride });
|
|
40227
40307
|
}
|
|
40228
|
-
return yield (0, failoverStrategies_1.queryMajority)({ method, path:
|
|
40308
|
+
return yield (0, failoverStrategies_1.queryMajority)({ method, path: path7, config: config2, postObject, timeoutOverride });
|
|
40229
40309
|
default:
|
|
40230
40310
|
throw new Error(`Unsupported failover strategy: ${config2.failoverStrategy}`);
|
|
40231
40311
|
}
|
|
@@ -41424,7 +41504,7 @@ var networkSettings = {};
|
|
|
41424
41504
|
const restNetworkSettingsValidationContext = RestNetworkSettingsSchema.safeParse(networkSettings2);
|
|
41425
41505
|
if ("error" in restNetworkSettingsValidationContext) {
|
|
41426
41506
|
const { error: { issues } = {} } = restNetworkSettingsValidationContext;
|
|
41427
|
-
const errorMessage2 = issues === null || issues === void 0 ? void 0 : issues.map(({ message, path:
|
|
41507
|
+
const errorMessage2 = issues === null || issues === void 0 ? void 0 : issues.map(({ message, path: path7 }) => `${path7[0]}: ${message}`).join(", ");
|
|
41428
41508
|
if (throwOnError) {
|
|
41429
41509
|
throw new Error(errorMessage2);
|
|
41430
41510
|
}
|
|
@@ -42806,6 +42886,7 @@ function classifyMemoryWrite(event, ctx, opts = {}) {
|
|
|
42806
42886
|
}
|
|
42807
42887
|
|
|
42808
42888
|
// src-ts/memory/guard.ts
|
|
42889
|
+
var import_node_path4 = __toESM(require("path"));
|
|
42809
42890
|
function emitDebugProbe(event, ctx, memEntry, logger2) {
|
|
42810
42891
|
if (!logger2?.info) return;
|
|
42811
42892
|
const ev = event ?? {};
|
|
@@ -42842,7 +42923,8 @@ async function guardMemoryWrite(input) {
|
|
|
42842
42923
|
toolNames,
|
|
42843
42924
|
enforce = true,
|
|
42844
42925
|
debug: debug2 = false,
|
|
42845
|
-
logger: logger2
|
|
42926
|
+
logger: logger2,
|
|
42927
|
+
memoryFilePath
|
|
42846
42928
|
} = input;
|
|
42847
42929
|
const memEntry = classifyMemoryWrite(event, ctx, { patterns, toolNames });
|
|
42848
42930
|
if (debug2) emitDebugProbe(event, ctx, memEntry, logger2);
|
|
@@ -42878,17 +42960,28 @@ async function guardMemoryWrite(input) {
|
|
|
42878
42960
|
committed: false
|
|
42879
42961
|
};
|
|
42880
42962
|
}
|
|
42881
|
-
|
|
42882
|
-
|
|
42883
|
-
|
|
42884
|
-
|
|
42885
|
-
|
|
42886
|
-
|
|
42887
|
-
|
|
42888
|
-
|
|
42889
|
-
|
|
42963
|
+
const isManagedMemoryFile = memoryFilePath !== void 0 && import_node_path4.default.resolve(memEntry.key) === import_node_path4.default.resolve(memoryFilePath);
|
|
42964
|
+
if (isManagedMemoryFile) {
|
|
42965
|
+
commitMemoryVersion(memEntry.value, auth, {
|
|
42966
|
+
score: scanResult.score,
|
|
42967
|
+
orgName,
|
|
42968
|
+
endpoint
|
|
42969
|
+
}).catch((err) => {
|
|
42970
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
42971
|
+
logger2?.warn?.("[atbash] memory commit to chain failed", {
|
|
42972
|
+
path: memEntry.key,
|
|
42973
|
+
reason
|
|
42974
|
+
});
|
|
42890
42975
|
});
|
|
42891
|
-
}
|
|
42976
|
+
} else {
|
|
42977
|
+
logger2?.info?.(
|
|
42978
|
+
"[atbash] scanned but not committed \u2014 not the managed memory file",
|
|
42979
|
+
{
|
|
42980
|
+
path: memEntry.key,
|
|
42981
|
+
memoryFilePath: memoryFilePath ?? "(not configured)"
|
|
42982
|
+
}
|
|
42983
|
+
);
|
|
42984
|
+
}
|
|
42892
42985
|
logger2?.info?.(
|
|
42893
42986
|
scanResult.verdict === "yellow" ? "[atbash] memory HOLD" : "[atbash] memory ALLOW",
|
|
42894
42987
|
{ path: memEntry.key, score: scanResult.score, reason: scanResult.reason }
|
|
@@ -42897,7 +42990,7 @@ async function guardMemoryWrite(input) {
|
|
|
42897
42990
|
handled: true,
|
|
42898
42991
|
decision: { allow: true },
|
|
42899
42992
|
scanResult,
|
|
42900
|
-
committed:
|
|
42993
|
+
committed: isManagedMemoryFile
|
|
42901
42994
|
};
|
|
42902
42995
|
}
|
|
42903
42996
|
|
|
@@ -42916,26 +43009,26 @@ async function syncLocalMemory(auth, pointer, opts = {}) {
|
|
|
42916
43009
|
const now = Date.now();
|
|
42917
43010
|
const withinTtl = !opts.force && now - pointer.checkedAt < ttl;
|
|
42918
43011
|
if (withinTtl) {
|
|
42919
|
-
return { drifted: false, pointer };
|
|
43012
|
+
return { drifted: false, checked: false, pointer };
|
|
42920
43013
|
}
|
|
42921
43014
|
const currentId = await getActiveMemoryId(auth, opts.chainOpts);
|
|
42922
43015
|
const nextPointer = { activeId: currentId, checkedAt: now };
|
|
42923
43016
|
if (currentId === pointer.activeId) {
|
|
42924
|
-
return { drifted: false, pointer: nextPointer };
|
|
43017
|
+
return { drifted: false, checked: true, pointer: nextPointer };
|
|
42925
43018
|
}
|
|
42926
43019
|
if (currentId === null) {
|
|
42927
|
-
return { drifted: true, current: null, pointer: nextPointer };
|
|
43020
|
+
return { drifted: true, checked: true, current: null, pointer: nextPointer };
|
|
42928
43021
|
}
|
|
42929
43022
|
const row = await getMemoryById(currentId, auth, opts.chainOpts);
|
|
42930
43023
|
if (row.decryptError) {
|
|
42931
43024
|
throw new MemoryIntegrityError(currentId, row.decryptError);
|
|
42932
43025
|
}
|
|
42933
|
-
return { drifted: true, current: row, pointer: nextPointer };
|
|
43026
|
+
return { drifted: true, checked: true, current: row, pointer: nextPointer };
|
|
42934
43027
|
}
|
|
42935
43028
|
|
|
42936
43029
|
// src-ts/memory/pointer-store.ts
|
|
42937
43030
|
var import_node_fs4 = require("fs");
|
|
42938
|
-
var
|
|
43031
|
+
var import_node_path5 = __toESM(require("path"));
|
|
42939
43032
|
var EMPTY = { version: 1, agents: {} };
|
|
42940
43033
|
var PointerStore = class {
|
|
42941
43034
|
constructor(filePath) {
|
|
@@ -42977,19 +43070,19 @@ var PointerStore = class {
|
|
|
42977
43070
|
this.cache = { ...EMPTY, agents: {} };
|
|
42978
43071
|
}
|
|
42979
43072
|
async persist(file) {
|
|
42980
|
-
await import_node_fs4.promises.mkdir(
|
|
43073
|
+
await import_node_fs4.promises.mkdir(import_node_path5.default.dirname(this.filePath), { recursive: true });
|
|
42981
43074
|
const tmp = `${this.filePath}.${process.pid}.tmp`;
|
|
42982
43075
|
await import_node_fs4.promises.writeFile(tmp, JSON.stringify(file, null, 2), "utf8");
|
|
42983
43076
|
await import_node_fs4.promises.rename(tmp, this.filePath);
|
|
42984
43077
|
}
|
|
42985
43078
|
};
|
|
42986
43079
|
function defaultPointerPath(workspaceDir = process.cwd()) {
|
|
42987
|
-
return
|
|
43080
|
+
return import_node_path5.default.join(workspaceDir, ".atbash", "memory-pointer.json");
|
|
42988
43081
|
}
|
|
42989
43082
|
|
|
42990
43083
|
// src-ts/memory/file-logger.ts
|
|
42991
43084
|
var import_node_fs5 = require("fs");
|
|
42992
|
-
var
|
|
43085
|
+
var import_node_path6 = __toESM(require("path"));
|
|
42993
43086
|
function formatMeta(meta) {
|
|
42994
43087
|
if (!meta || Object.keys(meta).length === 0) return "";
|
|
42995
43088
|
try {
|
|
@@ -43001,7 +43094,7 @@ function formatMeta(meta) {
|
|
|
43001
43094
|
function createFileLogger(filePath, upstream) {
|
|
43002
43095
|
let queue = Promise.resolve();
|
|
43003
43096
|
async function ensureDir() {
|
|
43004
|
-
await import_node_fs5.promises.mkdir(
|
|
43097
|
+
await import_node_fs5.promises.mkdir(import_node_path6.default.dirname(filePath), { recursive: true });
|
|
43005
43098
|
}
|
|
43006
43099
|
function append(level, message, meta) {
|
|
43007
43100
|
const line = `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${message}${formatMeta(meta)}
|
|
@@ -43021,7 +43114,7 @@ function createFileLogger(filePath, upstream) {
|
|
|
43021
43114
|
};
|
|
43022
43115
|
}
|
|
43023
43116
|
function defaultPluginLogPath(workspaceDir = process.cwd()) {
|
|
43024
|
-
return
|
|
43117
|
+
return import_node_path6.default.join(workspaceDir, ".atbash", "plugin.log");
|
|
43025
43118
|
}
|
|
43026
43119
|
|
|
43027
43120
|
// src-ts/memory/read-classifier.ts
|
|
@@ -43036,13 +43129,13 @@ function classifyMemoryRead(event, ctx, opts = {}) {
|
|
|
43036
43129
|
|
|
43037
43130
|
// src-ts/memory/guard-manager.ts
|
|
43038
43131
|
var import_node_fs6 = require("fs");
|
|
43039
|
-
var
|
|
43132
|
+
var import_node_path7 = __toESM(require("path"));
|
|
43040
43133
|
var DEFAULT_SYNC_TTL_MS = 3e4;
|
|
43041
43134
|
var MemoryGuardManager = class {
|
|
43042
43135
|
constructor(opts) {
|
|
43043
43136
|
this.opts = opts;
|
|
43044
43137
|
const workspaceDir = opts.workspaceDir;
|
|
43045
|
-
this.memoryFilePath = opts.memoryFilePath ??
|
|
43138
|
+
this.memoryFilePath = opts.memoryFilePath ?? import_node_path7.default.join(workspaceDir, "MEMORY.md");
|
|
43046
43139
|
this.pointerStore = new PointerStore(opts.pointerFilePath ?? defaultPointerPath(workspaceDir));
|
|
43047
43140
|
this.logger = createFileLogger(
|
|
43048
43141
|
opts.logFilePath ?? defaultPluginLogPath(workspaceDir),
|
|
@@ -43072,7 +43165,11 @@ var MemoryGuardManager = class {
|
|
|
43072
43165
|
async runBootProbe() {
|
|
43073
43166
|
try {
|
|
43074
43167
|
const seed = { activeId: null, checkedAt: 0 };
|
|
43075
|
-
const result = await syncLocalMemory(this.opts.auth, seed, {
|
|
43168
|
+
const result = await syncLocalMemory(this.opts.auth, seed, {
|
|
43169
|
+
ttlMs: 0,
|
|
43170
|
+
force: true,
|
|
43171
|
+
chainOpts: this.opts.chainOpts
|
|
43172
|
+
});
|
|
43076
43173
|
if (!result.drifted && result.pointer.activeId == null) {
|
|
43077
43174
|
this.logger.info(
|
|
43078
43175
|
`[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.`
|
|
@@ -43104,15 +43201,19 @@ var MemoryGuardManager = class {
|
|
|
43104
43201
|
}
|
|
43105
43202
|
}
|
|
43106
43203
|
/**
|
|
43107
|
-
* Returns a `HookDecision` when the
|
|
43108
|
-
*
|
|
43109
|
-
*
|
|
43204
|
+
* Returns a `HookDecision` when the guard reached a decision about this event.
|
|
43205
|
+
* Returns `null` when it did not — either the event isn't memory-related, or it
|
|
43206
|
+
* is but the guard could not check it. In both cases the host falls through to
|
|
43207
|
+
* its own audit.
|
|
43208
|
+
*
|
|
43209
|
+
* A returned decision carries `audited` (see `HookDecision`). Only
|
|
43210
|
+
* `{ allow: true, audited: true }` means "checked and cleared"; anything else
|
|
43211
|
+
* that allows is a call the host still needs to judge.
|
|
43110
43212
|
*/
|
|
43111
43213
|
async handleBeforeToolCall(event, ctx) {
|
|
43112
43214
|
if (classifyMemoryRead(event, ctx, this.opts.memoryReadClassifier)) {
|
|
43113
43215
|
this.logger.info("[atbash] memory read intercepted \u2014 running sync check");
|
|
43114
|
-
|
|
43115
|
-
return readDecision ?? { allow: true };
|
|
43216
|
+
return await this.handleMemoryRead(event, ctx);
|
|
43116
43217
|
}
|
|
43117
43218
|
const guardLogger = {
|
|
43118
43219
|
info: (msg, meta) => this.logger.info(msg, meta && typeof meta === "object" ? meta : void 0),
|
|
@@ -43129,7 +43230,9 @@ var MemoryGuardManager = class {
|
|
|
43129
43230
|
toolNames: this.opts.memoryWriteToolNames,
|
|
43130
43231
|
enforce: this.enforce,
|
|
43131
43232
|
debug: this.opts.debug,
|
|
43132
|
-
logger: guardLogger
|
|
43233
|
+
logger: guardLogger,
|
|
43234
|
+
// Only this file may reach the single, path-less chain memory slot.
|
|
43235
|
+
memoryFilePath: this.memoryFilePath
|
|
43133
43236
|
});
|
|
43134
43237
|
return this.mapGuardResult(guard);
|
|
43135
43238
|
}
|
|
@@ -43147,30 +43250,81 @@ var MemoryGuardManager = class {
|
|
|
43147
43250
|
block: true,
|
|
43148
43251
|
blockReason: d.reason ?? "",
|
|
43149
43252
|
allow: false,
|
|
43150
|
-
reason: d.reason
|
|
43253
|
+
reason: d.reason,
|
|
43254
|
+
// A block IS a decision — the most thoroughly checked one the guard
|
|
43255
|
+
// makes. Without this a host following the documented `!audited ->
|
|
43256
|
+
// judge it yourself` rule would re-judge its way past a red scan.
|
|
43257
|
+
audited: true,
|
|
43258
|
+
...sr2 ? { verdict: sr2.verdict } : {}
|
|
43151
43259
|
};
|
|
43152
43260
|
}
|
|
43153
43261
|
this.logger.info(
|
|
43154
43262
|
`[atbash] guardMemoryWrite ALLOWED \u2014 verdict=${verdict} score=${score} committed=${guard.committed === true}`
|
|
43155
43263
|
);
|
|
43156
|
-
|
|
43264
|
+
if (sr2 === void 0) {
|
|
43265
|
+
return { allow: true, audited: false, reason: "memory scan did not run (observe mode)" };
|
|
43266
|
+
}
|
|
43267
|
+
if (sr2.verdict !== "green") {
|
|
43268
|
+
return {
|
|
43269
|
+
allow: true,
|
|
43270
|
+
audited: false,
|
|
43271
|
+
verdict: sr2.verdict,
|
|
43272
|
+
reason: `memory scan returned ${sr2.verdict} but this guard is not enforcing it`
|
|
43273
|
+
};
|
|
43274
|
+
}
|
|
43275
|
+
return { allow: true, audited: true, verdict: sr2.verdict };
|
|
43157
43276
|
}
|
|
43158
|
-
|
|
43277
|
+
/**
|
|
43278
|
+
* Whether the pointer state this manager tracks actually describes the file
|
|
43279
|
+
* this call is about to read.
|
|
43280
|
+
*
|
|
43281
|
+
* The classifier fires on nine patterns — including the bare tokens
|
|
43282
|
+
* `"memory/"`, `"CLAUDE.md"` and `"AGENTS.md"` — but the sync path only ever
|
|
43283
|
+
* reads, refreshes, or vouches for `this.memoryFilePath`. Without this check a
|
|
43284
|
+
* read of `/repo/CLAUDE.md` (or any path merely containing `memory/`) would
|
|
43285
|
+
* receive an `audited: true` for a file the guard never opened.
|
|
43286
|
+
*
|
|
43287
|
+
* Conservative on purpose: every path-shaped value found must resolve to the
|
|
43288
|
+
* managed file. If none is found, or any one differs, the answer is no. That
|
|
43289
|
+
* also covers events carrying two different path keys, where the classifier
|
|
43290
|
+
* and the host could otherwise disagree about which one is authoritative.
|
|
43291
|
+
*/
|
|
43292
|
+
vouchesForTarget(event, ctx) {
|
|
43293
|
+
const KEYS = ["path", "file_path", "filePath", "notebook_path", "notebookPath", "target"];
|
|
43294
|
+
const found = [];
|
|
43295
|
+
for (const src of [event, ctx]) {
|
|
43296
|
+
for (const bag of [src, src?.params]) {
|
|
43297
|
+
if (!bag || typeof bag !== "object") continue;
|
|
43298
|
+
const rec = bag;
|
|
43299
|
+
for (const k of KEYS) {
|
|
43300
|
+
if (typeof rec[k] === "string" && rec[k]) found.push(rec[k]);
|
|
43301
|
+
}
|
|
43302
|
+
}
|
|
43303
|
+
}
|
|
43304
|
+
if (found.length === 0) return false;
|
|
43305
|
+
const managed = import_node_path7.default.resolve(this.memoryFilePath);
|
|
43306
|
+
return found.every((p) => import_node_path7.default.resolve(p) === managed);
|
|
43307
|
+
}
|
|
43308
|
+
async handleMemoryRead(event, ctx) {
|
|
43159
43309
|
const pointer = await this.pointerStore.get(this.agentPubkeyHex);
|
|
43160
43310
|
let result;
|
|
43161
43311
|
try {
|
|
43162
|
-
result = await syncLocalMemory(this.opts.auth, pointer, {
|
|
43312
|
+
result = await syncLocalMemory(this.opts.auth, pointer, {
|
|
43313
|
+
ttlMs: this.ttlMs,
|
|
43314
|
+
chainOpts: this.opts.chainOpts
|
|
43315
|
+
});
|
|
43163
43316
|
} catch (err) {
|
|
43164
43317
|
if (err instanceof MemoryIntegrityError) {
|
|
43165
43318
|
const reason = `Memory integrity check failed on id ${err.id} \u2014 read blocked.`;
|
|
43166
43319
|
this.logger.warn("[atbash] MEMORY INTEGRITY FAILURE", { id: err.id, error: err.message });
|
|
43167
43320
|
if (!this.enforce) return null;
|
|
43168
|
-
return { block: true, blockReason: reason, allow: false, reason };
|
|
43321
|
+
return { block: true, blockReason: reason, allow: false, reason, audited: true };
|
|
43169
43322
|
}
|
|
43170
43323
|
const msg = err instanceof Error ? err.message : String(err);
|
|
43171
43324
|
this.logger.warn("[atbash] memory sync failed (serving local copy)", { error: msg });
|
|
43172
43325
|
return null;
|
|
43173
43326
|
}
|
|
43327
|
+
let onDiskIsCurrent = result.checked;
|
|
43174
43328
|
if (result.drifted) {
|
|
43175
43329
|
const fresh = result.current;
|
|
43176
43330
|
if (fresh) {
|
|
@@ -43178,7 +43332,7 @@ var MemoryGuardManager = class {
|
|
|
43178
43332
|
const reason = `Rolled-back memory version #${fresh.id} scored ${fresh.score} (below threshold ${this.rollbackMinScore}) \u2014 read blocked.`;
|
|
43179
43333
|
this.logger.warn("[atbash] blocking read on low-score rollback", { id: fresh.id, score: fresh.score });
|
|
43180
43334
|
if (!this.enforce) return null;
|
|
43181
|
-
return { block: true, blockReason: reason, allow: false, reason };
|
|
43335
|
+
return { block: true, blockReason: reason, allow: false, reason, audited: true };
|
|
43182
43336
|
}
|
|
43183
43337
|
this.logger.info("[atbash] memory drift detected \u2014 refreshing local file", {
|
|
43184
43338
|
id: fresh.id,
|
|
@@ -43189,16 +43343,26 @@ var MemoryGuardManager = class {
|
|
|
43189
43343
|
} catch (err) {
|
|
43190
43344
|
const msg = err instanceof Error ? err.message : String(err);
|
|
43191
43345
|
this.logger.warn("[atbash] failed to write refreshed memory (serving old)", { error: msg });
|
|
43346
|
+
onDiskIsCurrent = false;
|
|
43192
43347
|
}
|
|
43193
43348
|
} else {
|
|
43194
43349
|
this.logger.info("[atbash] active memory removed on chain", { pubkey: this.agentPubkeyHex });
|
|
43350
|
+
onDiskIsCurrent = false;
|
|
43195
43351
|
}
|
|
43196
43352
|
}
|
|
43197
|
-
|
|
43198
|
-
|
|
43353
|
+
if (onDiskIsCurrent) {
|
|
43354
|
+
await this.pointerStore.set(this.agentPubkeyHex, result.pointer);
|
|
43355
|
+
} else {
|
|
43356
|
+
this.logger.warn(
|
|
43357
|
+
"[atbash] not advancing memory pointer \u2014 local file is stale or revoked; reads stay unaudited until it is refreshed"
|
|
43358
|
+
);
|
|
43359
|
+
}
|
|
43360
|
+
if (!onDiskIsCurrent) return null;
|
|
43361
|
+
if (!this.vouchesForTarget(event, ctx)) return null;
|
|
43362
|
+
return { allow: true, audited: true };
|
|
43199
43363
|
}
|
|
43200
43364
|
async writeMemoryAtomic(content) {
|
|
43201
|
-
await import_node_fs6.promises.mkdir(
|
|
43365
|
+
await import_node_fs6.promises.mkdir(import_node_path7.default.dirname(this.memoryFilePath), { recursive: true });
|
|
43202
43366
|
const tmp = `${this.memoryFilePath}.${process.pid}.tmp`;
|
|
43203
43367
|
await import_node_fs6.promises.writeFile(tmp, content, "utf8");
|
|
43204
43368
|
await import_node_fs6.promises.rename(tmp, this.memoryFilePath);
|