@joshuaswarren/openclaw-engram 9.2.5 → 9.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -8240,6 +8240,174 @@ function validateRequest(schemaName, body) {
8240
8240
  return { success: false, error: formatZodError(result.error) };
8241
8241
  }
8242
8242
 
8243
+ // src/adapters/claude-code.ts
8244
+ var ClaudeCodeAdapter = class {
8245
+ id = "claude-code";
8246
+ matches(context) {
8247
+ const clientName = context.clientInfo?.name?.toLowerCase() ?? "";
8248
+ if (clientName.includes("claude")) return true;
8249
+ const sessionHeader = headerValue(context.headers, "x-claude-session-id");
8250
+ if (sessionHeader) return true;
8251
+ return false;
8252
+ }
8253
+ resolveIdentity(context) {
8254
+ const sessionId = headerValue(context.headers, "x-claude-session-id");
8255
+ const projectPath = headerValue(context.headers, "x-claude-project-path");
8256
+ const namespace = projectPath ? slugify(projectPath) : "claude-code";
8257
+ const principal = headerValue(context.headers, "x-engram-principal") || context.clientInfo?.name || "claude-code";
8258
+ return {
8259
+ namespace,
8260
+ principal,
8261
+ sessionKey: sessionId ?? context.sessionKey,
8262
+ adapterId: this.id
8263
+ };
8264
+ }
8265
+ };
8266
+ function headerValue(headers, key) {
8267
+ const raw = headers[key];
8268
+ const value = Array.isArray(raw) ? raw[0] : raw;
8269
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
8270
+ }
8271
+ function slugify(s) {
8272
+ let slug = s.toLowerCase().replace(/[^a-z0-9]+/g, "-");
8273
+ let start = 0;
8274
+ while (start < slug.length && slug[start] === "-") start++;
8275
+ let end = slug.length;
8276
+ while (end > start && slug[end - 1] === "-") end--;
8277
+ return slug.slice(start, end).slice(0, 80) || "claude-code";
8278
+ }
8279
+
8280
+ // src/adapters/codex.ts
8281
+ var CodexAdapter = class {
8282
+ id = "codex";
8283
+ matches(context) {
8284
+ const clientName = context.clientInfo?.name?.toLowerCase() ?? "";
8285
+ if (clientName.includes("codex")) return true;
8286
+ const agentHeader = headerValue2(context.headers, "x-codex-agent-name");
8287
+ if (agentHeader) return true;
8288
+ return false;
8289
+ }
8290
+ resolveIdentity(context) {
8291
+ const agentName = headerValue2(context.headers, "x-codex-agent-name");
8292
+ const projectDir = headerValue2(context.headers, "x-codex-project-dir");
8293
+ const namespace = projectDir ? slugify2(projectDir) : "codex";
8294
+ const principal = headerValue2(context.headers, "x-engram-principal") || agentName || context.clientInfo?.name || "codex";
8295
+ return {
8296
+ namespace,
8297
+ principal,
8298
+ sessionKey: context.sessionKey,
8299
+ adapterId: this.id
8300
+ };
8301
+ }
8302
+ };
8303
+ function headerValue2(headers, key) {
8304
+ const raw = headers[key];
8305
+ const value = Array.isArray(raw) ? raw[0] : raw;
8306
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
8307
+ }
8308
+ function slugify2(s) {
8309
+ let slug = s.toLowerCase().replace(/[^a-z0-9]+/g, "-");
8310
+ let start = 0;
8311
+ while (start < slug.length && slug[start] === "-") start++;
8312
+ let end = slug.length;
8313
+ while (end > start && slug[end - 1] === "-") end--;
8314
+ return slug.slice(start, end).slice(0, 80) || "codex";
8315
+ }
8316
+
8317
+ // src/adapters/replit.ts
8318
+ var ReplitAdapter = class {
8319
+ id = "replit";
8320
+ matches(context) {
8321
+ if (headerValue3(context.headers, "x-replit-project-id")) return true;
8322
+ if (headerValue3(context.headers, "x-replit-user-id")) return true;
8323
+ return false;
8324
+ }
8325
+ resolveIdentity(context) {
8326
+ const projectId = headerValue3(context.headers, "x-replit-project-id");
8327
+ const userId = headerValue3(context.headers, "x-replit-user-id");
8328
+ const namespace = projectId ? `replit-${sanitizeId(projectId)}` : "replit";
8329
+ const principal = headerValue3(context.headers, "x-engram-principal") || (userId ? `replit-user-${sanitizeId(userId)}` : "replit-agent");
8330
+ return {
8331
+ namespace,
8332
+ principal,
8333
+ sessionKey: context.sessionKey,
8334
+ adapterId: this.id
8335
+ };
8336
+ }
8337
+ };
8338
+ function headerValue3(headers, key) {
8339
+ const raw = headers[key];
8340
+ const value = Array.isArray(raw) ? raw[0] : raw;
8341
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
8342
+ }
8343
+ function sanitizeId(s) {
8344
+ return s.replace(/[^a-zA-Z0-9_-]/g, "").slice(0, 64);
8345
+ }
8346
+
8347
+ // src/adapters/hermes.ts
8348
+ var HermesAdapter = class {
8349
+ id = "hermes";
8350
+ matches(context) {
8351
+ if (headerValue4(context.headers, "x-hermes-session-id")) return true;
8352
+ if (headerValue4(context.headers, "x-hermes-profile")) return true;
8353
+ return false;
8354
+ }
8355
+ resolveIdentity(context) {
8356
+ const sessionId = headerValue4(context.headers, "x-hermes-session-id");
8357
+ const profile = headerValue4(context.headers, "x-hermes-profile");
8358
+ const namespace = profile ? slugify3(profile) : "hermes";
8359
+ const principal = headerValue4(context.headers, "x-engram-principal") || profile || "hermes-agent";
8360
+ return {
8361
+ namespace,
8362
+ principal,
8363
+ sessionKey: sessionId ?? context.sessionKey,
8364
+ adapterId: this.id
8365
+ };
8366
+ }
8367
+ };
8368
+ function headerValue4(headers, key) {
8369
+ const raw = headers[key];
8370
+ const value = Array.isArray(raw) ? raw[0] : raw;
8371
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
8372
+ }
8373
+ function slugify3(s) {
8374
+ let slug = s.toLowerCase().replace(/[^a-z0-9]+/g, "-");
8375
+ let start = 0;
8376
+ while (start < slug.length && slug[start] === "-") start++;
8377
+ let end = slug.length;
8378
+ while (end > start && slug[end - 1] === "-") end--;
8379
+ return slug.slice(start, end).slice(0, 80) || "hermes";
8380
+ }
8381
+
8382
+ // src/adapters/registry.ts
8383
+ var AdapterRegistry = class {
8384
+ adapters;
8385
+ constructor(adapters) {
8386
+ this.adapters = adapters ?? [
8387
+ new HermesAdapter(),
8388
+ new ReplitAdapter(),
8389
+ new CodexAdapter(),
8390
+ new ClaudeCodeAdapter()
8391
+ ];
8392
+ }
8393
+ /**
8394
+ * Try each adapter in order. Return the first match, or null if
8395
+ * no adapter recognizes the request context.
8396
+ */
8397
+ resolve(context) {
8398
+ for (const adapter of this.adapters) {
8399
+ if (adapter.matches(context)) {
8400
+ return adapter.resolveIdentity(context);
8401
+ }
8402
+ }
8403
+ return null;
8404
+ }
8405
+ /** List registered adapter IDs */
8406
+ list() {
8407
+ return this.adapters.map((a) => a.id);
8408
+ }
8409
+ };
8410
+
8243
8411
  // src/access-http.ts
