@prismer/sdk 1.7.1 → 1.7.4

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
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ AIPIdentity: () => import_aip_sdk.AIPIdentity,
33
34
  AccountClient: () => AccountClient,
34
35
  AttachmentQueue: () => AttachmentQueue,
35
36
  BindingsClient: () => BindingsClient,
@@ -39,11 +40,16 @@ __export(index_exports, {
39
40
  DirectClient: () => DirectClient,
40
41
  E2EEncryption: () => E2EEncryption,
41
42
  ENVIRONMENTS: () => ENVIRONMENTS,
43
+ EvolutionCache: () => EvolutionCache,
44
+ EvolutionClient: () => EvolutionClient,
45
+ EvolutionRuntime: () => EvolutionRuntime,
42
46
  FilesClient: () => FilesClient,
43
47
  GroupsClient: () => GroupsClient,
44
48
  IMClient: () => IMClient,
45
49
  IMRealtimeClient: () => IMRealtimeClient,
50
+ IdentityClient: () => IdentityClient,
46
51
  IndexedDBStorage: () => IndexedDBStorage,
52
+ MemoryClient: () => MemoryClient,
47
53
  MemoryStorage: () => MemoryStorage,
48
54
  MessagesClient: () => MessagesClient,
49
55
  OfflineManager: () => OfflineManager,
@@ -51,10 +57,23 @@ __export(index_exports, {
51
57
  RealtimeSSEClient: () => RealtimeSSEClient,
52
58
  RealtimeWSClient: () => RealtimeWSClient,
53
59
  SQLiteStorage: () => SQLiteStorage,
60
+ SecurityClient: () => SecurityClient,
54
61
  TabCoordinator: () => TabCoordinator,
62
+ TasksClient: () => TasksClient,
55
63
  WorkspaceClient: () => WorkspaceClient,
56
64
  createClient: () => createClient,
57
- default: () => index_default
65
+ createEnrichedExtractor: () => createEnrichedExtractor,
66
+ decryptContext: () => decryptContext,
67
+ decryptFile: () => decryptFile,
68
+ decryptMessages: () => decryptMessages,
69
+ decryptOnReceive: () => decryptOnReceive,
70
+ default: () => index_default,
71
+ encryptContext: () => encryptContext,
72
+ encryptFile: () => encryptFile,
73
+ encryptForSend: () => encryptForSend,
74
+ extractSignals: () => extractSignals,
75
+ guessMimeType: () => guessMimeType,
76
+ safeSlug: () => safeSlug
58
77
  });
59
78
  module.exports = __toCommonJS(index_exports);
60
79
 
@@ -252,10 +271,11 @@ var RealtimeWSClient = class extends TypedEmitter {
252
271
  joinConversation(conversationId) {
253
272
  this.sendRaw({ type: "conversation.join", payload: { conversationId } });
254
273
  }
255
- sendMessage(conversationId, content, type = "text") {
274
+ sendMessage(conversationId, content, options) {
275
+ const opts = typeof options === "string" ? { type: options } : options;
256
276
  this.sendRaw({
257
277
  type: "message.send",
258
- payload: { conversationId, content, type },
278
+ payload: { conversationId, content, type: opts?.type ?? "text", ...opts?.metadata ? { metadata: opts.metadata } : {}, ...opts?.parentId ? { parentId: opts.parentId } : {} },
259
279
  requestId: `msg-${++this.pingCounter}`
260
280
  });
261
281
  }
@@ -1262,6 +1282,12 @@ var ENVIRONMENTS = {
1262
1282
  production: "https://prismer.cloud"
1263
1283
  };
1264
1284
 
1285
+ // src/aip.ts
1286
+ var import_aip_sdk = require("@prismer/aip-sdk");
1287
+ var import_aip_sdk2 = require("@prismer/aip-sdk");
1288
+ var import_aip_sdk3 = require("@prismer/aip-sdk");
1289
+ var import_aip_sdk4 = require("@prismer/aip-sdk");
1290
+
1265
1291
  // src/storage.ts
1266
1292
  var MemoryStorage = class {
1267
1293
  constructor() {
@@ -2146,20 +2172,27 @@ var PBKDF2_ITERATIONS = 1e5;
2146
2172
  var SALT_LENGTH = 16;
2147
2173
  var IV_LENGTH = 12;
2148
2174
  var KEY_LENGTH = 256;
2149
- var E2EEncryption = class {
2175
+ var _E2EEncryption = class _E2EEncryption {
2150
2176
  constructor() {
2151
2177
  this.masterKey = null;
2152
2178
  this.keyPair = null;
2153
2179
  this.sessionKeys = /* @__PURE__ */ new Map();
2154
2180
  // conversationId → AES key
2155
2181
  this.salt = null;
2182
+ // ─── Pipeline Functions ──────────────────────────────────
2183
+ this.messageCount = 0;
2184
+ this.lastRotation = Date.now();
2156
2185
  }
2157
2186
  /**
2158
2187
  * Initialize encryption with user passphrase.
2159
2188
  * Derives a master key via PBKDF2 and generates an ECDH key pair.
2189
+ *
2190
+ * @param passphrase - User passphrase for master key derivation
2191
+ * @param salt - Optional Base64-encoded salt. If omitted, a random 16-byte salt is generated.
2192
+ * Store the salt (via exportSalt()) so you can re-derive the same master key later.
2160
2193
  */
2161
- async init(passphrase) {
2162
- this.salt = getRandomValues(new Uint8Array(SALT_LENGTH));
2194
+ async init(passphrase, salt) {
2195
+ this.salt = salt ? new Uint8Array(base64ToArrayBuffer(salt)) : getRandomValues(new Uint8Array(SALT_LENGTH));
2163
2196
  const passphraseKey = await subtle().importKey(
2164
2197
  "raw",
2165
2198
  new TextEncoder().encode(passphrase),
@@ -2170,7 +2203,7 @@ var E2EEncryption = class {
2170
2203
  this.masterKey = await subtle().deriveKey(
2171
2204
  {
2172
2205
  name: "PBKDF2",
2173
- salt: this.salt,
2206
+ salt: new Uint8Array(this.salt.buffer, this.salt.byteOffset, this.salt.byteLength).buffer,
2174
2207
  iterations: PBKDF2_ITERATIONS,
2175
2208
  hash: "SHA-256"
2176
2209
  },
@@ -2185,6 +2218,14 @@ var E2EEncryption = class {
2185
2218
  ["deriveKey"]
2186
2219
  );
2187
2220
  }
2221
+ /**
2222
+ * Export the salt as Base64 string for persistent storage.
2223
+ * You must store this and pass it back to init() to re-derive the same master key.
2224
+ */
2225
+ exportSalt() {
2226
+ if (!this.salt) throw new Error("E2E not initialized. Call init() first.");
2227
+ return arrayBufferToBase64(this.salt.buffer);
2228
+ }
2188
2229
  /**
2189
2230
  * Export public key for sharing with conversation peers.
2190
2231
  */
@@ -2297,8 +2338,93 @@ var E2EEncryption = class {
2297
2338
  this.keyPair = null;
2298
2339
  this.sessionKeys.clear();
2299
2340
  this.salt = null;
2341
+ this.messageCount = 0;
2342
+ }
2343
+ /**
2344
+ * High-level encrypt-for-send pipeline.
2345
+ * Encrypts content, builds metadata, and handles key rotation.
2346
+ *
2347
+ * Returns { encryptedContent, metadata } ready to send.
2348
+ */
2349
+ async encryptForSend(conversationId, content) {
2350
+ if (!this.hasSessionKey(conversationId)) {
2351
+ throw new Error("No session key for this conversation. Call deriveSessionKey() first.");
2352
+ }
2353
+ const needsRotation = this.shouldRotateKey();
2354
+ const encryptedContent = await this.encrypt(conversationId, content);
2355
+ this.messageCount++;
2356
+ return {
2357
+ encryptedContent,
2358
+ metadata: {
2359
+ encrypted: true,
2360
+ encryptionVersion: 1,
2361
+ ...needsRotation && { keyRotationRequested: true }
2362
+ }
2363
+ };
2364
+ }
2365
+ /**
2366
+ * High-level decrypt-on-receive pipeline.
2367
+ * Decrypts content and validates metadata.
2368
+ */
2369
+ async decryptOnReceive(conversationId, encryptedContent, metadata) {
2370
+ if (!this.hasSessionKey(conversationId)) {
2371
+ throw new Error("No session key for this conversation. Call deriveSessionKey() first.");
2372
+ }
2373
+ return this.decrypt(conversationId, encryptedContent);
2374
+ }
2375
+ /**
2376
+ * High-level file encryption pipeline.
2377
+ */
2378
+ async encryptFile(conversationId, fileData) {
2379
+ const base64Data = arrayBufferToBase64(fileData);
2380
+ const encryptedData = await this.encrypt(conversationId, base64Data);
2381
+ return {
2382
+ encryptedData,
2383
+ metadata: {
2384
+ encrypted: true,
2385
+ encryptionVersion: 1,
2386
+ fileEncrypted: true
2387
+ }
2388
+ };
2389
+ }
2390
+ /**
2391
+ * High-level file decryption pipeline.
2392
+ */
2393
+ async decryptFile(conversationId, encryptedData) {
2394
+ const base64Data = await this.decrypt(conversationId, encryptedData);
2395
+ return base64ToArrayBuffer(base64Data);
2396
+ }
2397
+ /**
2398
+ * Check if key rotation is needed (1000 messages or 24 hours).
2399
+ */
2400
+ shouldRotateKey() {
2401
+ if (this.messageCount >= _E2EEncryption.KEY_ROTATION_THRESHOLD) {
2402
+ return true;
2403
+ }
2404
+ if (Date.now() - this.lastRotation >= _E2EEncryption.KEY_ROTATION_INTERVAL_MS) {
2405
+ return true;
2406
+ }
2407
+ return false;
2408
+ }
2409
+ /**
2410
+ * Perform key rotation: generate new ECDH keypair and reset counters.
2411
+ * The caller is responsible for re-exchanging keys with peers.
2412
+ */
2413
+ async rotateKeys() {
2414
+ this.keyPair = await subtle().generateKey(
2415
+ { name: "ECDH", namedCurve: "P-256" },
2416
+ false,
2417
+ ["deriveKey"]
2418
+ );
2419
+ this.messageCount = 0;
2420
+ this.lastRotation = Date.now();
2421
+ this.sessionKeys.clear();
2422
+ return this.exportPublicKey();
2300
2423
  }
2301
2424
  };
2425
+ _E2EEncryption.KEY_ROTATION_THRESHOLD = 1e3;
2426
+ _E2EEncryption.KEY_ROTATION_INTERVAL_MS = 24 * 60 * 60 * 1e3;
2427
+ var E2EEncryption = _E2EEncryption;
2302
2428
  function arrayBufferToBase64(buffer) {
2303
2429
  if (typeof btoa !== "undefined") {
2304
2430
  const bytes = new Uint8Array(buffer);
@@ -2323,6 +2449,548 @@ function base64ToArrayBuffer(base64) {
2323
2449
  return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
2324
2450
  }
2325
2451
 
2452
+ // src/encryption-pipeline.ts
2453
+ async function encryptForSend(e2e, conversationId, content, metadata) {
2454
+ if (!e2e.hasSessionKey(conversationId)) {
2455
+ return { content, metadata: metadata ?? {} };
2456
+ }
2457
+ const ciphertext = await e2e.encrypt(conversationId, content);
2458
+ return {
2459
+ content: ciphertext,
2460
+ metadata: { ...metadata, encrypted: true, encKeyId: `conv-${conversationId}` }
2461
+ };
2462
+ }
2463
+ async function decryptOnReceive(e2e, conversationId, content, metadata) {
2464
+ if (!metadata?.encrypted) {
2465
+ return { content, decrypted: false };
2466
+ }
2467
+ if (!e2e.hasSessionKey(conversationId)) {
2468
+ return { content, decrypted: false, error: "no_session_key" };
2469
+ }
2470
+ try {
2471
+ const plain = await e2e.decrypt(conversationId, content);
2472
+ return { content: plain, decrypted: true };
2473
+ } catch (err) {
2474
+ const message = err instanceof Error ? err.message : String(err);
2475
+ return { content, decrypted: false, error: message };
2476
+ }
2477
+ }
2478
+ async function encryptFile(e2e, conversationId, data) {
2479
+ if (!e2e.hasSessionKey(conversationId)) return null;
2480
+ const b64 = typeof Buffer !== "undefined" ? Buffer.from(data).toString("base64") : uint8ArrayToBase64(data);
2481
+ const ciphertext = await e2e.encrypt(conversationId, b64);
2482
+ return {
2483
+ data: ciphertext,
2484
+ metadata: { encrypted: true, encKeyId: `conv-${conversationId}` }
2485
+ };
2486
+ }
2487
+ async function decryptFile(e2e, conversationId, ciphertext) {
2488
+ if (!e2e.hasSessionKey(conversationId)) return null;
2489
+ try {
2490
+ const b64 = await e2e.decrypt(conversationId, ciphertext);
2491
+ if (typeof Buffer !== "undefined") {
2492
+ return new Uint8Array(Buffer.from(b64, "base64"));
2493
+ }
2494
+ return base64ToUint8Array(b64);
2495
+ } catch {
2496
+ return null;
2497
+ }
2498
+ }
2499
+ async function encryptContext(e2e, content, contextId = "context-cache") {
2500
+ if (!e2e.hasSessionKey(contextId)) return null;
2501
+ const ciphertext = await e2e.encrypt(contextId, content);
2502
+ return { content: ciphertext, encrypted: true };
2503
+ }
2504
+ async function decryptContext(e2e, ciphertext, contextId = "context-cache") {
2505
+ if (!e2e.hasSessionKey(contextId)) return null;
2506
+ try {
2507
+ return await e2e.decrypt(contextId, ciphertext);
2508
+ } catch {
2509
+ return null;
2510
+ }
2511
+ }
2512
+ async function decryptMessages(e2e, messages, conversationId) {
2513
+ let decryptedCount = 0;
2514
+ const errors = [];
2515
+ for (let i = 0; i < messages.length; i++) {
2516
+ const msg = messages[i];
2517
+ const convId = conversationId ?? msg.conversationId;
2518
+ if (!convId) continue;
2519
+ const result = await decryptOnReceive(e2e, convId, msg.content, msg.metadata);
2520
+ if (result.decrypted) {
2521
+ msg.content = result.content;
2522
+ if (msg.metadata) {
2523
+ msg.metadata._decrypted = true;
2524
+ }
2525
+ decryptedCount++;
2526
+ } else if (result.error) {
2527
+ errors.push({ index: i, error: result.error });
2528
+ }
2529
+ }
2530
+ return { decryptedCount, errors };
2531
+ }
2532
+ function uint8ArrayToBase64(bytes) {
2533
+ let binary = "";
2534
+ for (let i = 0; i < bytes.length; i++) {
2535
+ binary += String.fromCharCode(bytes[i]);
2536
+ }
2537
+ return btoa(binary);
2538
+ }
2539
+ function base64ToUint8Array(b64) {
2540
+ const binary = atob(b64);
2541
+ const bytes = new Uint8Array(binary.length);
2542
+ for (let i = 0; i < binary.length; i++) {
2543
+ bytes[i] = binary.charCodeAt(i);
2544
+ }
2545
+ return bytes;
2546
+ }
2547
+
2548
+ // src/evolution-cache.ts
2549
+ var EvolutionCache = class {
2550
+ constructor() {
2551
+ this._genes = /* @__PURE__ */ new Map();
2552
+ this._edges = /* @__PURE__ */ new Map();
2553
+ // key = signal_key
2554
+ this._globalPrior = /* @__PURE__ */ new Map();
2555
+ this._cursor = 0;
2556
+ }
2557
+ get cursor() {
2558
+ return this._cursor;
2559
+ }
2560
+ get geneCount() {
2561
+ return this._genes.size;
2562
+ }
2563
+ /** Load from a full snapshot */
2564
+ loadSnapshot(snapshot) {
2565
+ this._genes.clear();
2566
+ this._edges.clear();
2567
+ this._globalPrior.clear();
2568
+ for (const gene of snapshot.genes) {
2569
+ this._genes.set(gene.id, gene);
2570
+ }
2571
+ for (const edge of snapshot.edges) {
2572
+ const list = this._edges.get(edge.signal_key) ?? [];
2573
+ list.push(edge);
2574
+ this._edges.set(edge.signal_key, list);
2575
+ }
2576
+ for (const [key, val] of Object.entries(snapshot.globalPrior)) {
2577
+ this._globalPrior.set(key, val);
2578
+ }
2579
+ this._cursor = snapshot.cursor;
2580
+ }
2581
+ /** Apply incremental delta (alias: loadDelta) */
2582
+ applyDelta(delta) {
2583
+ const pulled = delta.pulled;
2584
+ for (const gene of pulled.genes) {
2585
+ this._genes.set(gene.id, gene);
2586
+ }
2587
+ for (const id of pulled.quarantines) {
2588
+ this._genes.delete(id);
2589
+ }
2590
+ for (const edge of pulled.edges) {
2591
+ const list = this._edges.get(edge.signal_key) ?? [];
2592
+ const idx = list.findIndex((e) => e.gene_id === edge.gene_id);
2593
+ if (idx >= 0) list[idx] = edge;
2594
+ else list.push(edge);
2595
+ this._edges.set(edge.signal_key, list);
2596
+ }
2597
+ for (const [key, val] of Object.entries(pulled.globalPrior)) {
2598
+ this._globalPrior.set(key, val);
2599
+ }
2600
+ this._cursor = pulled.cursor;
2601
+ }
2602
+ /** Apply incremental delta (alias for applyDelta) */
2603
+ loadDelta(delta) {
2604
+ this.applyDelta(delta);
2605
+ }
2606
+ /** Select best gene locally using Thompson Sampling — pure CPU, <1ms */
2607
+ selectGene(signals) {
2608
+ if (this._genes.size === 0) {
2609
+ return { action: "none", confidence: 0, reason: "no genes in cache", fromCache: true };
2610
+ }
2611
+ const signalKeys = signals.map((s) => s.type);
2612
+ const candidates = [];
2613
+ for (const gene of this._genes.values()) {
2614
+ if (gene.visibility === "quarantined") continue;
2615
+ const geneSignalTypes = (gene.signals_match || []).map(
2616
+ (s) => typeof s === "string" ? s : s.type
2617
+ );
2618
+ if (geneSignalTypes.length === 0) continue;
2619
+ const matchCount = signalKeys.filter((k) => geneSignalTypes.includes(k)).length;
2620
+ const coverageScore = matchCount / geneSignalTypes.length;
2621
+ if (coverageScore === 0) continue;
2622
+ let alpha = gene.success_count + 1;
2623
+ let beta = gene.failure_count + 1;
2624
+ for (const key of signalKeys) {
2625
+ const prior = this._globalPrior.get(key);
2626
+ if (prior) {
2627
+ alpha += 0.3 * prior.alpha;
2628
+ beta += 0.3 * prior.beta;
2629
+ }
2630
+ }
2631
+ const sampledScore = alpha / (alpha + beta);
2632
+ const totalObs = gene.success_count + gene.failure_count;
2633
+ if (totalObs >= 10 && gene.success_count / totalObs < 0.18) continue;
2634
+ const rankScore = coverageScore * 0.4 + sampledScore * 0.6;
2635
+ candidates.push({ gene, rankScore, coverageScore, sampledScore });
2636
+ }
2637
+ if (candidates.length === 0) {
2638
+ return {
2639
+ action: "create_suggested",
2640
+ confidence: 0,
2641
+ reason: "no matching genes for signals",
2642
+ fromCache: true
2643
+ };
2644
+ }
2645
+ candidates.sort((a, b) => b.rankScore - a.rankScore);
2646
+ const best = candidates[0];
2647
+ const alternatives = candidates.slice(1, 4).map((c) => ({
2648
+ gene_id: c.gene.id,
2649
+ confidence: Math.round(c.rankScore * 100) / 100,
2650
+ title: c.gene.title
2651
+ }));
2652
+ return {
2653
+ action: "apply_gene",
2654
+ gene_id: best.gene.id,
2655
+ gene: best.gene,
2656
+ strategy: best.gene.strategy,
2657
+ confidence: Math.round(best.rankScore * 100) / 100,
2658
+ coverageScore: Math.round(best.coverageScore * 100) / 100,
2659
+ alternatives,
2660
+ reason: `local cache selection (${this._genes.size} genes)`,
2661
+ fromCache: true
2662
+ };
2663
+ }
2664
+ };
2665
+
2666
+ // src/signal-enrichment.ts
2667
+ var ERROR_PATTERNS = [
2668
+ { pattern: /timeout|timed?\s*out|deadline\s*exceeded|context\s*deadline/i, type: "timeout" },
2669
+ { pattern: /econnrefused|connection\s*refused/i, type: "connection_refused" },
2670
+ { pattern: /enotfound|dns|getaddrinfo|resolve/i, type: "dns_error" },
2671
+ { pattern: /rate\s*limit|too\s*many\s*requests|429/i, type: "rate_limit" },
2672
+ { pattern: /401|unauthorized|unauthenticated|auth.*fail/i, type: "auth_error" },
2673
+ { pattern: /403|forbidden|access\s*denied|permission/i, type: "permission_error" },
2674
+ { pattern: /404|not\s*found/i, type: "not_found" },
2675
+ { pattern: /5\d{2}|internal\s*server|server\s*error|502|503|504/i, type: "server_error" },
2676
+ { pattern: /type\s*error|typeerror/i, type: "type_error" },
2677
+ { pattern: /syntax\s*error|syntaxerror|unexpected\s*token/i, type: "syntax_error" },
2678
+ { pattern: /reference\s*error|referenceerror|is\s*not\s*defined/i, type: "reference_error" },
2679
+ { pattern: /out\s*of\s*memory|oom|heap|allocation\s*failed/i, type: "oom" },
2680
+ { pattern: /crash|panic|segfault|sigsegv|sigabrt/i, type: "crash" },
2681
+ { pattern: /quota|limit\s*exceeded|insufficient/i, type: "quota_exceeded" },
2682
+ { pattern: /tls|ssl|certificate|cert\s*verify/i, type: "tls_error" },
2683
+ { pattern: /deadlock|lock\s*timeout|lock\s*wait/i, type: "deadlock" }
2684
+ ];
2685
+ function extractSignals(ctx) {
2686
+ const tags = [];
2687
+ if (ctx.error) {
2688
+ let matched = false;
2689
+ for (const { pattern, type } of ERROR_PATTERNS) {
2690
+ if (pattern.test(ctx.error)) {
2691
+ const tag = { type: `error:${type}` };
2692
+ if (ctx.provider) tag.provider = ctx.provider;
2693
+ if (ctx.stage) tag.stage = ctx.stage;
2694
+ if (ctx.severity) tag.severity = ctx.severity;
2695
+ tags.push(tag);
2696
+ matched = true;
2697
+ break;
2698
+ }
2699
+ }
2700
+ if (!matched) {
2701
+ const normalized = ctx.error.slice(0, 50).toLowerCase().replace(/[^a-z0-9_]/g, "_");
2702
+ const tag = { type: `error:${normalized}` };
2703
+ if (ctx.provider) tag.provider = ctx.provider;
2704
+ if (ctx.stage) tag.stage = ctx.stage;
2705
+ tags.push(tag);
2706
+ }
2707
+ }
2708
+ if (ctx.taskStatus === "failed") tags.push({ type: "task.failed" });
2709
+ if (ctx.taskStatus === "completed") tags.push({ type: "task.completed" });
2710
+ if (ctx.taskCapability) {
2711
+ tags.push({ type: `capability:${ctx.taskCapability}` });
2712
+ }
2713
+ if (ctx.tags) {
2714
+ for (const tag of ctx.tags) {
2715
+ tags.push({ type: tag });
2716
+ }
2717
+ }
2718
+ return tags;
2719
+ }
2720
+ function createEnrichedExtractor(config) {
2721
+ if (config.mode === "rules") {
2722
+ return async (ctx) => extractSignals(ctx);
2723
+ }
2724
+ const { llmExtract, timeoutMs = 3e3 } = config;
2725
+ if (!llmExtract) return async (ctx) => extractSignals(ctx);
2726
+ return async (ctx) => {
2727
+ try {
2728
+ const result = await Promise.race([
2729
+ llmExtract(ctx),
2730
+ new Promise(
2731
+ (_, reject) => setTimeout(() => reject(new Error("llm_timeout")), timeoutMs)
2732
+ )
2733
+ ]);
2734
+ return result;
2735
+ } catch {
2736
+ return extractSignals(ctx);
2737
+ }
2738
+ };
2739
+ }
2740
+
2741
+ // src/evolution-runtime.ts
2742
+ var EvolutionRuntime = class {
2743
+ constructor(client, config) {
2744
+ this.client = client;
2745
+ this.outbox = [];
2746
+ this.started = false;
2747
+ // Session tracking
2748
+ this._sessions = [];
2749
+ this._sessionCounter = 0;
2750
+ this.config = {
2751
+ syncIntervalMs: config?.syncIntervalMs ?? 6e4,
2752
+ enrichment: config?.enrichment ?? { mode: "rules" },
2753
+ scope: config?.scope ?? "global",
2754
+ outboxMaxSize: config?.outboxMaxSize ?? 50,
2755
+ outboxFlushMs: config?.outboxFlushMs ?? 5e3
2756
+ };
2757
+ this.scope = this.config.scope;
2758
+ this.cache = new EvolutionCache();
2759
+ this.enricher = config?.enrichment ? createEnrichedExtractor(config.enrichment) : async (ctx) => extractSignals(ctx);
2760
+ }
2761
+ // ─── Lifecycle ──────────────────────────────────────
2762
+ /** Initialize: load snapshot + start sync + start outbox flush */
2763
+ async start() {
2764
+ if (this.started) return;
2765
+ this.started = true;
2766
+ try {
2767
+ const snapshot = await this.client.getSyncSnapshot(0);
2768
+ if (snapshot.data) {
2769
+ this.cache.loadSnapshot(snapshot.data);
2770
+ }
2771
+ } catch {
2772
+ }
2773
+ if (this.config.syncIntervalMs > 0) {
2774
+ this.syncTimer = setInterval(() => this.sync(), this.config.syncIntervalMs);
2775
+ }
2776
+ this.flushTimer = setInterval(() => this.flush(), this.config.outboxFlushMs);
2777
+ }
2778
+ /** Stop: clear timers + flush remaining outbox */
2779
+ async stop() {
2780
+ if (this.syncTimer) clearInterval(this.syncTimer);
2781
+ if (this.flushTimer) clearInterval(this.flushTimer);
2782
+ await this.flush();
2783
+ this.started = false;
2784
+ }
2785
+ // ─── High-Level API ─────────────────────────────────
2786
+ /**
2787
+ * Get a strategy recommendation for an error/context.
2788
+ *
2789
+ * Flow: extract signals → try local cache (<1ms) → fallback to server (~30ms)
2790
+ *
2791
+ * @param error - Error message or Error object
2792
+ * @param context - Optional additional context (provider, stage, etc.)
2793
+ */
2794
+ async suggest(error, context) {
2795
+ const errorStr = error instanceof Error ? error.message : error;
2796
+ const ctx = {
2797
+ error: errorStr,
2798
+ ...context
2799
+ };
2800
+ const signals = await this.enricher(ctx);
2801
+ if (signals.length === 0) {
2802
+ return {
2803
+ action: "none",
2804
+ confidence: 0,
2805
+ signals: [],
2806
+ fromCache: false,
2807
+ reason: "no signals extracted from error"
2808
+ };
2809
+ }
2810
+ const buildSuggestion = (action, geneId, gene, strategy, confidence, fromCache, reason, alternatives) => {
2811
+ this.lastSuggestedGeneId = geneId;
2812
+ this._activeSession = {
2813
+ id: `ses_${++this._sessionCounter}_${Date.now()}`,
2814
+ suggestedAt: Date.now(),
2815
+ suggestedGeneId: geneId,
2816
+ signals,
2817
+ adopted: false,
2818
+ confidence,
2819
+ fromCache
2820
+ };
2821
+ return {
2822
+ action,
2823
+ geneId,
2824
+ gene,
2825
+ strategy,
2826
+ confidence,
2827
+ signals,
2828
+ fromCache,
2829
+ reason,
2830
+ alternatives
2831
+ };
2832
+ };
2833
+ if (this.cache.geneCount > 0) {
2834
+ const local = this.cache.selectGene(signals);
2835
+ if (local.action === "apply_gene" && local.confidence > 0.3) {
2836
+ return buildSuggestion(
2837
+ local.action,
2838
+ local.gene_id,
2839
+ local.gene,
2840
+ local.strategy,
2841
+ local.confidence,
2842
+ true,
2843
+ local.reason,
2844
+ local.alternatives
2845
+ );
2846
+ }
2847
+ }
2848
+ try {
2849
+ const result = await this.client.analyze({
2850
+ signals,
2851
+ scope: this.scope
2852
+ });
2853
+ if (result.data) {
2854
+ return buildSuggestion(
2855
+ result.data.action,
2856
+ result.data.gene_id,
2857
+ result.data.gene,
2858
+ result.data.strategy,
2859
+ result.data.confidence ?? 0,
2860
+ false,
2861
+ result.data.reason,
2862
+ result.data.alternatives
2863
+ );
2864
+ }
2865
+ } catch {
2866
+ const local = this.cache.selectGene(signals);
2867
+ return buildSuggestion(
2868
+ local.action,
2869
+ local.gene_id,
2870
+ local.gene,
2871
+ local.strategy,
2872
+ local.confidence,
2873
+ true,
2874
+ "server unreachable, using cache fallback",
2875
+ local.alternatives
2876
+ );
2877
+ }
2878
+ return {
2879
+ action: "none",
2880
+ confidence: 0,
2881
+ signals,
2882
+ fromCache: false,
2883
+ reason: "no recommendation from server"
2884
+ };
2885
+ }
2886
+ /**
2887
+ * Record an outcome. Fire-and-forget — never blocks, never throws.
2888
+ *
2889
+ * @param error - The error that was encountered
2890
+ * @param outcome - 'success' or 'failed'
2891
+ * @param summary - One-line summary of what happened
2892
+ * @param geneId - Gene that was used (auto-detected from last suggest() if omitted)
2893
+ */
2894
+ learned(error, outcome, summary, geneId, metadata) {
2895
+ const errorStr = error instanceof Error ? error.message : error;
2896
+ const ctx = { error: errorStr };
2897
+ const signals = extractSignals(ctx);
2898
+ const resolvedGeneId = geneId || this.lastSuggestedGeneId;
2899
+ if (!resolvedGeneId) return;
2900
+ if (this._activeSession) {
2901
+ const session = this._activeSession;
2902
+ session.usedGeneId = resolvedGeneId;
2903
+ session.adopted = resolvedGeneId === session.suggestedGeneId;
2904
+ session.completedAt = Date.now();
2905
+ session.outcome = outcome;
2906
+ session.durationMs = session.completedAt - session.suggestedAt;
2907
+ this._sessions.push(session);
2908
+ this._activeSession = void 0;
2909
+ }
2910
+ this.outbox.push({
2911
+ geneId: resolvedGeneId,
2912
+ signals,
2913
+ outcome,
2914
+ summary,
2915
+ metadata,
2916
+ timestamp: Date.now(),
2917
+ sessionId: this._sessions[this._sessions.length - 1]?.id
2918
+ });
2919
+ if (this.outbox.length >= this.config.outboxMaxSize) {
2920
+ this.flush().catch(() => {
2921
+ });
2922
+ }
2923
+ }
2924
+ // ─── Session Metrics ────────────────────────────────
2925
+ /** Get all completed sessions. */
2926
+ get sessions() {
2927
+ return this._sessions;
2928
+ }
2929
+ /** Get aggregate metrics for benchmarking. */
2930
+ getMetrics() {
2931
+ const sessions = this._sessions;
2932
+ const totalSuggestions = sessions.length;
2933
+ const suggestionsWithGene = sessions.filter((s) => s.suggestedGeneId).length;
2934
+ const totalLearned = sessions.filter((s) => s.completedAt).length;
2935
+ const adoptedSessions = sessions.filter((s) => s.adopted && s.completedAt);
2936
+ const adoptedCount = adoptedSessions.length;
2937
+ const nonAdopted = sessions.filter((s) => !s.adopted && s.completedAt);
2938
+ const durations = sessions.filter((s) => s.durationMs != null).map((s) => s.durationMs);
2939
+ const avgDurationMs = durations.length > 0 ? Math.round(durations.reduce((a, b) => a + b, 0) / durations.length) : 0;
2940
+ const adoptedSuccess = adoptedSessions.filter((s) => s.outcome === "success").length;
2941
+ const nonAdoptedSuccess = nonAdopted.filter((s) => s.outcome === "success").length;
2942
+ const cacheHits = sessions.filter((s) => s.fromCache).length;
2943
+ return {
2944
+ totalSuggestions,
2945
+ suggestionsWithGene,
2946
+ totalLearned,
2947
+ adoptedCount,
2948
+ geneUtilizationRate: suggestionsWithGene > 0 ? Math.round(adoptedCount / suggestionsWithGene * 100) / 100 : 0,
2949
+ avgDurationMs,
2950
+ adoptedSuccessRate: adoptedCount > 0 ? Math.round(adoptedSuccess / adoptedCount * 100) / 100 : 0,
2951
+ nonAdoptedSuccessRate: nonAdopted.length > 0 ? Math.round(nonAdoptedSuccess / nonAdopted.length * 100) / 100 : 0,
2952
+ cacheHitRate: totalSuggestions > 0 ? Math.round(cacheHits / totalSuggestions * 100) / 100 : 0
2953
+ };
2954
+ }
2955
+ /** Reset session history. */
2956
+ resetMetrics() {
2957
+ this._sessions = [];
2958
+ }
2959
+ // ─── Internal ───────────────────────────────────────
2960
+ /** Sync cache with server */
2961
+ async sync() {
2962
+ try {
2963
+ const result = await this.client.sync({
2964
+ pull: { since: this.cache.cursor },
2965
+ scope: this.scope
2966
+ });
2967
+ if (result.data?.pulled) {
2968
+ this.cache.applyDelta({ pulled: result.data.pulled });
2969
+ }
2970
+ } catch {
2971
+ }
2972
+ }
2973
+ /** Flush outbox to server */
2974
+ async flush() {
2975
+ if (this.outbox.length === 0) return;
2976
+ const batch = this.outbox.splice(0, this.config.outboxMaxSize);
2977
+ const promises = batch.map(
2978
+ (entry) => this.client.record({
2979
+ gene_id: entry.geneId,
2980
+ signals: entry.signals.map((s) => s.type),
2981
+ outcome: entry.outcome,
2982
+ summary: entry.summary,
2983
+ score: entry.score,
2984
+ metadata: entry.metadata,
2985
+ scope: this.scope
2986
+ }).catch(() => {
2987
+ this.outbox.push(entry);
2988
+ })
2989
+ );
2990
+ await Promise.allSettled(promises);
2991
+ }
2992
+ };
2993
+
2326
2994
  // src/index.ts
2327
2995
  var AccountClient = class {
2328
2996
  constructor(_r) {
@@ -2448,8 +3116,8 @@ var MessagesClient = class {
2448
3116
  return this._r("GET", `/api/im/messages/${conversationId}`, void 0, query);
2449
3117
  }
2450
3118
  /** Edit a message */
2451
- async edit(conversationId, messageId, content) {
2452
- return this._r("PATCH", `/api/im/messages/${conversationId}/${messageId}`, { content });
3119
+ async edit(conversationId, messageId, content, options) {
3120
+ return this._r("PATCH", `/api/im/messages/${conversationId}/${messageId}`, { content, ...options?.metadata ? { metadata: options.metadata } : {} });
2453
3121
  }
2454
3122
  /** Delete a message */
2455
3123
  async delete(conversationId, messageId) {
@@ -2536,6 +3204,560 @@ var WorkspaceClient = class {
2536
3204
  return this._r("GET", "/api/im/workspace/mentions/autocomplete", void 0, q);
2537
3205
  }
2538
3206
  };
3207
+ var TasksClient = class {
3208
+ constructor(_r) {
3209
+ this._r = _r;
3210
+ }
3211
+ /** Create a new task */
3212
+ async create(options) {
3213
+ return this._r("POST", "/api/im/tasks", options);
3214
+ }
3215
+ /** List tasks with optional filters */
3216
+ async list(options) {
3217
+ const query = {};
3218
+ if (options?.status) query.status = options.status;
3219
+ if (options?.capability) query.capability = options.capability;
3220
+ if (options?.assigneeId) query.assigneeId = options.assigneeId;
3221
+ if (options?.creatorId) query.creatorId = options.creatorId;
3222
+ if (options?.scheduleType) query.scheduleType = options.scheduleType;
3223
+ if (options?.limit != null) query.limit = String(options.limit);
3224
+ if (options?.cursor) query.cursor = options.cursor;
3225
+ return this._r("GET", "/api/im/tasks", void 0, query);
3226
+ }
3227
+ /** Get task details with logs */
3228
+ async get(taskId) {
3229
+ return this._r("GET", `/api/im/tasks/${taskId}`);
3230
+ }
3231
+ /** Update a task */
3232
+ async update(taskId, options) {
3233
+ return this._r("PATCH", `/api/im/tasks/${taskId}`, options);
3234
+ }
3235
+ /** Claim a pending task */
3236
+ async claim(taskId) {
3237
+ return this._r("POST", `/api/im/tasks/${taskId}/claim`);
3238
+ }
3239
+ /** Report progress on a task */
3240
+ async progress(taskId, options) {
3241
+ return this._r("POST", `/api/im/tasks/${taskId}/progress`, options);
3242
+ }
3243
+ /** Complete a task with result */
3244
+ async complete(taskId, options) {
3245
+ return this._r("POST", `/api/im/tasks/${taskId}/complete`, options);
3246
+ }
3247
+ /** Fail a task with error */
3248
+ async fail(taskId, error, metadata) {
3249
+ return this._r("POST", `/api/im/tasks/${taskId}/fail`, { error, metadata });
3250
+ }
3251
+ };
3252
+ var MemoryClient = class {
3253
+ constructor(_r) {
3254
+ this._r = _r;
3255
+ }
3256
+ /** Create a memory file */
3257
+ async createFile(options) {
3258
+ return this._r("POST", "/api/im/memory/files", options);
3259
+ }
3260
+ /** List memory files */
3261
+ async listFiles(options) {
3262
+ const query = {};
3263
+ if (options?.scope) query.scope = options.scope;
3264
+ if (options?.path) query.path = options.path;
3265
+ return this._r("GET", "/api/im/memory/files", void 0, query);
3266
+ }
3267
+ /** Get a memory file by ID */
3268
+ async getFile(fileId) {
3269
+ return this._r("GET", `/api/im/memory/files/${fileId}`);
3270
+ }
3271
+ /** Update a memory file (append, replace, or replace_section) */
3272
+ async updateFile(fileId, options) {
3273
+ return this._r("PATCH", `/api/im/memory/files/${fileId}`, options);
3274
+ }
3275
+ /** Delete a memory file */
3276
+ async deleteFile(fileId) {
3277
+ return this._r("DELETE", `/api/im/memory/files/${fileId}`);
3278
+ }
3279
+ /** Compact conversation messages into a summary */
3280
+ async compact(options) {
3281
+ return this._r("POST", "/api/im/memory/compact", options);
3282
+ }
3283
+ /** Get compaction summaries for a conversation */
3284
+ async getCompaction(conversationId) {
3285
+ return this._r("GET", `/api/im/memory/compact/${conversationId}`);
3286
+ }
3287
+ /** Load memory for session context */
3288
+ async load(scope) {
3289
+ const query = {};
3290
+ if (scope) query.scope = scope;
3291
+ return this._r("GET", "/api/im/memory/load", void 0, query);
3292
+ }
3293
+ };
3294
+ var IdentityClient = class {
3295
+ constructor(_r) {
3296
+ this._r = _r;
3297
+ }
3298
+ /** Get server public key */
3299
+ async getServerKey() {
3300
+ return this._r("GET", "/api/im/keys/server");
3301
+ }
3302
+ /** Register or rotate an identity key */
3303
+ async registerKey(options) {
3304
+ return this._r("PUT", "/api/im/keys/identity", options);
3305
+ }
3306
+ /** Get a user's identity key */
3307
+ async getKey(userId) {
3308
+ return this._r("GET", `/api/im/keys/identity/${userId}`);
3309
+ }
3310
+ /** Revoke own identity key */
3311
+ async revokeKey() {
3312
+ return this._r("POST", "/api/im/keys/identity/revoke");
3313
+ }
3314
+ /** Get key audit log for a user */
3315
+ async getAuditLog(userId) {
3316
+ return this._r("GET", `/api/im/keys/audit/${userId}`);
3317
+ }
3318
+ /** Verify key audit log integrity */
3319
+ async verifyAuditLog(userId) {
3320
+ return this._r("GET", `/api/im/keys/audit/${userId}/verify`);
3321
+ }
3322
+ };
3323
+ var SecurityClient = class {
3324
+ constructor(_r) {
3325
+ this._r = _r;
3326
+ }
3327
+ /** Get conversation security settings */
3328
+ async getConversationSecurity(conversationId) {
3329
+ return this._r("GET", `/api/im/conversations/${conversationId}/security`);
3330
+ }
3331
+ /** Update conversation security settings */
3332
+ async setConversationSecurity(conversationId, options) {
3333
+ return this._r("PATCH", `/api/im/conversations/${conversationId}/security`, options);
3334
+ }
3335
+ /** Upload a public key for a conversation */
3336
+ async uploadKey(conversationId, publicKey, algorithm) {
3337
+ const body = { publicKey };
3338
+ if (algorithm) body.algorithm = algorithm;
3339
+ return this._r("POST", `/api/im/conversations/${conversationId}/keys`, body);
3340
+ }
3341
+ /** Get keys for a conversation */
3342
+ async getKeys(conversationId) {
3343
+ return this._r("GET", `/api/im/conversations/${conversationId}/keys`);
3344
+ }
3345
+ /** Revoke a key for a specific user in a conversation */
3346
+ async revokeKey(conversationId, keyUserId) {
3347
+ return this._r("DELETE", `/api/im/conversations/${conversationId}/keys/${keyUserId}`);
3348
+ }
3349
+ };
3350
+ var EvolutionClient = class {
3351
+ constructor(_r) {
3352
+ this._r = _r;
3353
+ }
3354
+ // ── Public endpoints (no auth required) ──
3355
+ /** Get evolution stats */
3356
+ async getStats() {
3357
+ return this._r("GET", "/api/im/evolution/public/stats");
3358
+ }
3359
+ /** Get hot/trending genes */
3360
+ async getHotGenes(limit) {
3361
+ const query = {};
3362
+ if (limit != null) query.limit = String(limit);
3363
+ return this._r("GET", "/api/im/evolution/public/hot", void 0, query);
3364
+ }
3365
+ /** Browse published genes */
3366
+ async browseGenes(options) {
3367
+ const query = {};
3368
+ if (options?.category) query.category = options.category;
3369
+ if (options?.search) query.search = options.search;
3370
+ if (options?.sort) query.sort = options.sort;
3371
+ if (options?.page != null) query.page = String(options.page);
3372
+ if (options?.limit != null) query.limit = String(options.limit);
3373
+ return this._r("GET", "/api/im/evolution/public/genes", void 0, query);
3374
+ }
3375
+ /** Get a public gene by ID */
3376
+ async getPublicGene(geneId) {
3377
+ return this._r("GET", `/api/im/evolution/public/genes/${geneId}`);
3378
+ }
3379
+ /** Get capsules for a public gene */
3380
+ async getGeneCapsules(geneId, limit) {
3381
+ const query = {};
3382
+ if (limit != null) query.limit = String(limit);
3383
+ return this._r("GET", `/api/im/evolution/public/genes/${geneId}/capsules`, void 0, query);
3384
+ }
3385
+ /** Get gene lineage (parent + children) */
3386
+ async getGeneLineage(geneId) {
3387
+ return this._r("GET", `/api/im/evolution/public/genes/${geneId}/lineage`);
3388
+ }
3389
+ /** Get public evolution feed */
3390
+ async getFeed(limit) {
3391
+ const query = {};
3392
+ if (limit != null) query.limit = String(limit);
3393
+ return this._r("GET", "/api/im/evolution/public/feed", void 0, query);
3394
+ }
3395
+ // ── Authenticated endpoints ──
3396
+ /** Analyze signals and get gene recommendation */
3397
+ async analyze(options) {
3398
+ const { scope, ...body } = options;
3399
+ const q = {};
3400
+ if (scope) q.scope = scope;
3401
+ return this._r("POST", "/api/im/evolution/analyze", body, q);
3402
+ }
3403
+ /** Record an outcome (success/failure) for a gene */
3404
+ async record(options) {
3405
+ const { scope, ...body } = options;
3406
+ const q = {};
3407
+ if (scope) q.scope = scope;
3408
+ return this._r("POST", "/api/im/evolution/record", body, q);
3409
+ }
3410
+ /**
3411
+ * One-step evolution: analyze context → get gene recommendation → auto-record outcome.
3412
+ * Combines analyze() + record() into a single call for the common case.
3413
+ *
3414
+ * Usage:
3415
+ * const result = await client.evolution.evolve({
3416
+ * error: 'Connection timeout after 10s',
3417
+ * outcome: 'success',
3418
+ * score: 0.85,
3419
+ * summary: 'Fixed with exponential backoff',
3420
+ * });
3421
+ */
3422
+ async evolve(options) {
3423
+ const { outcome, score, summary, strategy_used, scope, ...analyzeOpts } = options;
3424
+ const analysis = await this.analyze({ ...analyzeOpts, ...scope ? { scope } : {} });
3425
+ if (!analysis.ok || !analysis.data) {
3426
+ return { ok: false, error: analysis.error };
3427
+ }
3428
+ const data = analysis.data;
3429
+ const geneId = data.gene_id;
3430
+ if (geneId && (data.action === "apply_gene" || data.action === "explore")) {
3431
+ const recordResult = await this.record({
3432
+ gene_id: geneId,
3433
+ signals: data.signals || analyzeOpts.signals || [],
3434
+ outcome,
3435
+ score: score ?? (outcome === "success" ? 0.8 : 0.2),
3436
+ summary: summary || `${outcome === "success" ? "Resolved" : "Failed to resolve"} using ${geneId}`,
3437
+ strategy_used,
3438
+ ...scope ? { scope } : {}
3439
+ });
3440
+ return {
3441
+ ok: true,
3442
+ data: {
3443
+ analysis: data,
3444
+ recorded: true,
3445
+ edge_updated: recordResult.data?.edge_updated
3446
+ }
3447
+ };
3448
+ }
3449
+ return {
3450
+ ok: true,
3451
+ data: { analysis: data, recorded: false }
3452
+ };
3453
+ }
3454
+ /** Trigger gene distillation */
3455
+ async distill(dryRun) {
3456
+ const query = {};
3457
+ if (dryRun) query.dry_run = "true";
3458
+ return this._r("POST", "/api/im/evolution/distill", void 0, query);
3459
+ }
3460
+ /** List own genes */
3461
+ async listGenes(signals, scope) {
3462
+ const query = {};
3463
+ if (signals) query.signals = signals;
3464
+ if (scope) query.scope = scope;
3465
+ return this._r("GET", "/api/im/evolution/genes", void 0, query);
3466
+ }
3467
+ /** Create a new gene */
3468
+ async createGene(options) {
3469
+ const { scope, ...body } = options;
3470
+ const q = {};
3471
+ if (scope) q.scope = scope;
3472
+ return this._r("POST", "/api/im/evolution/genes", body, q);
3473
+ }
3474
+ /** Delete a gene */
3475
+ async deleteGene(geneId) {
3476
+ return this._r("DELETE", `/api/im/evolution/genes/${encodeURIComponent(geneId)}`);
3477
+ }
3478
+ /** Publish a gene. Pass skipCanary=true to bypass canary validation (MVP/admin). */
3479
+ async publishGene(geneId, options) {
3480
+ return this._r("POST", `/api/im/evolution/genes/${encodeURIComponent(geneId)}/publish`, options?.skipCanary ? { skipCanary: true } : void 0);
3481
+ }
3482
+ /** Import a published gene */
3483
+ async importGene(geneId) {
3484
+ return this._r("POST", "/api/im/evolution/genes/import", { gene_id: geneId });
3485
+ }
3486
+ /** Fork a gene with modifications */
3487
+ async forkGene(options) {
3488
+ return this._r("POST", "/api/im/evolution/genes/fork", options);
3489
+ }
3490
+ /** Get signal-gene edges */
3491
+ async getEdges(options) {
3492
+ const query = {};
3493
+ if (options?.signalKey) query.signal_key = options.signalKey;
3494
+ if (options?.geneId) query.gene_id = options.geneId;
3495
+ if (options?.limit != null) query.limit = String(options.limit);
3496
+ if (options?.scope) query.scope = options.scope;
3497
+ return this._r("GET", "/api/im/evolution/edges", void 0, query);
3498
+ }
3499
+ /** Get agent personality profile */
3500
+ async getPersonality(agentId) {
3501
+ return this._r("GET", `/api/im/evolution/personality/${agentId}`);
3502
+ }
3503
+ /** Get own capsule history */
3504
+ async getCapsules(options) {
3505
+ const query = {};
3506
+ if (options?.page != null) query.page = String(options.page);
3507
+ if (options?.limit != null) query.limit = String(options.limit);
3508
+ if (options?.scope) query.scope = options.scope;
3509
+ return this._r("GET", "/api/im/evolution/capsules", void 0, query);
3510
+ }
3511
+ /** Get evolution report */
3512
+ async getReport(agentId, scope) {
3513
+ const query = {};
3514
+ if (agentId) query.agent_id = agentId;
3515
+ if (scope) query.scope = scope;
3516
+ return this._r("GET", "/api/im/evolution/report", void 0, query);
3517
+ }
3518
+ /** List available evolution scopes */
3519
+ async listScopes() {
3520
+ return this._r("GET", "/api/im/evolution/scopes");
3521
+ }
3522
+ // ─── v0.3.1: Stories, Metrics, Skills ──────────────
3523
+ /** Get recent evolution stories (for L1 narrative embedding) */
3524
+ async getStories(options) {
3525
+ const query = {};
3526
+ if (options?.limit != null) query.limit = String(options.limit);
3527
+ if (options?.since != null) query.since = String(options.since);
3528
+ return this._r("GET", "/api/im/evolution/stories", void 0, query);
3529
+ }
3530
+ /** Get north-star metrics comparison (standard vs hypergraph) */
3531
+ async getMetrics() {
3532
+ return this._r("GET", "/api/im/evolution/metrics");
3533
+ }
3534
+ /** Trigger metrics collection snapshot */
3535
+ async collectMetrics(windowHours) {
3536
+ return this._r("POST", "/api/im/evolution/metrics/collect", { window_hours: windowHours ?? 1 });
3537
+ }
3538
+ /** Search skills catalog */
3539
+ async searchSkills(options) {
3540
+ const q = {};
3541
+ if (options?.query) q.query = options.query;
3542
+ if (options?.category) q.category = options.category;
3543
+ if (options?.limit != null) q.limit = String(options.limit);
3544
+ return this._r("GET", "/api/im/skills/search", void 0, q);
3545
+ }
3546
+ /** Get skill catalog stats */
3547
+ async getSkillStats() {
3548
+ return this._r("GET", "/api/im/skills/stats");
3549
+ }
3550
+ /** Install a skill — creates Gene + returns content + install guide */
3551
+ async installSkill(slugOrId) {
3552
+ return this._r("POST", `/api/im/skills/${encodeURIComponent(slugOrId)}/install`);
3553
+ }
3554
+ /** Uninstall a skill */
3555
+ async uninstallSkill(slugOrId) {
3556
+ return this._r("DELETE", `/api/im/skills/${encodeURIComponent(slugOrId)}/install`);
3557
+ }
3558
+ /** List installed skills for this agent */
3559
+ async installedSkills() {
3560
+ return this._r("GET", "/api/im/skills/installed");
3561
+ }
3562
+ /** Get full skill content (SKILL.md + package info) */
3563
+ async getSkillContent(slugOrId) {
3564
+ return this._r("GET", `/api/im/skills/${encodeURIComponent(slugOrId)}/content`);
3565
+ }
3566
+ /** Create/submit a community skill */
3567
+ async createSkill(input) {
3568
+ return this._r("POST", "/api/im/skills", input);
3569
+ }
3570
+ /** Star a skill (increment community rating) */
3571
+ async starSkill(skillId) {
3572
+ return this._r("POST", `/api/im/skills/${encodeURIComponent(skillId)}/star`);
3573
+ }
3574
+ /**
3575
+ * Install a skill and write SKILL.md to local filesystem.
3576
+ * Combines cloud install + local file sync for Claude Code / OpenClaw / OpenCode.
3577
+ * @param slugOrId - Skill slug or ID
3578
+ * @param options - Local install options
3579
+ */
3580
+ async installSkillLocal(slugOrId, options) {
3581
+ const result = await this.installSkill(slugOrId);
3582
+ if (!result.ok || !result.data) return result;
3583
+ let content = result.data.skill?.content || "";
3584
+ if (!content) {
3585
+ const contentResult = await this.getSkillContent(slugOrId);
3586
+ content = contentResult.data?.content || "";
3587
+ }
3588
+ if (!content) {
3589
+ return { ...result, data: { ...result.data, localPaths: [] } };
3590
+ }
3591
+ const rawSlug = result.data.skill?.slug || slugOrId;
3592
+ const slug = rawSlug.replace(/[\/\\]/g, "").replace(/\.\./g, "");
3593
+ if (!slug) {
3594
+ return { ...result, data: { ...result.data, localPaths: [] } };
3595
+ }
3596
+ const localPaths = [];
3597
+ try {
3598
+ const fs = await import("fs");
3599
+ const path = await import("path");
3600
+ const os = await import("os");
3601
+ const home = os.homedir();
3602
+ const pluginBase = process.env.PRISMER_PLUGIN_DIR || path.join(home, ".claude", "plugins", "prismer");
3603
+ const platformPaths = options?.project ? {
3604
+ "claude-code": path.join(options.projectRoot || ".", ".claude", "skills", slug),
3605
+ "openclaw": path.join(options.projectRoot || ".", "skills", slug),
3606
+ "opencode": path.join(options.projectRoot || ".", ".opencode", "skills", slug),
3607
+ "plugin": path.join(options.projectRoot || ".", ".claude", "plugins", "prismer", "skills", slug)
3608
+ } : {
3609
+ "claude-code": path.join(home, ".claude", "skills", slug),
3610
+ "openclaw": path.join(home, ".openclaw", "skills", slug),
3611
+ "opencode": path.join(home, ".config", "opencode", "skills", slug),
3612
+ "plugin": path.join(pluginBase, "skills", slug)
3613
+ };
3614
+ const targets = options?.platforms || Object.keys(platformPaths);
3615
+ for (const platform of targets) {
3616
+ const dir = platformPaths[platform];
3617
+ if (!dir) continue;
3618
+ try {
3619
+ fs.mkdirSync(dir, { recursive: true });
3620
+ const filePath = path.join(dir, "SKILL.md");
3621
+ fs.writeFileSync(filePath, content, "utf-8");
3622
+ localPaths.push(filePath);
3623
+ } catch {
3624
+ }
3625
+ }
3626
+ } catch {
3627
+ }
3628
+ return { ...result, data: { ...result.data, localPaths } };
3629
+ }
3630
+ /**
3631
+ * Uninstall a skill and remove local SKILL.md files.
3632
+ */
3633
+ async uninstallSkillLocal(slugOrId) {
3634
+ const result = await this.uninstallSkill(slugOrId);
3635
+ const removedPaths = [];
3636
+ const slug = safeSlug(slugOrId);
3637
+ if (!slug) return { ...result, data: { uninstalled: result.data?.uninstalled ?? false, removedPaths } };
3638
+ try {
3639
+ const fs = await import("fs");
3640
+ const path = await import("path");
3641
+ const os = await import("os");
3642
+ const home = os.homedir();
3643
+ const pluginBase = process.env.PRISMER_PLUGIN_DIR || path.join(home, ".claude", "plugins", "prismer");
3644
+ const dirs = [
3645
+ path.join(home, ".claude", "skills", slug),
3646
+ path.join(home, ".openclaw", "skills", slug),
3647
+ path.join(home, ".config", "opencode", "skills", slug),
3648
+ path.join(pluginBase, "skills", slug)
3649
+ ];
3650
+ for (const dir of dirs) {
3651
+ try {
3652
+ if (fs.existsSync(dir)) {
3653
+ fs.rmSync(dir, { recursive: true });
3654
+ removedPaths.push(dir);
3655
+ }
3656
+ } catch {
3657
+ }
3658
+ }
3659
+ } catch {
3660
+ }
3661
+ return { ...result, data: { uninstalled: result.data?.uninstalled ?? false, removedPaths } };
3662
+ }
3663
+ /**
3664
+ * Sync all installed skills to local filesystem.
3665
+ */
3666
+ async syncSkillsLocal(options) {
3667
+ const installed = await this.installedSkills();
3668
+ if (!installed.ok || !installed.data) return { synced: 0, failed: 0, paths: [] };
3669
+ let synced = 0;
3670
+ let failed = 0;
3671
+ const paths = [];
3672
+ for (const record of installed.data) {
3673
+ const rawSlug = record.skill?.slug;
3674
+ if (!rawSlug) {
3675
+ failed++;
3676
+ continue;
3677
+ }
3678
+ const slug = rawSlug.replace(/[\/\\]/g, "").replace(/\.\./g, "");
3679
+ if (!slug) {
3680
+ failed++;
3681
+ continue;
3682
+ }
3683
+ try {
3684
+ const contentResult = await this.getSkillContent(slug);
3685
+ const content = contentResult.data?.content;
3686
+ if (!content) {
3687
+ failed++;
3688
+ continue;
3689
+ }
3690
+ const fs = await import("fs");
3691
+ const path = await import("path");
3692
+ const os = await import("os");
3693
+ const home = os.homedir();
3694
+ const pluginBase = process.env.PRISMER_PLUGIN_DIR || path.join(home, ".claude", "plugins", "prismer");
3695
+ const platformPaths = {
3696
+ "claude-code": path.join(home, ".claude", "skills", slug),
3697
+ "openclaw": path.join(home, ".openclaw", "skills", slug),
3698
+ "opencode": path.join(home, ".config", "opencode", "skills", slug),
3699
+ "plugin": path.join(pluginBase, "skills", slug)
3700
+ };
3701
+ const targets = options?.platforms || Object.keys(platformPaths);
3702
+ for (const platform of targets) {
3703
+ const dir = platformPaths[platform];
3704
+ if (!dir) continue;
3705
+ try {
3706
+ fs.mkdirSync(dir, { recursive: true });
3707
+ const filePath = path.join(dir, "SKILL.md");
3708
+ fs.writeFileSync(filePath, content, "utf-8");
3709
+ paths.push(filePath);
3710
+ } catch {
3711
+ }
3712
+ }
3713
+ synced++;
3714
+ } catch {
3715
+ failed++;
3716
+ }
3717
+ }
3718
+ return { synced, failed, paths };
3719
+ }
3720
+ /** Export a Gene as a Skill */
3721
+ async exportAsSkill(geneId, options) {
3722
+ return this._r("POST", `/api/im/evolution/genes/${geneId}/export-skill`, options);
3723
+ }
3724
+ // ─── P0: Report, Achievements, Sync ──────────────
3725
+ /** Submit a raw-context evolution report (auto-creates signals + gene match) */
3726
+ async submitReport(options) {
3727
+ return this._r("POST", "/api/im/evolution/report", {
3728
+ raw_context: options.rawContext,
3729
+ outcome: options.outcome,
3730
+ task_context: options.taskContext,
3731
+ task_error: options.taskError,
3732
+ task_id: options.taskId,
3733
+ metadata: options.metadata
3734
+ });
3735
+ }
3736
+ /** Get status of a submitted report by traceId */
3737
+ async getReportStatus(traceId) {
3738
+ return this._r("GET", `/api/im/evolution/report/${traceId}`);
3739
+ }
3740
+ /** Get evolution achievements for the current agent */
3741
+ async getAchievements() {
3742
+ return this._r("GET", "/api/im/evolution/achievements");
3743
+ }
3744
+ /** Get a sync snapshot (global gene/edge state since a sequence number) */
3745
+ async getSyncSnapshot(since) {
3746
+ const query = { scope: "global" };
3747
+ if (since != null) query.since = String(since);
3748
+ return this._r("GET", "/api/im/evolution/sync/snapshot", void 0, query);
3749
+ }
3750
+ /** Bidirectional sync: push local outcomes and pull remote updates */
3751
+ async sync(options) {
3752
+ const body = {};
3753
+ if (options?.pushOutcomes) body.push = { outcomes: options.pushOutcomes };
3754
+ if (options?.pullSince != null) body.pull = { since: options.pullSince };
3755
+ return this._r("POST", "/api/im/evolution/sync", body);
3756
+ }
3757
+ };
3758
+ function safeSlug(input) {
3759
+ return input.replace(/[\/\\]/g, "").replace(/\.\./g, "").replace(/\0/g, "");
3760
+ }
2539
3761
  function guessMimeType(fileName) {
2540
3762
  const ext = fileName.split(".").pop()?.toLowerCase() || "";
2541
3763
  const map = {
@@ -2774,6 +3996,11 @@ var IMClient = class {
2774
3996
  this.bindings = new BindingsClient(request);
2775
3997
  this.credits = new CreditsClient(request);
2776
3998
  this.workspace = new WorkspaceClient(request);
3999
+ this.tasks = new TasksClient(request);
4000
+ this.memory = new MemoryClient(request);
4001
+ this.identity = new IdentityClient(request);
4002
+ this.security = new SecurityClient(request);
4003
+ this.evolution = new EvolutionClient(request);
2777
4004
  this.files = new FilesClient(request, wsBase, fetchFn, getAuthHeaders);
2778
4005
  this.realtime = new IMRealtimeClient(wsBase);
2779
4006
  this.offline = offlineManager ?? null;
@@ -2948,6 +4175,7 @@ function createClient(config) {
2948
4175
  }
2949
4176
  // Annotate the CommonJS export names for ESM import in node:
2950
4177
  0 && (module.exports = {
4178
+ AIPIdentity,
2951
4179
  AccountClient,
2952
4180
  AttachmentQueue,
2953
4181
  BindingsClient,
@@ -2957,11 +4185,16 @@ function createClient(config) {
2957
4185
  DirectClient,
2958
4186
  E2EEncryption,
2959
4187
  ENVIRONMENTS,
4188
+ EvolutionCache,
4189
+ EvolutionClient,
4190
+ EvolutionRuntime,
2960
4191
  FilesClient,
2961
4192
  GroupsClient,
2962
4193
  IMClient,
2963
4194
  IMRealtimeClient,
4195
+ IdentityClient,
2964
4196
  IndexedDBStorage,
4197
+ MemoryClient,
2965
4198
  MemoryStorage,
2966
4199
  MessagesClient,
2967
4200
  OfflineManager,
@@ -2969,7 +4202,20 @@ function createClient(config) {
2969
4202
  RealtimeSSEClient,
2970
4203
  RealtimeWSClient,
2971
4204
  SQLiteStorage,
4205
+ SecurityClient,
2972
4206
  TabCoordinator,
4207
+ TasksClient,
2973
4208
  WorkspaceClient,
2974
- createClient
4209
+ createClient,
4210
+ createEnrichedExtractor,
4211
+ decryptContext,
4212
+ decryptFile,
4213
+ decryptMessages,
4214
+ decryptOnReceive,
4215
+ encryptContext,
4216
+ encryptFile,
4217
+ encryptForSend,
4218
+ extractSignals,
4219
+ guessMimeType,
4220
+ safeSlug
2975
4221
  });