@atbash/sdk 0.10.6-dev.0 → 0.10.9-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.
@@ -310,6 +310,12 @@ interface AtbashOptions {
310
310
  orgEncryptionPubKey?: string;
311
311
  /** When true (default), `auditToolCall` denies on any error. */
312
312
  failClosed?: boolean;
313
+ /**
314
+ * Verbose diagnostics. Off by default. When on, a failed judge call also
315
+ * logs the response body, which is the difference between "judge API failed"
316
+ * and knowing why it failed. Opt-in because that body can echo the action.
317
+ */
318
+ debug?: boolean;
313
319
  logger?: AtbashLogger;
314
320
  }
315
321
  /** Canonical decision returned by `auditToolCall`. */
@@ -350,6 +356,8 @@ interface FromConfigOptions {
350
356
  /** Default org name — see {@link AtbashOptions.orgName}. */
351
357
  orgName?: string;
352
358
  failClosed?: boolean;
359
+ /** See {@link AtbashOptions.debug}. */
360
+ debug?: boolean;
353
361
  logger?: AtbashLogger;
354
362
  }
355
363
  /** Options accepted by `judgeAction`. */
@@ -414,6 +422,7 @@ declare class Atbash {
414
422
  readonly failClosed: boolean;
415
423
  /** Org key learned from the last agent-exists check, for this agent only. */
416
424
  private _orgKeyFromChain;
425
+ private readonly debug;
417
426
  private readonly logger;
418
427
  private readonly http;
419
428
  /**
@@ -427,7 +436,20 @@ declare class Atbash {
427
436
  * server-side replay protection windows never expire it mid-session.
428
437
  */
429
438
  private _authBearer;
439
+ /** Guards `logEnvironmentOnce` — hosts construct several clients. */
440
+ private static environmentLogged;
430
441
  constructor(privkey: string, options?: AtbashOptions);
442
+ /**
443
+ * Say which environment this build talks to, once per process.
444
+ *
445
+ * The endpoint and both chain RIDs are compiled in, chosen by the npm tag,
446
+ * and no configuration repoints a released build. So installing the build
447
+ * for the wrong environment is invisible: the plugin loads, the hook fires,
448
+ * and every judge call fails because the agent does not exist on the chain
449
+ * this build targets. Organisation names are not unique across environments
450
+ * either, so an org resolving is not evidence the build is right.
451
+ */
452
+ private logEnvironmentOnce;
431
453
  /**
432
454
  * Construct from resolved config: explicit overrides → env vars → the
433
455
  * `~/.config/atbash/config.json` file (see userConfig.resolve). The private
@@ -470,6 +492,15 @@ declare class Atbash {
470
492
  * explicitly false.
471
493
  */
472
494
  auditToolCall(input: ToolCallInput): Promise<Decision>;
495
+ /**
496
+ * One exit for every judge failure.
497
+ *
498
+ * Status and reason go in the *message*, not only in the meta object: hosts
499
+ * print the message and drop the meta, which is why this read as a bare
500
+ * "judge API failed" while the judge was answering with a precise reason.
501
+ * The response body follows only under `debug`, since it can echo the action.
502
+ */
503
+ private failJudge;
473
504
  private fail;
474
505
  getJudgmentStatus(judgmentId: string, agentPubkey?: string): Promise<JudgmentStatus>;
475
506
  getToolCalls(maxCount: number): Promise<ToolCallRecord[]>;
@@ -545,7 +576,13 @@ declare class Atbash {
545
576
  private raiseIfError;
546
577
  /** Wrap a failed HTTP *response* (non-2xx / non-200) as an AtbashAPIError. */
547
578
  private httpError;
548
- /** Wrap a *transport* failure (fetch threw, no response) as an AtbashAPIError. */
579
+ /**
580
+ * Wrap a transport failure (fetch threw, no response) as an AtbashAPIError.
581
+ *
582
+ * `HttpTransportError.kind` names the cause; the message is already
583
+ * human-readable. `debug` echoes the original exception so operators can
584
+ * cross-reference with node / undici logs when a class doesn't match.
585
+ */
549
586
  private transportError;
550
587
  private json;
551
588
  static generateKeypair(): KeyPair;
@@ -571,6 +608,43 @@ declare class SignatureVerificationError extends Error {
571
608
  constructor(message: string);
572
609
  }
573
610
 
611
+ /**
612
+ * Thin typed fetch wrapper.
613
+ *
614
+ * openapi-typescript emits types only (no runtime client), so this is the
615
+ * single hand-written transport — generic `get`/`post` over global `fetch`
616
+ * with a per-request timeout. The endpoint-specific request/response *shapes*
617
+ * are pulled from the generated `schema.ts` at the call sites in client.ts, so
618
+ * the wire contract still lives in spec/openapi.yaml. Methods return the raw
619
+ * `Response` so the caller can read the exact bytes the server signed before
620
+ * any decode (judge signature verification) — mirroring the Python surface's
621
+ * use of raw httpx (DECISIONS 2026-05-22).
622
+ */
623
+ type QueryValue = string | number | boolean | undefined | null;
624
+ declare class HttpClient {
625
+ readonly baseUrl: string;
626
+ readonly timeoutMs: number;
627
+ constructor(baseUrl: string, timeoutMs: number);
628
+ buildUrl(path: string, query?: Record<string, QueryValue>): string;
629
+ get(path: string, query?: Record<string, QueryValue>, headers?: Record<string, string>): Promise<Response>;
630
+ post(path: string, body: unknown, headers?: Record<string, string>): Promise<Response>;
631
+ private fetch;
632
+ }
633
+ /**
634
+ * A transport failure the SDK can act on. Every real cause the platform surfaces
635
+ * lands as one of these — the message names the cause in plain language so a
636
+ * plugin can show it to a user without decoding httpx / fetch internals.
637
+ *
638
+ * `cause` preserves the original error for debug logging; consumers that want
639
+ * the raw exception (e.g. tests) read it there.
640
+ */
641
+ declare class HttpTransportError extends Error {
642
+ readonly kind: "timeout" | "aborted" | "dns" | "connect_refused" | "connection_reset" | "unknown";
643
+ constructor(kind: HttpTransportError["kind"], message: string, options?: {
644
+ cause?: unknown;
645
+ });
646
+ }
647
+
574
648
  /** Normalize wire shapes (verdict casing, status, pubkey) to canonical forms. */
575
649
 
576
650
  declare function normalizeVerdict(raw: unknown): Verdict;
@@ -585,6 +659,8 @@ interface AtbashUserConfig {
585
659
  blockchainRid?: string;
586
660
  provider?: string;
587
661
  providerModel?: string;
662
+ /** "1" / "true" turns on verbose diagnostics. See AtbashOptions.debug. */
663
+ debug?: string;
588
664
  }
589
665
  declare function getConfigDir(): string;
590
666
  declare function getConfigPath(): string;
@@ -595,6 +671,26 @@ declare function resolve(key: keyof AtbashUserConfig, flagValue?: string): strin
595
671
  declare function resolveKeyPath(input?: string): string;
596
672
  declare function loadAgentFromFile(keyPath?: string): AgentAuth;
597
673
 
674
+ /**
675
+ * Accepted key filenames, in precedence order.
676
+ *
677
+ * `guard-client-key` stays first: it is the name every existing install
678
+ * already has, and changing which file wins would silently switch agent
679
+ * identity for anyone holding both. `atbash-client-key` is accepted because
680
+ * it is the name people actually create — the old one carries retired
681
+ * branding — and hitting ENOENT on a key you just wrote, from a plugin that
682
+ * still reports itself installed, is a miserable first run.
683
+ */
684
+ declare const KEY_FILENAMES: readonly ["guard-client-key", "atbash-client-key"];
685
+ /** Every path checked when no explicit key path is given, in order. */
686
+ declare function keyPathCandidates(): string[];
687
+ /**
688
+ * Pick the key path: an explicit input wins untouched; otherwise the first
689
+ * accepted filename that exists, falling back to the preferred name so the
690
+ * error names something recognisable when nothing is there.
691
+ */
692
+ declare function chooseKeyPath(input: string | undefined, exists: (p: string) => boolean): string;
693
+
598
694
  /**
599
695
  * Canonical secret kinds reported by the Rust core in `SecretMatch.kind`.
600
696
  * Wire is permissive (modelled as a free string in {@link SecretMatch})
@@ -613,6 +709,26 @@ declare function verifyJudgeResponseSignature(bodyBytes: Uint8Array, signatureHe
613
709
  reason?: string;
614
710
  };
615
711
 
712
+ /**
713
+ * The boot memory-sync failure line.
714
+ *
715
+ * Split out of `guard-manager.ts` so it can be asserted without constructing a
716
+ * guard manager, which needs the native addon. The message is the whole point
717
+ * of AT-304: hosts print the message and drop the structured meta, so a cause
718
+ * that lives only in meta never reaches the operator.
719
+ */
720
+ /** Advice, not a diagnosis — appended only when the cause is unhelpful. */
721
+ declare const BOOT_SYNC_HINT = "check the chain endpoint and orgName if the cause above does not explain it";
722
+ /**
723
+ * Lead with the real cause.
724
+ *
725
+ * The previous wording named the chain endpoint and orgName as the things to
726
+ * check, which sent operators to verify configuration that was already correct
727
+ * while the actual cause (a node answering `404 Can't find blockchain with
728
+ * blockchainRID: …` for a chain it does not host) stayed hidden.
729
+ */
730
+ declare function bootSyncFailureLine(cause: unknown): string;
731
+
616
732
  /** Derive the 32-byte AES key from an agent's secp256k1 privkey (hex). Deterministic — same privkey always yields the same key. */
617
733
  declare function deriveMemoryKey(privkey: string): Promise<Buffer>;
618
734
  /** Encrypt UTF-8 plaintext. `ciphertext` has the 16-byte GCM auth tag appended, matching the SDK's on-chain byte layout. */
@@ -1164,4 +1280,4 @@ declare function containsSecret(text: string): boolean;
1164
1280
  declare function createMemorySnapshot(entries: MemoryEntry[], takenAt: number): MemorySnapshot;
1165
1281
  declare function diffMemorySnapshots(before: MemorySnapshot, after: MemorySnapshot): MemoryDiffResult;
1166
1282
 
1167
- export { type ActionType, type AgentAuth, type AgentMemoryEntry, type AgentPolicy, type AnomalySeverity, type AnomalyType, Atbash, AtbashAPIError, type AtbashLogger, type AtbashOptions, type AtbashUserConfig, type ChainOpts, type ClassifierToolContext, type ClassifierToolEvent, type ClassifyMemoryReadOptions, type ClassifyMemoryWriteOptions, type ClientSource, type CommitMemoryOptions, DEFAULT_BLOCKCHAIN_RID, DEFAULT_CHROMIA_NODE_URLS, DEFAULT_ENDPOINT, DEFAULT_MEMORY_PATH_PATTERNS, DEFAULT_MEMORY_READ_TOOL_NAMES, DEFAULT_MEMORY_WRITE_TOOL_NAMES, type Decision, type DecisionVerdict, EciesDomain, type EncryptedMemory, type Envelope, type FromConfigOptions, type GuardLogger, type GuardMemoryDecision, type GuardMemoryWriteInput, type GuardMemoryWriteResult, type HeldAction, type HeldActionReview, type HookDecision, type JudgeEndpointConfig, type JudgeOptions, type JudgeResult, type JudgmentState, type JudgmentStatus, type KeyPair, type LogToolCallOptions, type LogToolCallResult, type MemoryAnomaly, type MemoryDiffResult, type MemoryEntry, MemoryGuardManager, type MemoryGuardManagerOptions, MemoryIntegrityError, type MemoryPointer, type MemoryRollbackEvent, type MemoryScanOptions, type MemoryScanResult, type MemoryScanVerdict, type MemorySnapshot, type ModifiedEntry, type Network, type OrgSubscription, PointerStore, type Provider, type PubkeyValue, type RedactResult, type RollbackMemoryOptions, type SecretKind, type SecretMatch, SignatureVerificationError, type Subscription, type SyncMemoryOptions, type SyncMemoryResult, type TelemetryConfig, type TierInfo, type ToolCallFull, type ToolCallInput, type ToolCallRecord, type ValidatedEndpoint, type Verdict, type WrappedLogger, buildAllowedJudgeHosts, claimHashHex, classifyMemoryRead, classifyMemoryWrite, columnAad, commitMemoryVersion, containsEvasionCharacters, containsSecret, createFileLogger, createMemoryGuardManager, createMemorySnapshot, decryptForOrg, decryptMemoryContent, defaultPluginLogPath, defaultPointerPath, deriveMemoryKey, derivePublicKey, diffMemorySnapshots, encryptForOrg, encryptMemoryContent, encryptedLength, flushTelemetry, generateKeypair, getActiveMemory, getActiveMemoryId, getAllAgentMemory, getConfigDir, getConfigPath, getMemoryById, getMemoryHistory, getRollbackHistory, guardMemoryWrite, isEnvelope, isValidPrivateKey, keyFingerprintOf, loadAgent, loadAgentFromFile, loadUserConfig, normalizeActionForHash, normalizeForMatching, normalizeStatus, normalizeVerdict, packEnvelope, parseEnvelope, pubkeyToHex, recordCall, recordDuration, redactJsonStrings, redactSecrets, resolve, resolveKeyPath, rollbackMemory, saveUserConfig, scanMemory, scanMemoryBatch, setupTelemetry, shutdownTelemetry, signEncryptedToolCall, signJudgeAction, signLogToolCall, syncLocalMemory, validateJudgeEndpoint, verifyJudgeResponseSignature, verifySignature };
1283
+ export { type ActionType, type AgentAuth, type AgentMemoryEntry, type AgentPolicy, type AnomalySeverity, type AnomalyType, Atbash, AtbashAPIError, type AtbashLogger, type AtbashOptions, type AtbashUserConfig, BOOT_SYNC_HINT, type ChainOpts, type ClassifierToolContext, type ClassifierToolEvent, type ClassifyMemoryReadOptions, type ClassifyMemoryWriteOptions, type ClientSource, type CommitMemoryOptions, DEFAULT_BLOCKCHAIN_RID, DEFAULT_CHROMIA_NODE_URLS, DEFAULT_ENDPOINT, DEFAULT_MEMORY_PATH_PATTERNS, DEFAULT_MEMORY_READ_TOOL_NAMES, DEFAULT_MEMORY_WRITE_TOOL_NAMES, type Decision, type DecisionVerdict, EciesDomain, type EncryptedMemory, type Envelope, type FromConfigOptions, type GuardLogger, type GuardMemoryDecision, type GuardMemoryWriteInput, type GuardMemoryWriteResult, type HeldAction, type HeldActionReview, type HookDecision, HttpClient, HttpTransportError, type JudgeEndpointConfig, type JudgeOptions, type JudgeResult, type JudgmentState, type JudgmentStatus, KEY_FILENAMES, type KeyPair, type LogToolCallOptions, type LogToolCallResult, type MemoryAnomaly, type MemoryDiffResult, type MemoryEntry, MemoryGuardManager, type MemoryGuardManagerOptions, MemoryIntegrityError, type MemoryPointer, type MemoryRollbackEvent, type MemoryScanOptions, type MemoryScanResult, type MemoryScanVerdict, type MemorySnapshot, type ModifiedEntry, type Network, type OrgSubscription, PointerStore, type Provider, type PubkeyValue, type RedactResult, type RollbackMemoryOptions, type SecretKind, type SecretMatch, SignatureVerificationError, type Subscription, type SyncMemoryOptions, type SyncMemoryResult, type TelemetryConfig, type TierInfo, type ToolCallFull, type ToolCallInput, type ToolCallRecord, type ValidatedEndpoint, type Verdict, type WrappedLogger, bootSyncFailureLine, buildAllowedJudgeHosts, chooseKeyPath, claimHashHex, classifyMemoryRead, classifyMemoryWrite, columnAad, commitMemoryVersion, containsEvasionCharacters, containsSecret, createFileLogger, createMemoryGuardManager, createMemorySnapshot, decryptForOrg, decryptMemoryContent, defaultPluginLogPath, defaultPointerPath, deriveMemoryKey, derivePublicKey, diffMemorySnapshots, encryptForOrg, encryptMemoryContent, encryptedLength, flushTelemetry, generateKeypair, getActiveMemory, getActiveMemoryId, getAllAgentMemory, getConfigDir, getConfigPath, getMemoryById, getMemoryHistory, getRollbackHistory, guardMemoryWrite, isEnvelope, isValidPrivateKey, keyFingerprintOf, keyPathCandidates, loadAgent, loadAgentFromFile, loadUserConfig, normalizeActionForHash, normalizeForMatching, normalizeStatus, normalizeVerdict, packEnvelope, parseEnvelope, pubkeyToHex, recordCall, recordDuration, redactJsonStrings, redactSecrets, resolve, resolveKeyPath, rollbackMemory, saveUserConfig, scanMemory, scanMemoryBatch, setupTelemetry, shutdownTelemetry, signEncryptedToolCall, signJudgeAction, signLogToolCall, syncLocalMemory, validateJudgeEndpoint, verifyJudgeResponseSignature, verifySignature };
package/dist/browser.mjs CHANGED
@@ -12126,7 +12126,7 @@ function requireBuffer_list() {
12126
12126
  }
12127
12127
  }, {
12128
12128
  key: "join",
12129
- value: function join2(s2) {
12129
+ value: function join3(s2) {
12130
12130
  if (this.length === 0) return "";
12131
12131
  var p = this.head;
12132
12132
  var ret = "" + p.data;
@@ -16208,7 +16208,7 @@ function requireBufferList() {
16208
16208
  this.head = this.tail = null;
16209
16209
  this.length = 0;
16210
16210
  };
16211
- BufferList2.prototype.join = function join2(s2) {
16211
+ BufferList2.prototype.join = function join3(s2) {
16212
16212
  if (this.length === 0) return "";
16213
16213
  var p = this.head;
16214
16214
  var ret = "" + p.data;
@@ -30372,7 +30372,7 @@ function requireBuffer() {
30372
30372
  }
30373
30373
  }
30374
30374
  buffer.EncoderBuffer = EncoderBuffer2;
30375
- EncoderBuffer2.prototype.join = function join2(out, offset) {
30375
+ EncoderBuffer2.prototype.join = function join3(out, offset) {
30376
30376
  if (!out)
30377
30377
  out = new Buffer5(this.length);
30378
30378
  if (!offset)
@@ -43294,9 +43294,9 @@ var index = /* @__PURE__ */ getDefaultExportFromCjs(builtExports);
43294
43294
 
43295
43295
  // src-ts/browser/native.ts
43296
43296
  var { Buffer: Buffer3, gtx: pcgtx } = index;
43297
- var ATBASH_ENDPOINT = "https://atbash.ai";
43298
- var ATBASH_BLOCKCHAIN_RID = "0163241D9AF137638E63E48EFCDE15510F38C2426F7AD5DC726AF60351BF4DFE";
43299
- var ATBASH_PRIVATE_BLOCKCHAIN_RID = "39FFD3557D0296CB2C57FDC6A3B8C024E95639CF4964DA08141AC20C6344D408";
43297
+ var ATBASH_ENDPOINT = "https://chromia-verified-ai-dev-two.vercel.app";
43298
+ var ATBASH_BLOCKCHAIN_RID = "02668C5218871F69A93CC0F7032DCFFE06EF0D35EF2F0B07A92A3D83A3F23A7D";
43299
+ var ATBASH_PRIVATE_BLOCKCHAIN_RID = "2603569AE8DC3F254323F719C8D4347BBA964E874E781291F8474236BE8B6493";
43300
43300
  var DEFAULT_CHROMIA_NODE_URLS_ARR = define_ATBASH_CHROMIA_NODE_URLS_default;
43301
43301
  var DEFAULT_PRIVATE_NODE_URLS_ARR = define_ATBASH_PRIVATE_NODE_URLS_default;
43302
43302
  var MERKLE_HASH_VERSION = 2;
@@ -44478,9 +44478,69 @@ var HttpClient = class {
44478
44478
  });
44479
44479
  }
44480
44480
  async fetch(url, init4) {
44481
- return fetch(url, { ...init4, signal: AbortSignal.timeout(this.timeoutMs) });
44481
+ try {
44482
+ return await fetch(url, {
44483
+ ...init4,
44484
+ signal: AbortSignal.timeout(this.timeoutMs)
44485
+ });
44486
+ } catch (err) {
44487
+ throw classifyTransportError(err, url, init4.method ?? "GET", this.timeoutMs);
44488
+ }
44482
44489
  }
44483
44490
  };
44491
+ var HttpTransportError = class extends Error {
44492
+ kind;
44493
+ constructor(kind, message, options) {
44494
+ super(message, options);
44495
+ this.name = "HttpTransportError";
44496
+ this.kind = kind;
44497
+ }
44498
+ };
44499
+ function classifyTransportError(err, url, method, timeoutMs) {
44500
+ const name2 = err instanceof Error ? err.name : "";
44501
+ const cause = err instanceof Error ? err.cause : void 0;
44502
+ const code2 = cause && typeof cause === "object" && "code" in cause ? String(cause.code) : "";
44503
+ if (name2 === "TimeoutError") {
44504
+ return new HttpTransportError(
44505
+ "timeout",
44506
+ `${method} ${url} did not respond within ${timeoutMs} ms \u2014 the judge may be slow to boot or the LLM is under load; retry in a moment`,
44507
+ { cause: err }
44508
+ );
44509
+ }
44510
+ if (name2 === "AbortError") {
44511
+ return new HttpTransportError(
44512
+ "aborted",
44513
+ `${method} ${url} was cancelled by the caller`,
44514
+ { cause: err }
44515
+ );
44516
+ }
44517
+ if (code2 === "ENOTFOUND" || code2 === "EAI_AGAIN") {
44518
+ return new HttpTransportError(
44519
+ "dns",
44520
+ `could not resolve the judge hostname (${url}) \u2014 check the endpoint and DNS`,
44521
+ { cause: err }
44522
+ );
44523
+ }
44524
+ if (code2 === "ECONNREFUSED") {
44525
+ return new HttpTransportError(
44526
+ "connect_refused",
44527
+ `judge refused the connection (${url}) \u2014 the service may be down or restarting`,
44528
+ { cause: err }
44529
+ );
44530
+ }
44531
+ if (code2 === "ECONNRESET" || code2 === "EPIPE") {
44532
+ return new HttpTransportError(
44533
+ "connection_reset",
44534
+ `judge dropped the connection mid-request (${url}) \u2014 retry once`,
44535
+ { cause: err }
44536
+ );
44537
+ }
44538
+ return new HttpTransportError(
44539
+ "unknown",
44540
+ `${method} ${url} failed: ${err instanceof Error ? err.message : String(err)}`,
44541
+ { cause: err }
44542
+ );
44543
+ }
44484
44544
 
44485
44545
  // src-ts/browser/keyLoader.ts
44486
44546
  init_define_ATBASH_CHROMIA_NODE_URLS();
@@ -44573,6 +44633,7 @@ var Atbash = class _Atbash {
44573
44633
  failClosed;
44574
44634
  /** Org key learned from the last agent-exists check, for this agent only. */
44575
44635
  _orgKeyFromChain = null;
44636
+ debug;
44576
44637
  logger;
44577
44638
  http;
44578
44639
  /**
@@ -44586,6 +44647,8 @@ var Atbash = class _Atbash {
44586
44647
  * server-side replay protection windows never expire it mid-session.
44587
44648
  */
44588
44649
  _authBearer = null;
44650
+ /** Guards `logEnvironmentOnce` — hosts construct several clients. */
44651
+ static environmentLogged = false;
44589
44652
  constructor(privkey, options = {}) {
44590
44653
  this.auth = native.loadAgent(privkey);
44591
44654
  this.endpoint = (options.endpoint ?? DEFAULT_ENDPOINT).replace(/\/+$/, "") || DEFAULT_ENDPOINT;
@@ -44595,8 +44658,10 @@ var Atbash = class _Atbash {
44595
44658
  this.verifyPubKey = options.verifyPubKey;
44596
44659
  this.orgEncryptionPubKey = options.orgEncryptionPubKey;
44597
44660
  this.failClosed = options.failClosed !== false;
44661
+ this.debug = options.debug === true;
44598
44662
  this.logger = options.logger ?? {};
44599
- this.http = new HttpClient(this.endpoint, options.timeoutMs ?? 3e4);
44663
+ this.http = new HttpClient(this.endpoint, options.timeoutMs ?? 6e4);
44664
+ this.logEnvironmentOnce();
44600
44665
  if (this.endpoint !== DEFAULT_ENDPOINT) {
44601
44666
  this.logger.warn?.("[atbash] running on non-default judge endpoint", {
44602
44667
  endpoint: this.endpoint,
@@ -44604,6 +44669,31 @@ var Atbash = class _Atbash {
44604
44669
  });
44605
44670
  }
44606
44671
  }
44672
+ /**
44673
+ * Say which environment this build talks to, once per process.
44674
+ *
44675
+ * The endpoint and both chain RIDs are compiled in, chosen by the npm tag,
44676
+ * and no configuration repoints a released build. So installing the build
44677
+ * for the wrong environment is invisible: the plugin loads, the hook fires,
44678
+ * and every judge call fails because the agent does not exist on the chain
44679
+ * this build targets. Organisation names are not unique across environments
44680
+ * either, so an org resolving is not evidence the build is right.
44681
+ */
44682
+ logEnvironmentOnce() {
44683
+ if (_Atbash.environmentLogged) return;
44684
+ _Atbash.environmentLogged = true;
44685
+ const brief = (rid) => rid ? `${rid.slice(0, 8)}\u2026` : "(unset)";
44686
+ this.logger.info?.(
44687
+ `[atbash] environment \u2014 judge=${this.endpoint} publicChain=${brief(native.DEFAULT_BLOCKCHAIN_RID)} privateChain=${brief(native.DEFAULT_PRIVATE_BLOCKCHAIN_RID)} activeChain=${brief(this.blockchainRid)} responseSignatureCheck=${this.verifyPubKey ? "on" : "off"}`,
44688
+ {
44689
+ judgeEndpoint: this.endpoint,
44690
+ publicBlockchainRid: native.DEFAULT_BLOCKCHAIN_RID,
44691
+ privateBlockchainRid: native.DEFAULT_PRIVATE_BLOCKCHAIN_RID,
44692
+ activeBlockchainRid: this.blockchainRid,
44693
+ responseSignatureCheck: Boolean(this.verifyPubKey)
44694
+ }
44695
+ );
44696
+ }
44607
44697
  /**
44608
44698
  * Construct from resolved config: explicit overrides → env vars → the
44609
44699
  * `~/.config/atbash/config.json` file (see userConfig.resolve). The private
@@ -44627,6 +44717,9 @@ var Atbash = class _Atbash {
44627
44717
  orgName: options.orgName,
44628
44718
  verifyPubKey: validated.verifyPubKey ?? void 0,
44629
44719
  failClosed: options.failClosed,
44720
+ // ATBASH_DEBUG lets an operator turn diagnostics on without editing a
44721
+ // host's plugin config, which is usually the harder half.
44722
+ debug: options.debug ?? /^(1|true|yes)$/i.test(resolve("debug")),
44630
44723
  logger: options.logger
44631
44724
  });
44632
44725
  }
@@ -44872,8 +44965,9 @@ var Atbash = class _Atbash {
44872
44965
  });
44873
44966
  if (result.verdict === "No verdict") {
44874
44967
  if (result.status !== "logged") {
44875
- return this.fail(
44968
+ return this.failJudge(
44876
44969
  `judge returned no verdict without an audit-tier marker (status: ${result.status || "absent"})`,
44970
+ void 0,
44877
44971
  result.toolCallId
44878
44972
  );
44879
44973
  }
@@ -44925,16 +45019,38 @@ var Atbash = class _Atbash {
44925
45019
  toolCallId: result.toolCallId
44926
45020
  };
44927
45021
  }
44928
- return this.fail(
45022
+ return this.failJudge(
44929
45023
  "unrecognized action_type from judge",
45024
+ void 0,
44930
45025
  result.toolCallId
44931
45026
  );
44932
45027
  } catch (err) {
44933
- const message = errorMessage(err);
44934
- this.logger.warn?.("[atbash] judge API failed", { reason: message });
44935
- return this.fail(message);
45028
+ return this.failJudge(errorMessage(err), err);
44936
45029
  }
44937
45030
  }
45031
+ /**
45032
+ * One exit for every judge failure.
45033
+ *
45034
+ * Status and reason go in the *message*, not only in the meta object: hosts
45035
+ * print the message and drop the meta, which is why this read as a bare
45036
+ * "judge API failed" while the judge was answering with a precise reason.
45037
+ * The response body follows only under `debug`, since it can echo the action.
45038
+ */
45039
+ failJudge(reason, cause, toolCallId) {
45040
+ const api2 = cause instanceof AtbashAPIError ? cause : null;
45041
+ const status = api2 ? ` status=${api2.status || "no-response"}` : "";
45042
+ const body = this.debug && api2?.body ? ` body=${truncate(api2.body, 500)}` : "";
45043
+ this.logger.warn?.(
45044
+ `[atbash] judge API failed \u2014${status} reason=${truncate(reason, 300)}${body}`,
45045
+ {
45046
+ reason,
45047
+ ...api2 ? { status: api2.status, body: api2.body } : {},
45048
+ endpoint: this.endpoint,
45049
+ ...toolCallId ? { toolCallId } : {}
45050
+ }
45051
+ );
45052
+ return this.fail(reason, toolCallId);
45053
+ }
44938
45054
  fail(reason, toolCallId) {
44939
45055
  return { allow: !this.failClosed, verdict: "ERROR", reason, toolCallId };
44940
45056
  }
@@ -45275,8 +45391,27 @@ var Atbash = class _Atbash {
45275
45391
  this.endpoint
45276
45392
  );
45277
45393
  }
45278
- /** Wrap a *transport* failure (fetch threw, no response) as an AtbashAPIError. */
45394
+ /**
45395
+ * Wrap a transport failure (fetch threw, no response) as an AtbashAPIError.
45396
+ *
45397
+ * `HttpTransportError.kind` names the cause; the message is already
45398
+ * human-readable. `debug` echoes the original exception so operators can
45399
+ * cross-reference with node / undici logs when a class doesn't match.
45400
+ */
45279
45401
  transportError(err) {
45402
+ if (err instanceof HttpTransportError) {
45403
+ if (this.debug) {
45404
+ this.logger.warn?.(
45405
+ `[atbash] transport failed \u2014 kind=${err.kind}`,
45406
+ {
45407
+ kind: err.kind,
45408
+ cause: err.cause instanceof Error ? err.cause.message : String(err.cause ?? ""),
45409
+ endpoint: this.endpoint
45410
+ }
45411
+ );
45412
+ }
45413
+ return new AtbashAPIError(0, err.message, "", this.endpoint);
45414
+ }
45280
45415
  return new AtbashAPIError(0, errorMessage(err), "", this.endpoint);
45281
45416
  }
45282
45417
  async json(resp) {
@@ -45422,9 +45557,32 @@ function stringifyArgs(args) {
45422
45557
  }
45423
45558
  }
45424
45559
  var MAX_ACTION_LEN = 4e3;
45425
- function truncate(text) {
45426
- if (text.length <= MAX_ACTION_LEN) return text;
45427
- return text.slice(0, MAX_ACTION_LEN) + "\u2026";
45560
+ function truncate(text, limit = MAX_ACTION_LEN) {
45561
+ if (text.length <= limit) return text;
45562
+ return text.slice(0, limit) + "\u2026";
45563
+ }
45564
+
45565
+ // src-ts/key-path.ts
45566
+ init_define_ATBASH_CHROMIA_NODE_URLS();
45567
+ init_define_ATBASH_PRIVATE_NODE_URLS();
45568
+ import { homedir } from "os";
45569
+ import { join as join2 } from "path";
45570
+ var KEY_DIR_REL = ".config/atbash";
45571
+ var KEY_FILENAMES = ["guard-client-key", "atbash-client-key"];
45572
+ function home() {
45573
+ return process.env.HOME || homedir() || "";
45574
+ }
45575
+ function expandHome(p) {
45576
+ if (!p.startsWith("~/")) return p;
45577
+ return join2(home(), p.slice(2));
45578
+ }
45579
+ function keyPathCandidates() {
45580
+ return KEY_FILENAMES.map((name2) => join2(home(), KEY_DIR_REL, name2));
45581
+ }
45582
+ function chooseKeyPath(input, exists) {
45583
+ if (input) return expandHome(input);
45584
+ const candidates = keyPathCandidates();
45585
+ return candidates.find(exists) ?? candidates[0];
45428
45586
  }
45429
45587
 
45430
45588
  // src-ts/redact.ts
@@ -45471,6 +45629,19 @@ function verifyJudgeResponseSignature(bodyBytes, signatureHex, pubKeyHex) {
45471
45629
  };
45472
45630
  }
45473
45631
 
45632
+ // src-ts/memory/boot-sync-message.ts
45633
+ init_define_ATBASH_CHROMIA_NODE_URLS();
45634
+ init_define_ATBASH_PRIVATE_NODE_URLS();
45635
+ var BOOT_SYNC_HINT = "check the chain endpoint and orgName if the cause above does not explain it";
45636
+ function bootSyncFailureLine(cause) {
45637
+ const reason = cause instanceof Error ? cause.message : String(cause);
45638
+ const trimmed = reason.trim();
45639
+ return trimmed ? `[atbash] boot memory sync failed: ${trimmed}` : (
45640
+ // No cause to show: fall back to the advice rather than a bare colon.
45641
+ `[atbash] boot memory sync failed \u2014 ${BOOT_SYNC_HINT}`
45642
+ );
45643
+ }
45644
+
45474
45645
  // src-ts/memory/index.ts
45475
45646
  init_define_ATBASH_CHROMIA_NODE_URLS();
45476
45647
  init_define_ATBASH_PRIVATE_NODE_URLS();
@@ -45876,6 +46047,7 @@ function diffMemorySnapshots2(before, after) {
45876
46047
  export {
45877
46048
  Atbash,
45878
46049
  AtbashAPIError,
46050
+ BOOT_SYNC_HINT,
45879
46051
  DEFAULT_BLOCKCHAIN_RID,
45880
46052
  DEFAULT_CHROMIA_NODE_URLS,
45881
46053
  DEFAULT_ENDPOINT,
@@ -45883,11 +46055,16 @@ export {
45883
46055
  DEFAULT_MEMORY_READ_TOOL_NAMES,
45884
46056
  DEFAULT_MEMORY_WRITE_TOOL_NAMES,
45885
46057
  EciesDomain,
46058
+ HttpClient,
46059
+ HttpTransportError,
46060
+ KEY_FILENAMES,
45886
46061
  MemoryGuardManager,
45887
46062
  MemoryIntegrityError,
45888
46063
  PointerStore,
45889
46064
  SignatureVerificationError,
46065
+ bootSyncFailureLine,
45890
46066
  buildAllowedJudgeHosts,
46067
+ chooseKeyPath,
45891
46068
  claimHashHex,
45892
46069
  classifyMemoryRead,
45893
46070
  classifyMemoryWrite,
@@ -45922,6 +46099,7 @@ export {
45922
46099
  isEnvelope,
45923
46100
  isValidPrivateKey2 as isValidPrivateKey,
45924
46101
  keyFingerprintOf,
46102
+ keyPathCandidates,
45925
46103
  loadAgent2 as loadAgent,
45926
46104
  loadAgentFromFile,
45927
46105
  loadUserConfig,