@atbash/sdk 0.19.2-dev.0 → 0.21.0-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.d.mts +118 -24
- package/dist/browser.mjs +314 -251
- package/dist/index.d.mts +118 -24
- package/dist/index.d.ts +118 -24
- package/dist/index.js +271 -130
- package/dist/index.mjs +280 -141
- package/index.d.ts +0 -4
- package/index.js +58 -56
- package/package.json +8 -6
package/dist/index.mjs
CHANGED
|
@@ -43,32 +43,28 @@ function agentAuthHeaders(auth, blockchainRid) {
|
|
|
43
43
|
return { Authorization: `Bearer ${agentAuthBearer(auth, blockchainRid)}` };
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
// src-ts/constants.ts
|
|
47
|
-
var DEFAULT_ENDPOINT = native.DEFAULT_ENDPOINT;
|
|
48
|
-
var DEFAULT_CHROMIA_NODE_URLS = Object.freeze(
|
|
49
|
-
native.defaultChromiaNodeUrls()
|
|
50
|
-
);
|
|
51
|
-
var DEFAULT_BLOCKCHAIN_RID = native.DEFAULT_BLOCKCHAIN_RID;
|
|
52
|
-
|
|
53
46
|
// src-ts/chain-config.ts
|
|
54
47
|
var DEFAULT_PRIVATE_NODE_URLS = Object.freeze(
|
|
55
48
|
native.defaultPrivateNodeUrls()
|
|
56
49
|
);
|
|
57
50
|
var DEFAULT_PRIVATE_BLOCKCHAIN_RID = native.DEFAULT_PRIVATE_BLOCKCHAIN_RID;
|
|
58
|
-
var PUBLIC_CHAIN = {
|
|
59
|
-
network: "public",
|
|
60
|
-
blockchainRid: DEFAULT_BLOCKCHAIN_RID,
|
|
61
|
-
nodeUrls: DEFAULT_CHROMIA_NODE_URLS
|
|
62
|
-
};
|
|
63
51
|
var PRIVATE_CHAIN = {
|
|
64
52
|
network: "private",
|
|
65
53
|
blockchainRid: DEFAULT_PRIVATE_BLOCKCHAIN_RID,
|
|
66
54
|
nodeUrls: DEFAULT_PRIVATE_NODE_URLS
|
|
67
55
|
};
|
|
68
56
|
function chainForNetwork(network) {
|
|
69
|
-
|
|
57
|
+
if (network !== "private") {
|
|
58
|
+
throw new Error(
|
|
59
|
+
`network must be "private" (the public chain is retired), got ${JSON.stringify(network)}`
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
return PRIVATE_CHAIN;
|
|
70
63
|
}
|
|
71
64
|
|
|
65
|
+
// src-ts/constants.ts
|
|
66
|
+
var DEFAULT_ENDPOINT = native.DEFAULT_ENDPOINT;
|
|
67
|
+
|
|
72
68
|
// src-ts/encrypted-toolcall.ts
|
|
73
69
|
function columnAad(toolCallId, column) {
|
|
74
70
|
return `${toolCallId}:${column}`;
|
|
@@ -166,12 +162,12 @@ var AtbashAPIError = class extends Error {
|
|
|
166
162
|
* ran does not carry. The path is the fact that settles it.
|
|
167
163
|
*/
|
|
168
164
|
path;
|
|
169
|
-
constructor(status, body, statusText = "", endpoint = DEFAULT_ENDPOINT,
|
|
170
|
-
super(enrich(status, body, statusText, endpoint,
|
|
165
|
+
constructor(status, body, statusText = "", endpoint = DEFAULT_ENDPOINT, path4) {
|
|
166
|
+
super(enrich(status, body, statusText, endpoint, path4));
|
|
171
167
|
this.name = "AtbashAPIError";
|
|
172
168
|
this.status = status;
|
|
173
169
|
this.body = body;
|
|
174
|
-
this.path =
|
|
170
|
+
this.path = path4;
|
|
175
171
|
}
|
|
176
172
|
};
|
|
177
173
|
var SignatureVerificationError = class extends Error {
|
|
@@ -180,9 +176,18 @@ var SignatureVerificationError = class extends Error {
|
|
|
180
176
|
this.name = "SignatureVerificationError";
|
|
181
177
|
}
|
|
182
178
|
};
|
|
183
|
-
|
|
179
|
+
var JudgeRefusalError = class extends Error {
|
|
180
|
+
constructor(message) {
|
|
181
|
+
super(message);
|
|
182
|
+
this.name = "JudgeRefusalError";
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
function isRefusalStatus(status) {
|
|
186
|
+
return status >= 400 && status < 500 && status !== 408;
|
|
187
|
+
}
|
|
188
|
+
function enrich(status, body, statusText, endpoint, path4) {
|
|
184
189
|
const dashboard = endpoint.replace(/\/+$/, "") || DEFAULT_ENDPOINT;
|
|
185
|
-
let msg = `API error ${status}${
|
|
190
|
+
let msg = `API error ${status}${path4 ? ` from ${path4}` : ""}: ${body || statusText}`;
|
|
186
191
|
const lowered = body.toLowerCase();
|
|
187
192
|
if (lowered.includes("agent not registered")) {
|
|
188
193
|
msg += `
|
|
@@ -203,6 +208,61 @@ function enrich(status, body, statusText, endpoint, path5) {
|
|
|
203
208
|
return msg;
|
|
204
209
|
}
|
|
205
210
|
|
|
211
|
+
// src-ts/jail-hold.ts
|
|
212
|
+
var DEFAULTS = { ceilingMs: 3e4, pollMs: 1e3 };
|
|
213
|
+
var holds = /* @__PURE__ */ new Map();
|
|
214
|
+
var blockedAt = /* @__PURE__ */ new Map();
|
|
215
|
+
var BLOCK_MEMORY_MS = 10 * 6e4;
|
|
216
|
+
var config = { ...DEFAULTS };
|
|
217
|
+
function isJailHeld(pubkey) {
|
|
218
|
+
return holds.has(pubkey);
|
|
219
|
+
}
|
|
220
|
+
function recordBlock(pubkey) {
|
|
221
|
+
const now = Date.now();
|
|
222
|
+
for (const [key, at] of blockedAt) if (now - at > BLOCK_MEMORY_MS) blockedAt.delete(key);
|
|
223
|
+
blockedAt.set(pubkey, now);
|
|
224
|
+
}
|
|
225
|
+
function blockedSince(pubkey, startedAt) {
|
|
226
|
+
const at = blockedAt.get(pubkey);
|
|
227
|
+
return at !== void 0 && startedAt <= at;
|
|
228
|
+
}
|
|
229
|
+
function holdJail(pubkey, confirmJailed, onGiveUp) {
|
|
230
|
+
if (holds.has(pubkey)) return;
|
|
231
|
+
const hold = { timer: null };
|
|
232
|
+
holds.set(pubkey, hold);
|
|
233
|
+
const deadline = Date.now() + config.ceilingMs;
|
|
234
|
+
const tick = async () => {
|
|
235
|
+
if (holds.get(pubkey) !== hold) return;
|
|
236
|
+
let jailed = false;
|
|
237
|
+
try {
|
|
238
|
+
jailed = await confirmJailed();
|
|
239
|
+
} catch {
|
|
240
|
+
}
|
|
241
|
+
if (holds.get(pubkey) !== hold) return;
|
|
242
|
+
if (jailed) {
|
|
243
|
+
holds.delete(pubkey);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (Date.now() >= deadline) {
|
|
247
|
+
holds.delete(pubkey);
|
|
248
|
+
onGiveUp?.();
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const timer = setTimeout(() => void tick(), config.pollMs);
|
|
252
|
+
timer.unref?.();
|
|
253
|
+
hold.timer = timer;
|
|
254
|
+
};
|
|
255
|
+
void tick();
|
|
256
|
+
}
|
|
257
|
+
function releaseJailHolds() {
|
|
258
|
+
for (const hold of holds.values()) if (hold.timer) clearTimeout(hold.timer);
|
|
259
|
+
holds.clear();
|
|
260
|
+
blockedAt.clear();
|
|
261
|
+
}
|
|
262
|
+
function configureJailHold(next) {
|
|
263
|
+
config = { ...DEFAULTS, ...next };
|
|
264
|
+
}
|
|
265
|
+
|
|
206
266
|
// src-ts/http/client.ts
|
|
207
267
|
var HttpClient = class {
|
|
208
268
|
baseUrl;
|
|
@@ -211,8 +271,8 @@ var HttpClient = class {
|
|
|
211
271
|
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
212
272
|
this.timeoutMs = timeoutMs;
|
|
213
273
|
}
|
|
214
|
-
buildUrl(
|
|
215
|
-
const url = new URL(this.baseUrl +
|
|
274
|
+
buildUrl(path4, query) {
|
|
275
|
+
const url = new URL(this.baseUrl + path4);
|
|
216
276
|
if (query) {
|
|
217
277
|
for (const [k, v] of Object.entries(query)) {
|
|
218
278
|
if (v !== void 0 && v !== null && v !== "") {
|
|
@@ -222,14 +282,14 @@ var HttpClient = class {
|
|
|
222
282
|
}
|
|
223
283
|
return url.toString();
|
|
224
284
|
}
|
|
225
|
-
async get(
|
|
226
|
-
return this.fetch(this.buildUrl(
|
|
285
|
+
async get(path4, query, headers) {
|
|
286
|
+
return this.fetch(this.buildUrl(path4, query), {
|
|
227
287
|
method: "GET",
|
|
228
288
|
...headers && { headers }
|
|
229
289
|
});
|
|
230
290
|
}
|
|
231
|
-
async post(
|
|
232
|
-
return this.fetch(this.buildUrl(
|
|
291
|
+
async post(path4, body, headers) {
|
|
292
|
+
return this.fetch(this.buildUrl(path4), {
|
|
233
293
|
method: "POST",
|
|
234
294
|
headers: { "Content-Type": "application/json", ...headers },
|
|
235
295
|
body: JSON.stringify(body)
|
|
@@ -553,7 +613,7 @@ import {
|
|
|
553
613
|
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
|
|
554
614
|
import { BatchLogRecordProcessor, LoggerProvider } from "@opentelemetry/sdk-logs";
|
|
555
615
|
import { createHash } from "crypto";
|
|
556
|
-
var SDK_VERSION = true ? "0.
|
|
616
|
+
var SDK_VERSION = true ? "0.21.0-dev.0" : "";
|
|
557
617
|
var SDK_LANGUAGE = "node";
|
|
558
618
|
function sdkResourceAttributes() {
|
|
559
619
|
const attrs = {
|
|
@@ -584,8 +644,8 @@ function isTelemetryOptedOut() {
|
|
|
584
644
|
const filePath = join2(home2, ".config", "atbash", "telemetry.json");
|
|
585
645
|
const raw = readFileSync2(filePath, "utf-8").trim();
|
|
586
646
|
if (!raw) return false;
|
|
587
|
-
const
|
|
588
|
-
return
|
|
647
|
+
const config2 = JSON.parse(raw);
|
|
648
|
+
return config2.enabled === false;
|
|
589
649
|
} catch {
|
|
590
650
|
return false;
|
|
591
651
|
}
|
|
@@ -630,26 +690,26 @@ function customCollector() {
|
|
|
630
690
|
}
|
|
631
691
|
return { url: url.replace(/\/+$/, ""), headers: () => headers };
|
|
632
692
|
}
|
|
633
|
-
function setupTelemetry(
|
|
634
|
-
if (!
|
|
693
|
+
function setupTelemetry(config2) {
|
|
694
|
+
if (!config2.enabled) return;
|
|
635
695
|
if (isTelemetryOptedOut()) return;
|
|
636
|
-
if (
|
|
637
|
-
defaultSource =
|
|
696
|
+
if (config2.source && !sourceExplicitlySet && SOURCE_SHAPE.test(config2.source)) {
|
|
697
|
+
defaultSource = config2.source;
|
|
638
698
|
sourceExplicitlySet = true;
|
|
639
699
|
}
|
|
640
|
-
if (
|
|
641
|
-
requestedExportIntervalMs =
|
|
700
|
+
if (config2.exportIntervalMs !== void 0 && requestedExportIntervalMs === void 0) {
|
|
701
|
+
requestedExportIntervalMs = config2.exportIntervalMs;
|
|
642
702
|
}
|
|
643
703
|
if (meterProvider) return;
|
|
644
704
|
const collector = customCollector();
|
|
645
|
-
if (!collector && (!
|
|
705
|
+
if (!collector && (!config2.endpoint || !config2.getAuthHeaders)) return;
|
|
646
706
|
if (!collector && /^https?:\/\/(localhost|127\.0\.0\.1|0\.0\.0\.0)(:|\/|$)/i.test(
|
|
647
|
-
|
|
707
|
+
config2.endpoint
|
|
648
708
|
))
|
|
649
709
|
return;
|
|
650
710
|
const destination = collector ?? {
|
|
651
|
-
url: `${
|
|
652
|
-
headers: () =>
|
|
711
|
+
url: `${config2.endpoint.replace(/\/+$/, "")}/api/telemetry`,
|
|
712
|
+
headers: () => config2.getAuthHeaders()
|
|
653
713
|
};
|
|
654
714
|
const proxyUrl = destination.url;
|
|
655
715
|
const exporter = new OTLPMetricExporter({
|
|
@@ -684,7 +744,7 @@ function setupTelemetry(config) {
|
|
|
684
744
|
description: "SDK function execution duration",
|
|
685
745
|
unit: "ms"
|
|
686
746
|
});
|
|
687
|
-
counterHasher =
|
|
747
|
+
counterHasher = config2.hashAgentKey ?? defaultAgentKeyHasher;
|
|
688
748
|
const logExporter = new OTLPLogExporter({
|
|
689
749
|
// A real collector takes OTLP at its own signal paths; the Atbash proxy
|
|
690
750
|
// takes a query parameter, because it is one authenticated route.
|
|
@@ -703,8 +763,8 @@ function setupTelemetry(config) {
|
|
|
703
763
|
});
|
|
704
764
|
}
|
|
705
765
|
configureEvents(loggerProvider.getLogger("atbash-sdk"), {
|
|
706
|
-
source: sourceOrDefault(
|
|
707
|
-
hashAgentKey:
|
|
766
|
+
source: sourceOrDefault(config2.source),
|
|
767
|
+
hashAgentKey: config2.hashAgentKey ?? defaultAgentKeyHasher,
|
|
708
768
|
version: SDK_VERSION
|
|
709
769
|
});
|
|
710
770
|
}
|
|
@@ -782,13 +842,13 @@ function loadUserConfig() {
|
|
|
782
842
|
return {};
|
|
783
843
|
}
|
|
784
844
|
}
|
|
785
|
-
function saveUserConfig(
|
|
845
|
+
function saveUserConfig(config2) {
|
|
786
846
|
const dir = getConfigDir();
|
|
787
847
|
if (!existsSync2(dir)) {
|
|
788
848
|
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
789
849
|
}
|
|
790
850
|
const filePath = getConfigPath();
|
|
791
|
-
writeFileSync(filePath, JSON.stringify(
|
|
851
|
+
writeFileSync(filePath, JSON.stringify(config2, null, 2) + "\n", {
|
|
792
852
|
mode: 384
|
|
793
853
|
});
|
|
794
854
|
chmodSync(filePath, 384);
|
|
@@ -814,15 +874,16 @@ function resolve(key, flagValue) {
|
|
|
814
874
|
function forcedChainNetwork(flagValue) {
|
|
815
875
|
const raw = resolve("defaultChainNetwork", flagValue);
|
|
816
876
|
if (!raw) return void 0;
|
|
817
|
-
if (raw !== "
|
|
877
|
+
if (raw !== "private") {
|
|
818
878
|
throw new Error(
|
|
819
|
-
`ATBASH_DEFAULT_CHAIN_NETWORK / defaultChainNetwork must be "
|
|
879
|
+
`ATBASH_DEFAULT_CHAIN_NETWORK / defaultChainNetwork must be "private" (the public chain is retired), got ${JSON.stringify(raw)} \u2014 unset it to let each org's chain decide.`
|
|
820
880
|
);
|
|
821
881
|
}
|
|
822
882
|
return raw;
|
|
823
883
|
}
|
|
824
884
|
|
|
825
885
|
// src-ts/client.ts
|
|
886
|
+
var AGENT_NOT_REGISTERED = "Agent not registered. Onboard the agent at the dashboard before submitting actions.";
|
|
826
887
|
function generateToolCallId() {
|
|
827
888
|
return `tc-${Date.now()}-${randomHex(4)}`;
|
|
828
889
|
}
|
|
@@ -832,15 +893,13 @@ function resolveConstructorChain(options) {
|
|
|
832
893
|
const hasBrid = options.blockchainRid !== void 0;
|
|
833
894
|
if (hasNodeUrls !== hasBrid) {
|
|
834
895
|
throw new Error(
|
|
835
|
-
'nodeUrls and blockchainRid must be provided together \u2014 passing one without the other 404s every chain request. Prefer `chain:
|
|
896
|
+
'nodeUrls and blockchainRid must be provided together \u2014 passing one without the other 404s every chain request. Prefer `chain: PRIVATE_CHAIN` or `network: "private"`.'
|
|
836
897
|
);
|
|
837
898
|
}
|
|
838
899
|
if (hasNodeUrls && hasBrid) {
|
|
839
|
-
const brid = options.blockchainRid;
|
|
840
|
-
const derivedNetwork = options.network ?? (brid === PUBLIC_CHAIN.blockchainRid ? "public" : brid === PRIVATE_CHAIN.blockchainRid ? "private" : "private");
|
|
841
900
|
return {
|
|
842
|
-
network:
|
|
843
|
-
blockchainRid:
|
|
901
|
+
network: "private",
|
|
902
|
+
blockchainRid: options.blockchainRid,
|
|
844
903
|
nodeUrls: options.nodeUrls
|
|
845
904
|
};
|
|
846
905
|
}
|
|
@@ -980,10 +1039,9 @@ var Atbash = class _Atbash {
|
|
|
980
1039
|
_Atbash.environmentLogged = true;
|
|
981
1040
|
const brief = (rid) => rid ? `${rid.slice(0, 8)}\u2026` : "(unset)";
|
|
982
1041
|
this.logger.info?.(
|
|
983
|
-
`[atbash] environment \u2014 judge=${this.endpoint}
|
|
1042
|
+
`[atbash] environment \u2014 judge=${this.endpoint} privateChain=${brief(native.DEFAULT_PRIVATE_BLOCKCHAIN_RID)} activeChain=${brief(this.blockchainRid)} responseSignatureCheck=${this.verifyPubKey ? "on" : "off"}`,
|
|
984
1043
|
{
|
|
985
1044
|
judgeEndpoint: this.endpoint,
|
|
986
|
-
publicBlockchainRid: native.DEFAULT_BLOCKCHAIN_RID,
|
|
987
1045
|
privateBlockchainRid: native.DEFAULT_PRIVATE_BLOCKCHAIN_RID,
|
|
988
1046
|
activeBlockchainRid: this.blockchainRid,
|
|
989
1047
|
responseSignatureCheck: Boolean(this.verifyPubKey)
|
|
@@ -1171,6 +1229,15 @@ config.json still holds an "agentKey" (${identity}), but a settings file no long
|
|
|
1171
1229
|
* return the signed tx hex. The server broadcasts to chain.
|
|
1172
1230
|
*/
|
|
1173
1231
|
async logToolCall(action, context = "", options = {}) {
|
|
1232
|
+
return this._logToolCall(action, context, options, false);
|
|
1233
|
+
}
|
|
1234
|
+
/**
|
|
1235
|
+
* `raisePreflightErrors` (the judge path, like Python's
|
|
1236
|
+
* `raise_preflight_errors`): a failed registration check throws instead of
|
|
1237
|
+
* becoming `{ success: false }`, so the caller can tell Atbash's "no"
|
|
1238
|
+
* (not registered, or a 4xx) from an outage.
|
|
1239
|
+
*/
|
|
1240
|
+
async _logToolCall(action, context, options, raisePreflightErrors) {
|
|
1174
1241
|
const start = performance.now();
|
|
1175
1242
|
recordCall("logToolCall", void 0, this.auth.pubkey);
|
|
1176
1243
|
let exists;
|
|
@@ -1180,18 +1247,20 @@ config.json still holds an "agentKey" (${identity}), but a settings file no long
|
|
|
1180
1247
|
});
|
|
1181
1248
|
} catch (err) {
|
|
1182
1249
|
recordDuration("logToolCall", performance.now() - start, "error");
|
|
1250
|
+
if (raisePreflightErrors) throw err;
|
|
1183
1251
|
return { success: false, toolCallId: null, error: errorMessage(err) };
|
|
1184
1252
|
}
|
|
1185
1253
|
if (!exists) {
|
|
1186
1254
|
recordDuration("logToolCall", performance.now() - start, "error");
|
|
1255
|
+
if (raisePreflightErrors) throw new JudgeRefusalError(AGENT_NOT_REGISTERED);
|
|
1187
1256
|
return {
|
|
1188
1257
|
success: false,
|
|
1189
1258
|
toolCallId: null,
|
|
1190
|
-
error:
|
|
1259
|
+
error: AGENT_NOT_REGISTERED
|
|
1191
1260
|
};
|
|
1192
1261
|
}
|
|
1193
1262
|
const toolCallId = generateToolCallId();
|
|
1194
|
-
const brid =
|
|
1263
|
+
const brid = await this.callBrid(options.chainOpts);
|
|
1195
1264
|
const orgKey = options.orgEncryptionPubKey ?? this.orgEncryptionPubKey ?? this._orgKeyFromChain;
|
|
1196
1265
|
try {
|
|
1197
1266
|
const signedHex = orgKey ? signEncryptedToolCall(
|
|
@@ -1241,9 +1310,13 @@ config.json still holds an "agentKey" (${identity}), but a settings file no long
|
|
|
1241
1310
|
if (!action?.trim()) {
|
|
1242
1311
|
throw new Error("action is required and cannot be empty.");
|
|
1243
1312
|
}
|
|
1313
|
+
if (isJailHeld(this.auth.pubkey)) return this.localJailBlock();
|
|
1314
|
+
const startedAt = Date.now();
|
|
1244
1315
|
let chainOpts = options.chainOpts;
|
|
1245
1316
|
if (options.orgName && this._explicitChain) {
|
|
1246
|
-
chainOpts = options.chainOpts ?? {
|
|
1317
|
+
chainOpts = options.chainOpts ?? {
|
|
1318
|
+
blockchainRid: this._defaultChain.blockchainRid
|
|
1319
|
+
};
|
|
1247
1320
|
} else if (options.orgName && this.forcedNetwork()) {
|
|
1248
1321
|
chainOpts = { network: this.forcedNetwork() };
|
|
1249
1322
|
} else if (options.orgName) {
|
|
@@ -1253,8 +1326,7 @@ config.json still holds an "agentKey" (${identity}), but a settings file no long
|
|
|
1253
1326
|
} else {
|
|
1254
1327
|
const mapNetwork = await this.getActiveNetworkForOrg(options.orgName);
|
|
1255
1328
|
if (mapNetwork) {
|
|
1256
|
-
|
|
1257
|
-
this._chainCache.set(options.orgName, chain);
|
|
1329
|
+
this._chainCache.set(options.orgName, chainForNetwork(mapNetwork));
|
|
1258
1330
|
chainOpts = { network: mapNetwork };
|
|
1259
1331
|
} else if (!chainOpts?.blockchainRid) {
|
|
1260
1332
|
const resolved = await this.resolveChainFromMap(
|
|
@@ -1265,12 +1337,13 @@ config.json still holds an "agentKey" (${identity}), but a settings file no long
|
|
|
1265
1337
|
}
|
|
1266
1338
|
}
|
|
1267
1339
|
}
|
|
1268
|
-
const brid = this.
|
|
1269
|
-
const logResult = await this.
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
chainOpts
|
|
1273
|
-
|
|
1340
|
+
const brid = await this.callBrid(chainOpts);
|
|
1341
|
+
const logResult = await this._logToolCall(
|
|
1342
|
+
action,
|
|
1343
|
+
context,
|
|
1344
|
+
{ toolName: options.toolName, toolArgsJson: options.toolArgsJson, chainOpts },
|
|
1345
|
+
true
|
|
1346
|
+
);
|
|
1274
1347
|
if (!logResult.success || !logResult.toolCallId || !logResult.signedHex) {
|
|
1275
1348
|
throw new Error(logResult.error || "Failed to sign log_tool_call");
|
|
1276
1349
|
}
|
|
@@ -1307,10 +1380,16 @@ config.json still holds an "agentKey" (${identity}), but a settings file no long
|
|
|
1307
1380
|
if (verifyPubKey !== void 0) {
|
|
1308
1381
|
verifyResponseSignature(bodyBytes, resp, verifyPubKey);
|
|
1309
1382
|
}
|
|
1310
|
-
const
|
|
1383
|
+
const parsed = tryParseJson(bodyBytes.toString("utf-8"));
|
|
1384
|
+
if (!isRecord2(parsed)) {
|
|
1385
|
+
throw new JudgeRefusalError(
|
|
1386
|
+
"The judge's reply could not be read, so the action was not approved."
|
|
1387
|
+
);
|
|
1388
|
+
}
|
|
1389
|
+
const data = parsed;
|
|
1311
1390
|
const rawScore = data.score;
|
|
1312
1391
|
const score = typeof rawScore === "number" && Number.isInteger(rawScore) && rawScore >= 1 && rawScore <= 10 ? rawScore : void 0;
|
|
1313
|
-
|
|
1392
|
+
const result = {
|
|
1314
1393
|
verdict: normalizeVerdict(data.verdict),
|
|
1315
1394
|
allow: this.executable(data),
|
|
1316
1395
|
actionType: normalizeActionType(data.action_type),
|
|
@@ -1326,6 +1405,45 @@ config.json still holds an "agentKey" (${identity}), but a settings file no long
|
|
|
1326
1405
|
score,
|
|
1327
1406
|
refusal: explicitRefusal(data)
|
|
1328
1407
|
};
|
|
1408
|
+
return this.applyJailHold(result, startedAt);
|
|
1409
|
+
}
|
|
1410
|
+
/**
|
|
1411
|
+
* Start a local hold on an enforced, on-chain BLOCK (the verdict that jails).
|
|
1412
|
+
* Refuse any other result that lands while the agent is held, or whose
|
|
1413
|
+
* request was already in flight when the block arrived: the server judged it
|
|
1414
|
+
* on pre-jail state.
|
|
1415
|
+
*/
|
|
1416
|
+
applyJailHold(result, startedAt) {
|
|
1417
|
+
const pubkey = this.auth.pubkey;
|
|
1418
|
+
if (result.verdict === "BLOCK" && result.enforced && result.onChain) {
|
|
1419
|
+
recordBlock(pubkey);
|
|
1420
|
+
holdJail(
|
|
1421
|
+
pubkey,
|
|
1422
|
+
() => this.getAgentPolicy(pubkey).then((p) => p.isJailed),
|
|
1423
|
+
() => this.logger.warn?.("[atbash] local jail hold released: the chain did not confirm the jail in time")
|
|
1424
|
+
);
|
|
1425
|
+
return result;
|
|
1426
|
+
}
|
|
1427
|
+
return isJailHeld(pubkey) || blockedSince(pubkey, startedAt) ? this.localJailBlock(result.toolCallId) : result;
|
|
1428
|
+
}
|
|
1429
|
+
/** The server's jailed refusal, produced locally while the agent is held. */
|
|
1430
|
+
localJailBlock(toolCallId = generateToolCallId()) {
|
|
1431
|
+
return {
|
|
1432
|
+
verdict: "BLOCK",
|
|
1433
|
+
allow: false,
|
|
1434
|
+
actionType: "block",
|
|
1435
|
+
reason: "Agent is jailed. All actions are blocked until the organization owner unjails this agent.",
|
|
1436
|
+
confidence: 1,
|
|
1437
|
+
provider: "policy",
|
|
1438
|
+
latencyMs: 0,
|
|
1439
|
+
toolCallId,
|
|
1440
|
+
onChain: false,
|
|
1441
|
+
enforced: true,
|
|
1442
|
+
enforcementMode: "enforce",
|
|
1443
|
+
status: "",
|
|
1444
|
+
score: void 0,
|
|
1445
|
+
refusal: "BLOCK"
|
|
1446
|
+
};
|
|
1329
1447
|
}
|
|
1330
1448
|
/* ── audit_tool_call (redact → judge → decision) ───────────────────────── */
|
|
1331
1449
|
/**
|
|
@@ -1377,6 +1495,9 @@ config.json still holds an "agentKey" (${identity}), but a settings file no long
|
|
|
1377
1495
|
reason: `The judge's reply failed its signature check (${errorMessage(err)}), so it was not trusted.`
|
|
1378
1496
|
};
|
|
1379
1497
|
}
|
|
1498
|
+
if (err instanceof JudgeRefusalError || err instanceof AtbashAPIError && isRefusalStatus(err.status)) {
|
|
1499
|
+
return { ...this.failJudge(errorMessage(err), err), allow: false };
|
|
1500
|
+
}
|
|
1380
1501
|
return this.failJudge(errorMessage(err), err);
|
|
1381
1502
|
}
|
|
1382
1503
|
}
|
|
@@ -1406,6 +1527,15 @@ config.json still holds an "agentKey" (${identity}), but a settings file no long
|
|
|
1406
1527
|
* never overrides a refusal.
|
|
1407
1528
|
*/
|
|
1408
1529
|
decide(result) {
|
|
1530
|
+
const inner = this.decideInner(result);
|
|
1531
|
+
if (!result.enforcementMode) return inner;
|
|
1532
|
+
return {
|
|
1533
|
+
...inner,
|
|
1534
|
+
enforced: result.enforced,
|
|
1535
|
+
enforcementMode: result.enforcementMode
|
|
1536
|
+
};
|
|
1537
|
+
}
|
|
1538
|
+
decideInner(result) {
|
|
1409
1539
|
const toolCallId = result.toolCallId;
|
|
1410
1540
|
const deny = (verdict, reason) => ({
|
|
1411
1541
|
allow: false,
|
|
@@ -1519,17 +1649,17 @@ config.json still holds an "agentKey" (${identity}), but a settings file no long
|
|
|
1519
1649
|
/**
|
|
1520
1650
|
* Return the current status of a previously submitted judgment.
|
|
1521
1651
|
*
|
|
1522
|
-
* `chainOpts` names which chain the judgment was signed against
|
|
1523
|
-
*
|
|
1524
|
-
*
|
|
1525
|
-
*
|
|
1526
|
-
*
|
|
1527
|
-
*
|
|
1652
|
+
* `chainOpts` names which chain the judgment was signed against; the SDK
|
|
1653
|
+
* sends it as the `brid` query param the server routes by. Without it the
|
|
1654
|
+
* read uses the same chain `judgeAction` signs for (see `callBrid`): the
|
|
1655
|
+
* client's org chain when it has an `orgName`, else the client default.
|
|
1656
|
+
* A judgment signed with an explicit per-call `chainOpts` (or a per-call
|
|
1657
|
+
* `orgName` on another chain) must be polled with that same `chainOpts`.
|
|
1528
1658
|
*/
|
|
1529
1659
|
async getJudgmentStatus(judgmentId, agentPubkey, chainOpts) {
|
|
1530
1660
|
const pk = agentPubkey ?? this.auth.pubkey;
|
|
1531
|
-
const brid = this.bridFromChainOpts(chainOpts);
|
|
1532
1661
|
return this.track("getJudgmentStatus", pk, async () => {
|
|
1662
|
+
const brid = await this.callBrid(chainOpts);
|
|
1533
1663
|
const resp = await this.http.get(
|
|
1534
1664
|
"/api/v1/judge",
|
|
1535
1665
|
{ tool_call_id: judgmentId, agent_pubkey: pk, brid },
|
|
@@ -1734,21 +1864,16 @@ config.json still holds an "agentKey" (${identity}), but a settings file no long
|
|
|
1734
1864
|
}
|
|
1735
1865
|
if (resp.status !== 200) throw await this.httpError(resp);
|
|
1736
1866
|
const data = await this.json(resp);
|
|
1737
|
-
if (data?.network === "
|
|
1738
|
-
return data.network;
|
|
1739
|
-
}
|
|
1867
|
+
if (data?.network === "private") return data.network;
|
|
1740
1868
|
return null;
|
|
1741
1869
|
}
|
|
1742
1870
|
/**
|
|
1743
1871
|
* Resolve which chain an org's actions should run against. Cached
|
|
1744
1872
|
* per-client by orgName. Resolution order:
|
|
1745
1873
|
* 1. `org_networks` map (authoritative).
|
|
1746
|
-
* 2.
|
|
1747
|
-
*
|
|
1748
|
-
*
|
|
1749
|
-
* A lookup that names exactly one chain wins outright. Where it names
|
|
1750
|
-
* neither (a brand-new org) or cannot choose between them, the client's
|
|
1751
|
-
* configured default decides.
|
|
1874
|
+
* 2. Subscription fallback — the org's subscription row on the chain.
|
|
1875
|
+
* A lookup that finds the org wins outright. Where it finds nothing (a
|
|
1876
|
+
* brand-new org), the client's configured default decides.
|
|
1752
1877
|
*/
|
|
1753
1878
|
async resolveChainForOrg(orgName) {
|
|
1754
1879
|
const name = orgName.trim();
|
|
@@ -1770,35 +1895,14 @@ config.json still holds an "agentKey" (${identity}), but a settings file no long
|
|
|
1770
1895
|
const cached = this._chainCache.get(orgName);
|
|
1771
1896
|
if (cached) return cached;
|
|
1772
1897
|
if (mapNetwork) {
|
|
1773
|
-
const chain = mapNetwork
|
|
1898
|
+
const chain = chainForNetwork(mapNetwork);
|
|
1774
1899
|
this._chainCache.set(orgName, chain);
|
|
1775
1900
|
return chain;
|
|
1776
1901
|
}
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
this.getOrgSubscription(orgName, "private")
|
|
1780
|
-
|
|
1781
|
-
const pubSub = pubRes.status === "fulfilled" ? pubRes.value : null;
|
|
1782
|
-
const privSub = privRes.status === "fulfilled" ? privRes.value : null;
|
|
1783
|
-
const failure2 = pubRes.status === "rejected" ? pubRes.reason : privRes.status === "rejected" ? privRes.reason : null;
|
|
1784
|
-
if (pubSub?.is_private_blockchain) {
|
|
1785
|
-
this._chainCache.set(orgName, PRIVATE_CHAIN);
|
|
1786
|
-
return PRIVATE_CHAIN;
|
|
1787
|
-
}
|
|
1788
|
-
if (pubSub && privSub) {
|
|
1789
|
-
const chain = privSub.assigned_at === pubSub.assigned_at ? this._defaultChain : privSub.assigned_at > pubSub.assigned_at ? PRIVATE_CHAIN : PUBLIC_CHAIN;
|
|
1790
|
-
this._chainCache.set(orgName, chain);
|
|
1791
|
-
return chain;
|
|
1792
|
-
}
|
|
1793
|
-
if (pubSub) {
|
|
1794
|
-
this._chainCache.set(orgName, PUBLIC_CHAIN);
|
|
1795
|
-
return PUBLIC_CHAIN;
|
|
1796
|
-
}
|
|
1797
|
-
if (privSub?.is_private_blockchain) {
|
|
1798
|
-
this._chainCache.set(orgName, PRIVATE_CHAIN);
|
|
1799
|
-
return PRIVATE_CHAIN;
|
|
1800
|
-
}
|
|
1801
|
-
if (failure2) {
|
|
1902
|
+
let privSub;
|
|
1903
|
+
try {
|
|
1904
|
+
privSub = await this.getOrgSubscription(orgName, "private");
|
|
1905
|
+
} catch (failure2) {
|
|
1802
1906
|
const detail = failure2 instanceof Error ? failure2.message : String(failure2);
|
|
1803
1907
|
throw new AtbashAPIError(
|
|
1804
1908
|
failure2 instanceof AtbashAPIError ? failure2.status : 0,
|
|
@@ -1807,6 +1911,10 @@ config.json still holds an "agentKey" (${identity}), but a settings file no long
|
|
|
1807
1911
|
this.endpoint
|
|
1808
1912
|
);
|
|
1809
1913
|
}
|
|
1914
|
+
if (privSub) {
|
|
1915
|
+
this._chainCache.set(orgName, PRIVATE_CHAIN);
|
|
1916
|
+
return PRIVATE_CHAIN;
|
|
1917
|
+
}
|
|
1810
1918
|
this._chainCache.set(orgName, this._defaultChain);
|
|
1811
1919
|
return this._defaultChain;
|
|
1812
1920
|
}
|
|
@@ -1863,10 +1971,21 @@ config.json still holds an "agentKey" (${identity}), but a settings file no long
|
|
|
1863
1971
|
*/
|
|
1864
1972
|
bridFromChainOpts(chainOpts) {
|
|
1865
1973
|
if (chainOpts?.blockchainRid) return chainOpts.blockchainRid;
|
|
1866
|
-
if (chainOpts?.network
|
|
1867
|
-
if (chainOpts?.network === "public") return PUBLIC_CHAIN.blockchainRid;
|
|
1974
|
+
if (chainOpts?.network) return chainForNetwork(chainOpts.network).blockchainRid;
|
|
1868
1975
|
return this.blockchainRid;
|
|
1869
1976
|
}
|
|
1977
|
+
/**
|
|
1978
|
+
* The chain one call's transactions are signed for: the per-call override
|
|
1979
|
+
* when given, otherwise the client's org, otherwise the client default.
|
|
1980
|
+
* log_tool_call, judge_action and the judgment-status read all use this, so
|
|
1981
|
+
* a request never pairs transactions signed for two different chains.
|
|
1982
|
+
*/
|
|
1983
|
+
async callBrid(chainOpts) {
|
|
1984
|
+
if (chainOpts?.blockchainRid || chainOpts?.network) {
|
|
1985
|
+
return this.bridFromChainOpts(chainOpts);
|
|
1986
|
+
}
|
|
1987
|
+
return await this.defaultOrgBrid() ?? this.blockchainRid;
|
|
1988
|
+
}
|
|
1870
1989
|
/**
|
|
1871
1990
|
* Resolve the dashboard chain used by agent metadata/policy reads.
|
|
1872
1991
|
* Explicit per-call network overrides win; otherwise use the supplied org
|
|
@@ -1912,8 +2031,8 @@ config.json still holds an "agentKey" (${identity}), but a settings file no long
|
|
|
1912
2031
|
async riskEnginePost(body, network, brid) {
|
|
1913
2032
|
let resp;
|
|
1914
2033
|
try {
|
|
1915
|
-
const
|
|
1916
|
-
resp = await this.http.post(
|
|
2034
|
+
const path4 = network ? `/api/risk-engine?network=${encodeURIComponent(network)}` : "/api/risk-engine";
|
|
2035
|
+
resp = await this.http.post(path4, body, this.authHeaders(brid));
|
|
1917
2036
|
} catch (err) {
|
|
1918
2037
|
throw this.transportError(err);
|
|
1919
2038
|
}
|
|
@@ -2174,10 +2293,6 @@ function tryParseJson(text) {
|
|
|
2174
2293
|
return void 0;
|
|
2175
2294
|
}
|
|
2176
2295
|
}
|
|
2177
|
-
function parseJson(bytes) {
|
|
2178
|
-
const parsed = tryParseJson(bytes.toString("utf-8"));
|
|
2179
|
-
return parsed === void 0 ? {} : parsed;
|
|
2180
|
-
}
|
|
2181
2296
|
function requestPath(url) {
|
|
2182
2297
|
if (!url) return void 0;
|
|
2183
2298
|
try {
|
|
@@ -2453,13 +2568,13 @@ function resolveBlockchainRid(chainOpts) {
|
|
|
2453
2568
|
if (chainOpts?.blockchainRid !== void 0) return chainOpts.blockchainRid;
|
|
2454
2569
|
if (chainOpts?.nodeUrls !== void 0) {
|
|
2455
2570
|
throw new Error(
|
|
2456
|
-
'chainOpts.nodeUrls no longer selects a chain on its own \u2014 memory reaches the chain through the Atbash service, not a node. Set `blockchainRid`, or `network: "
|
|
2571
|
+
'chainOpts.nodeUrls no longer selects a chain on its own \u2014 memory reaches the chain through the Atbash service, not a node. Set `blockchainRid`, or `network: "private"`.'
|
|
2457
2572
|
);
|
|
2458
2573
|
}
|
|
2459
|
-
const
|
|
2574
|
+
const config2 = chainForNetwork(
|
|
2460
2575
|
chainOpts?.network ?? forcedChainNetwork() ?? "private"
|
|
2461
2576
|
);
|
|
2462
|
-
return
|
|
2577
|
+
return config2.blockchainRid;
|
|
2463
2578
|
}
|
|
2464
2579
|
async function commitMemoryVersion(plaintext, auth, opts) {
|
|
2465
2580
|
const key = await deriveMemoryKey(auth.privkey);
|
|
@@ -2685,7 +2800,34 @@ function classifyMemoryWrite(event, ctx, opts = {}) {
|
|
|
2685
2800
|
// src-ts/memory/guard.ts
|
|
2686
2801
|
import { promises as fs } from "fs";
|
|
2687
2802
|
import os from "os";
|
|
2688
|
-
|
|
2803
|
+
|
|
2804
|
+
// src-ts/memory/slot.ts
|
|
2805
|
+
import nodePath from "path";
|
|
2806
|
+
function asciiLower(s) {
|
|
2807
|
+
return s.replace(/[A-Z]/g, (c) => String.fromCharCode(c.charCodeAt(0) | 32));
|
|
2808
|
+
}
|
|
2809
|
+
function spelledAs(target, base, p = nodePath) {
|
|
2810
|
+
const resolved = p.resolve(base);
|
|
2811
|
+
if (p.sep !== "\\") return resolved;
|
|
2812
|
+
const prefix = resolved.replace(/[\\/]+$/, "");
|
|
2813
|
+
const t = asciiLower(target);
|
|
2814
|
+
const b = asciiLower(prefix);
|
|
2815
|
+
if (t === b || t.startsWith(b + "\\") || t.startsWith(b + "/")) {
|
|
2816
|
+
return target.slice(0, prefix.length);
|
|
2817
|
+
}
|
|
2818
|
+
return resolved;
|
|
2819
|
+
}
|
|
2820
|
+
function memorySlotOf(target, home2, root, extraHomes, p = nodePath) {
|
|
2821
|
+
const resolved = p.resolve(target);
|
|
2822
|
+
return native.memorySlotForPath(
|
|
2823
|
+
resolved,
|
|
2824
|
+
home2 ? spelledAs(resolved, home2, p) : "",
|
|
2825
|
+
root ? spelledAs(resolved, root, p) : void 0,
|
|
2826
|
+
extraHomes
|
|
2827
|
+
);
|
|
2828
|
+
}
|
|
2829
|
+
|
|
2830
|
+
// src-ts/memory/guard.ts
|
|
2689
2831
|
function emitDebugProbe(event, ctx, memEntry, logger2) {
|
|
2690
2832
|
if (!logger2?.info) return;
|
|
2691
2833
|
const ev = event ?? {};
|
|
@@ -2711,7 +2853,7 @@ function emitDebugProbe(event, ctx, memEntry, logger2) {
|
|
|
2711
2853
|
}
|
|
2712
2854
|
function memorySlotFor(key, root, extraHomes) {
|
|
2713
2855
|
const home2 = process.env.HOME || os.homedir() || "";
|
|
2714
|
-
return
|
|
2856
|
+
return memorySlotOf(key, home2, root, extraHomes);
|
|
2715
2857
|
}
|
|
2716
2858
|
async function resultingDocument(memEntry, event, ctx) {
|
|
2717
2859
|
const edits = native.extractMemoryEdits(event, ctx);
|
|
@@ -2914,7 +3056,7 @@ async function syncLocalMemory(auth, pointer, opts = {}) {
|
|
|
2914
3056
|
|
|
2915
3057
|
// src-ts/memory/pointer-store.ts
|
|
2916
3058
|
import { promises as fs2 } from "fs";
|
|
2917
|
-
import
|
|
3059
|
+
import path from "path";
|
|
2918
3060
|
var VERSION = 2;
|
|
2919
3061
|
var ZERO = { activeId: null, checkedAt: 0 };
|
|
2920
3062
|
var PointerStore = class {
|
|
@@ -2967,19 +3109,19 @@ var PointerStore = class {
|
|
|
2967
3109
|
this.cache = { version: VERSION, agents: {} };
|
|
2968
3110
|
}
|
|
2969
3111
|
async persist(file) {
|
|
2970
|
-
await fs2.mkdir(
|
|
3112
|
+
await fs2.mkdir(path.dirname(this.filePath), { recursive: true });
|
|
2971
3113
|
const tmp = `${this.filePath}.${process.pid}.tmp`;
|
|
2972
3114
|
await fs2.writeFile(tmp, JSON.stringify(file, null, 2), "utf8");
|
|
2973
3115
|
await fs2.rename(tmp, this.filePath);
|
|
2974
3116
|
}
|
|
2975
3117
|
};
|
|
2976
3118
|
function defaultPointerPath(workspaceDir = process.cwd()) {
|
|
2977
|
-
return
|
|
3119
|
+
return path.join(workspaceDir, ".atbash", "memory-pointer.json");
|
|
2978
3120
|
}
|
|
2979
3121
|
|
|
2980
3122
|
// src-ts/memory/file-logger.ts
|
|
2981
3123
|
import { promises as fs3 } from "fs";
|
|
2982
|
-
import
|
|
3124
|
+
import path2 from "path";
|
|
2983
3125
|
function formatMeta(meta) {
|
|
2984
3126
|
if (!meta || Object.keys(meta).length === 0) return "";
|
|
2985
3127
|
try {
|
|
@@ -2992,7 +3134,7 @@ function createFileLogger(filePath, upstream) {
|
|
|
2992
3134
|
let queue = Promise.resolve();
|
|
2993
3135
|
let writeError;
|
|
2994
3136
|
async function ensureDir() {
|
|
2995
|
-
await fs3.mkdir(
|
|
3137
|
+
await fs3.mkdir(path2.dirname(filePath), { recursive: true });
|
|
2996
3138
|
}
|
|
2997
3139
|
function append(level, message, meta) {
|
|
2998
3140
|
const line = `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${message}${formatMeta(meta)}
|
|
@@ -3018,7 +3160,7 @@ function createFileLogger(filePath, upstream) {
|
|
|
3018
3160
|
};
|
|
3019
3161
|
}
|
|
3020
3162
|
function defaultPluginLogPath(workspaceDir = process.cwd()) {
|
|
3021
|
-
return
|
|
3163
|
+
return path2.join(workspaceDir, ".atbash", "plugin.log");
|
|
3022
3164
|
}
|
|
3023
3165
|
|
|
3024
3166
|
// src-ts/memory/read-classifier.ts
|
|
@@ -3034,14 +3176,14 @@ function classifyMemoryRead(event, ctx, opts = {}) {
|
|
|
3034
3176
|
// src-ts/memory/guard-manager.ts
|
|
3035
3177
|
import { promises as fs4 } from "fs";
|
|
3036
3178
|
import os2 from "os";
|
|
3037
|
-
import
|
|
3179
|
+
import path3 from "path";
|
|
3038
3180
|
var DEFAULT_SYNC_TTL_MS = 3e4;
|
|
3039
3181
|
var MemoryGuardManager = class {
|
|
3040
3182
|
constructor(opts) {
|
|
3041
3183
|
this.opts = opts;
|
|
3042
3184
|
const workspaceDir = opts.workspaceDir;
|
|
3043
3185
|
this.workspaceDir = workspaceDir;
|
|
3044
|
-
this.memoryFilePath = opts.memoryFilePath ??
|
|
3186
|
+
this.memoryFilePath = opts.memoryFilePath ?? path3.join(workspaceDir, "MEMORY.md");
|
|
3045
3187
|
this.pointerStore = new PointerStore(opts.pointerFilePath ?? defaultPointerPath(workspaceDir));
|
|
3046
3188
|
this.logger = createFileLogger(
|
|
3047
3189
|
opts.logFilePath ?? defaultPluginLogPath(workspaceDir),
|
|
@@ -3256,7 +3398,7 @@ var MemoryGuardManager = class {
|
|
|
3256
3398
|
*/
|
|
3257
3399
|
async locate(slot, roots) {
|
|
3258
3400
|
for (const root of roots) {
|
|
3259
|
-
const candidate =
|
|
3401
|
+
const candidate = path3.join(root, slot);
|
|
3260
3402
|
try {
|
|
3261
3403
|
await fs4.access(candidate);
|
|
3262
3404
|
return candidate;
|
|
@@ -3271,7 +3413,7 @@ var MemoryGuardManager = class {
|
|
|
3271
3413
|
/** Roots a chain slot may be joined to, most specific first. */
|
|
3272
3414
|
async memoryRoots() {
|
|
3273
3415
|
const roots = [];
|
|
3274
|
-
if (this.opts.memoryRoot) roots.push(
|
|
3416
|
+
if (this.opts.memoryRoot) roots.push(path3.resolve(this.opts.memoryRoot));
|
|
3275
3417
|
const home2 = process.env.HOME || os2.homedir() || "";
|
|
3276
3418
|
if (home2) {
|
|
3277
3419
|
const names = [
|
|
@@ -3279,7 +3421,7 @@ var MemoryGuardManager = class {
|
|
|
3279
3421
|
...this.opts.agentHomeDirs ?? []
|
|
3280
3422
|
];
|
|
3281
3423
|
for (const name of names) {
|
|
3282
|
-
const candidate =
|
|
3424
|
+
const candidate = path3.join(home2, name);
|
|
3283
3425
|
try {
|
|
3284
3426
|
if ((await fs4.stat(candidate)).isDirectory()) roots.push(candidate);
|
|
3285
3427
|
} catch {
|
|
@@ -3417,7 +3559,7 @@ var MemoryGuardManager = class {
|
|
|
3417
3559
|
const rec = bag;
|
|
3418
3560
|
for (const k of KEYS) {
|
|
3419
3561
|
const v = rec[k];
|
|
3420
|
-
if (typeof v === "string" && v) found.add(
|
|
3562
|
+
if (typeof v === "string" && v) found.add(path3.resolve(this.workspaceDir, v));
|
|
3421
3563
|
}
|
|
3422
3564
|
}
|
|
3423
3565
|
}
|
|
@@ -3464,12 +3606,7 @@ var MemoryGuardManager = class {
|
|
|
3464
3606
|
*/
|
|
3465
3607
|
slotFor(target) {
|
|
3466
3608
|
const home2 = process.env.HOME || os2.homedir() || "";
|
|
3467
|
-
return
|
|
3468
|
-
path4.resolve(target),
|
|
3469
|
-
home2,
|
|
3470
|
-
this.opts.memoryRoot,
|
|
3471
|
-
this.opts.agentHomeDirs
|
|
3472
|
-
);
|
|
3609
|
+
return memorySlotOf(target, home2, this.opts.memoryRoot, this.opts.agentHomeDirs);
|
|
3473
3610
|
}
|
|
3474
3611
|
/**
|
|
3475
3612
|
* Verify every memory file this call reads, each against its own chain slot.
|
|
@@ -3618,7 +3755,7 @@ var MemoryGuardManager = class {
|
|
|
3618
3755
|
}
|
|
3619
3756
|
/** Replace `target` in one step, so a reader never sees a half-written file. */
|
|
3620
3757
|
async writeFileAtomic(target, content) {
|
|
3621
|
-
await fs4.mkdir(
|
|
3758
|
+
await fs4.mkdir(path3.dirname(target), { recursive: true });
|
|
3622
3759
|
const tmp = `${target}.${process.pid}.tmp`;
|
|
3623
3760
|
await fs4.writeFile(tmp, content, "utf8");
|
|
3624
3761
|
await fs4.rename(tmp, target);
|
|
@@ -3749,8 +3886,6 @@ export {
|
|
|
3749
3886
|
Atbash,
|
|
3750
3887
|
AtbashAPIError,
|
|
3751
3888
|
BOOT_SYNC_HINT,
|
|
3752
|
-
DEFAULT_BLOCKCHAIN_RID,
|
|
3753
|
-
DEFAULT_CHROMIA_NODE_URLS,
|
|
3754
3889
|
DEFAULT_ENDPOINT,
|
|
3755
3890
|
DEFAULT_MEMORY_PATH_PATTERNS,
|
|
3756
3891
|
DEFAULT_MEMORY_READ_TOOL_NAMES,
|
|
@@ -3758,11 +3893,11 @@ export {
|
|
|
3758
3893
|
EciesDomain,
|
|
3759
3894
|
HttpClient,
|
|
3760
3895
|
HttpTransportError,
|
|
3896
|
+
JudgeRefusalError,
|
|
3761
3897
|
KEY_FILENAMES,
|
|
3762
3898
|
MemoryGuardManager,
|
|
3763
3899
|
MemoryIntegrityError,
|
|
3764
3900
|
PRIVATE_CHAIN,
|
|
3765
|
-
PUBLIC_CHAIN,
|
|
3766
3901
|
PointerStore,
|
|
3767
3902
|
SignatureVerificationError,
|
|
3768
3903
|
bootSyncFailureLine,
|
|
@@ -3776,6 +3911,7 @@ export {
|
|
|
3776
3911
|
columnAad,
|
|
3777
3912
|
commitMemoryVersion,
|
|
3778
3913
|
configureEvents,
|
|
3914
|
+
configureJailHold,
|
|
3779
3915
|
containsEvasionCharacters,
|
|
3780
3916
|
containsSecret,
|
|
3781
3917
|
createFileLogger,
|
|
@@ -3804,12 +3940,14 @@ export {
|
|
|
3804
3940
|
getRollbackHistory,
|
|
3805
3941
|
guardMemoryWrite,
|
|
3806
3942
|
isEnvelope,
|
|
3943
|
+
isJailHeld,
|
|
3807
3944
|
isValidPrivateKey,
|
|
3808
3945
|
keyFingerprintOf,
|
|
3809
3946
|
keyPathCandidates,
|
|
3810
3947
|
loadAgent,
|
|
3811
3948
|
loadAgentFromFile,
|
|
3812
3949
|
loadUserConfig,
|
|
3950
|
+
memorySlotOf,
|
|
3813
3951
|
normalizeActionForHash,
|
|
3814
3952
|
normalizeActionType,
|
|
3815
3953
|
normalizeForMatching,
|
|
@@ -3823,6 +3961,7 @@ export {
|
|
|
3823
3961
|
recordEvent,
|
|
3824
3962
|
redactJsonStrings,
|
|
3825
3963
|
redactSecrets,
|
|
3964
|
+
releaseJailHolds,
|
|
3826
3965
|
resolve,
|
|
3827
3966
|
resolveKeyPath,
|
|
3828
3967
|
rollbackMemory,
|