8244
8412
  function resolveDefaultAdminConsolePublicDir() {
8245
8413
  const candidates = [
@@ -8302,6 +8470,7 @@ var EngramAccessHttpServer = class {
8302
8470
  adminConsoleEnabled;
8303
8471
  adminConsolePublicDir;
8304
8472
  trustPrincipalHeader;
8473
+ adapterRegistry;
8305
8474
  writeRequestTimestamps = [];
8306
8475
  mcpServer;
8307
8476
  server = null;
@@ -8316,6 +8485,7 @@ var EngramAccessHttpServer = class {
8316
8485
  this.adminConsoleEnabled = options.adminConsoleEnabled !== false;
8317
8486
  this.adminConsolePublicDir = options.adminConsolePublicDir ?? defaultAdminConsolePublicDir;
8318
8487
  this.trustPrincipalHeader = options.trustPrincipalHeader === true;
8488
+ this.adapterRegistry = options.enableAdapters !== false ? options.adapterRegistry ?? new AdapterRegistry() : null;
8319
8489
  this.mcpServer = new EngramMcpServer(this.service, { principal: options.principal });
8320
8490
  }
8321
8491
  async start() {
@@ -8386,10 +8556,20 @@ var EngramAccessHttpServer = class {
8386
8556
  maxBodyBytes: this.maxBodyBytes
8387
8557
  };
8388
8558
  }
8559
+ /**
8560
+ * Resolve the adapter identity for the incoming request.
8561
+ * Returns null if no adapter matches or adapters are disabled.
8562
+ */
8563
+ resolveAdapterIdentity(req) {
8564
+ if (!this.adapterRegistry) return null;
8565
+ return this.adapterRegistry.resolve({
8566
+ headers: req.headers
8567
+ });
8568
+ }
8389
8569
  resolveRequestPrincipal(req) {
8390
8570
  if (this.trustPrincipalHeader) {
8391
- const headerValue = req.headers["x-engram-principal"];
8392
- const raw = Array.isArray(headerValue) ? headerValue[0] : headerValue;
8571
+ const headerValue5 = req.headers["x-engram-principal"];
8572
+ const raw = Array.isArray(headerValue5) ? headerValue5[0] : headerValue5;
8393
8573
  if (typeof raw === "string") {
8394
8574
  const trimmed = raw.trim();
8395
8575
  if (trimmed.length > 0) {
@@ -8397,6 +8577,10 @@ var EngramAccessHttpServer = class {
8397
8577
  }
8398
8578
  }
8399
8579
  }
8580
+ const adapterIdentity = this.resolveAdapterIdentity(req);
8581
+ if (adapterIdentity) {
8582
+ return adapterIdentity.principal;
8583
+ }
8400
8584
  return this.authenticatedPrincipal;
8401
8585
  }
8402
8586
  async handle(req, res, correlationId) {
@@ -8423,6 +8607,15 @@ var EngramAccessHttpServer = class {
8423
8607
  this.respondJson(res, 200, await this.service.health());
8424
8608
  return;
8425
8609
  }
8610
+ if (req.method === "GET" && pathname === "/engram/v1/adapters") {
8611
+ const identity = this.resolveAdapterIdentity(req);
8612
+ this.respondJson(res, 200, {
8613
+ adaptersEnabled: this.adapterRegistry !== null,
8614
+ registered: this.adapterRegistry?.list() ?? [],
8615
+ resolved: identity
8616
+ });
8617
+ return;
8618
+ }
8426
8619
  if (req.method === "POST" && pathname === "/engram/v1/recall") {
8427
8620
  const body = await this.readValidatedBody(req, "recall");
8428
8621
  const response = await this.service.recall({