@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/cli.js CHANGED
@@ -6,6 +6,10 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
9
13
  var __copyProps = (to, from, except, desc) => {
10
14
  if (from && typeof from === "object" || typeof from === "function") {
11
15
  for (let key of __getOwnPropNames(from))
@@ -22,8 +26,15 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
22
26
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
27
  mod
24
28
  ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
25
30
 
26
31
  // src/cli.ts
32
+ var cli_exports = {};
33
+ __export(cli_exports, {
34
+ getAPIClient: () => getAPIClient,
35
+ getIMClient: () => getIMClient
36
+ });
37
+ module.exports = __toCommonJS(cli_exports);
27
38
  var import_commander = require("commander");
28
39
  var fs = __toESM(require("fs"));
29
40
  var path = __toESM(require("path"));
@@ -224,10 +235,11 @@ var RealtimeWSClient = class extends TypedEmitter {
224
235
  joinConversation(conversationId) {
225
236
  this.sendRaw({ type: "conversation.join", payload: { conversationId } });
226
237
  }
227
- sendMessage(conversationId, content, type = "text") {
238
+ sendMessage(conversationId, content, options) {
239
+ const opts = typeof options === "string" ? { type: options } : options;
228
240
  this.sendRaw({
229
241
  type: "message.send",
230
- payload: { conversationId, content, type },
242
+ payload: { conversationId, content, type: opts?.type ?? "text", ...opts?.metadata ? { metadata: opts.metadata } : {}, ...opts?.parentId ? { parentId: opts.parentId } : {} },
231
243
  requestId: `msg-${++this.pingCounter}`
232
244
  });
233
245
  }
@@ -947,8 +959,8 @@ var OfflineManager = class extends OfflineEmitter {
947
959
  // ── Read cache ────────────────────────────────────────────
948
960
  async readFromCache(path2, query) {
949
961
  if (/\/api\/im\/conversations$/.test(path2)) {
950
- const convos2 = await this.storage.getConversations({ limit: 50 });
951
- if (convos2.length > 0) return { ok: true, data: convos2 };
962
+ const convos = await this.storage.getConversations({ limit: 50 });
963
+ if (convos.length > 0) return { ok: true, data: convos };
952
964
  }
953
965
  const msgMatch = path2.match(/\/api\/im\/messages\/([^/]+)$/);
954
966
  if (msgMatch) {
@@ -967,7 +979,7 @@ var OfflineManager = class extends OfflineEmitter {
967
979
  if (!result?.ok || !result?.data) return;
968
980
  try {
969
981
  if (/\/api\/im\/conversations$/.test(path2) && Array.isArray(result.data)) {
970
- const convos2 = result.data.map((c) => ({
982
+ const convos = result.data.map((c) => ({
971
983
  id: c.id,
972
984
  type: c.type ?? "direct",
973
985
  title: c.title,
@@ -978,7 +990,7 @@ var OfflineManager = class extends OfflineEmitter {
978
990
  metadata: c.metadata,
979
991
  updatedAt: c.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
980
992
  }));
981
- await this.storage.putConversations(convos2);
993
+ await this.storage.putConversations(convos);
982
994
  }
983
995
  const msgMatch = path2.match(/\/api\/im\/messages\/([^/]+)$/);
984
996
  if (msgMatch && Array.isArray(result.data)) {
@@ -1113,6 +1125,317 @@ var ENVIRONMENTS = {
1113
1125
  production: "https://prismer.cloud"
1114
1126
  };
1115
1127
 
1128
+ // src/aip.ts
1129
+ var import_aip_sdk = require("@prismer/aip-sdk");
1130
+ var import_aip_sdk2 = require("@prismer/aip-sdk");
1131
+ var import_aip_sdk3 = require("@prismer/aip-sdk");
1132
+ var import_aip_sdk4 = require("@prismer/aip-sdk");
1133
+
1134
+ // src/encryption.ts
1135
+ function getSubtleCrypto() {
1136
+ if (typeof globalThis.crypto?.subtle !== "undefined") {
1137
+ return globalThis.crypto.subtle;
1138
+ }
1139
+ try {
1140
+ const { webcrypto } = require("crypto");
1141
+ return webcrypto.subtle;
1142
+ } catch {
1143
+ throw new Error("No SubtleCrypto available. Requires browser or Node.js 16+.");
1144
+ }
1145
+ }
1146
+ function getRandomValues(arr) {
1147
+ if (typeof globalThis.crypto?.getRandomValues !== "undefined") {
1148
+ return globalThis.crypto.getRandomValues(arr);
1149
+ }
1150
+ try {
1151
+ const { webcrypto } = require("crypto");
1152
+ return webcrypto.getRandomValues(arr);
1153
+ } catch {
1154
+ throw new Error("No crypto.getRandomValues available.");
1155
+ }
1156
+ }
1157
+ var subtle = () => getSubtleCrypto();
1158
+ var PBKDF2_ITERATIONS = 1e5;
1159
+ var SALT_LENGTH = 16;
1160
+ var IV_LENGTH = 12;
1161
+ var KEY_LENGTH = 256;
1162
+ var _E2EEncryption = class _E2EEncryption {
1163
+ constructor() {
1164
+ this.masterKey = null;
1165
+ this.keyPair = null;
1166
+ this.sessionKeys = /* @__PURE__ */ new Map();
1167
+ // conversationId → AES key
1168
+ this.salt = null;
1169
+ // ─── Pipeline Functions ──────────────────────────────────
1170
+ this.messageCount = 0;
1171
+ this.lastRotation = Date.now();
1172
+ }
1173
+ /**
1174
+ * Initialize encryption with user passphrase.
1175
+ * Derives a master key via PBKDF2 and generates an ECDH key pair.
1176
+ *
1177
+ * @param passphrase - User passphrase for master key derivation
1178
+ * @param salt - Optional Base64-encoded salt. If omitted, a random 16-byte salt is generated.
1179
+ * Store the salt (via exportSalt()) so you can re-derive the same master key later.
1180
+ */
1181
+ async init(passphrase, salt) {
1182
+ this.salt = salt ? new Uint8Array(base64ToArrayBuffer(salt)) : getRandomValues(new Uint8Array(SALT_LENGTH));
1183
+ const passphraseKey = await subtle().importKey(
1184
+ "raw",
1185
+ new TextEncoder().encode(passphrase),
1186
+ "PBKDF2",
1187
+ false,
1188
+ ["deriveKey"]
1189
+ );
1190
+ this.masterKey = await subtle().deriveKey(
1191
+ {
1192
+ name: "PBKDF2",
1193
+ salt: new Uint8Array(this.salt.buffer, this.salt.byteOffset, this.salt.byteLength).buffer,
1194
+ iterations: PBKDF2_ITERATIONS,
1195
+ hash: "SHA-256"
1196
+ },
1197
+ passphraseKey,
1198
+ { name: "AES-GCM", length: KEY_LENGTH },
1199
+ false,
1200
+ ["encrypt", "decrypt"]
1201
+ );
1202
+ this.keyPair = await subtle().generateKey(
1203
+ { name: "ECDH", namedCurve: "P-256" },
1204
+ true,
1205
+ ["deriveKey"]
1206
+ );
1207
+ }
1208
+ /**
1209
+ * Export the salt as Base64 string for persistent storage.
1210
+ * You must store this and pass it back to init() to re-derive the same master key.
1211
+ */
1212
+ exportSalt() {
1213
+ if (!this.salt) throw new Error("E2E not initialized. Call init() first.");
1214
+ return arrayBufferToBase64(this.salt.buffer);
1215
+ }
1216
+ /**
1217
+ * Export public key for sharing with conversation peers.
1218
+ */
1219
+ async exportPublicKey() {
1220
+ if (!this.keyPair) throw new Error("E2E not initialized. Call init() first.");
1221
+ return subtle().exportKey("jwk", this.keyPair.publicKey);
1222
+ }
1223
+ /**
1224
+ * Derive a shared session key for a conversation using ECDH.
1225
+ * Call this with each peer's public key.
1226
+ */
1227
+ async deriveSessionKey(conversationId, peerPublicKey) {
1228
+ if (!this.keyPair) throw new Error("E2E not initialized. Call init() first.");
1229
+ const importedPeerKey = await subtle().importKey(
1230
+ "jwk",
1231
+ peerPublicKey,
1232
+ { name: "ECDH", namedCurve: "P-256" },
1233
+ false,
1234
+ []
1235
+ );
1236
+ const sessionKey = await subtle().deriveKey(
1237
+ { name: "ECDH", public: importedPeerKey },
1238
+ this.keyPair.privateKey,
1239
+ { name: "AES-GCM", length: KEY_LENGTH },
1240
+ false,
1241
+ ["encrypt", "decrypt"]
1242
+ );
1243
+ this.sessionKeys.set(conversationId, sessionKey);
1244
+ }
1245
+ /**
1246
+ * Set a pre-shared session key for a conversation.
1247
+ * Useful when the key is exchanged out-of-band or derived from a group key.
1248
+ */
1249
+ async setSessionKey(conversationId, rawKey) {
1250
+ const key = await subtle().importKey(
1251
+ "raw",
1252
+ rawKey,
1253
+ { name: "AES-GCM", length: KEY_LENGTH },
1254
+ false,
1255
+ ["encrypt", "decrypt"]
1256
+ );
1257
+ this.sessionKeys.set(conversationId, key);
1258
+ }
1259
+ /**
1260
+ * Generate a random session key for a conversation.
1261
+ * Returns the raw key bytes for sharing with peers.
1262
+ */
1263
+ async generateSessionKey(conversationId) {
1264
+ const key = await subtle().generateKey(
1265
+ { name: "AES-GCM", length: KEY_LENGTH },
1266
+ true,
1267
+ ["encrypt", "decrypt"]
1268
+ );
1269
+ this.sessionKeys.set(conversationId, key);
1270
+ return subtle().exportKey("raw", key);
1271
+ }
1272
+ /**
1273
+ * Encrypt plaintext for a conversation.
1274
+ * Returns base64-encoded ciphertext with prepended IV.
1275
+ */
1276
+ async encrypt(conversationId, plaintext) {
1277
+ const key = this.sessionKeys.get(conversationId);
1278
+ if (!key) throw new Error(`No session key for conversation ${conversationId}. Call deriveSessionKey() first.`);
1279
+ const iv = getRandomValues(new Uint8Array(IV_LENGTH));
1280
+ const encoded = new TextEncoder().encode(plaintext);
1281
+ const ciphertext = await subtle().encrypt(
1282
+ { name: "AES-GCM", iv },
1283
+ key,
1284
+ encoded
1285
+ );
1286
+ const combined = new Uint8Array(iv.length + ciphertext.byteLength);
1287
+ combined.set(iv, 0);
1288
+ combined.set(new Uint8Array(ciphertext), iv.length);
1289
+ return arrayBufferToBase64(combined.buffer);
1290
+ }
1291
+ /**
1292
+ * Decrypt ciphertext from a conversation.
1293
+ * Expects base64-encoded data with prepended IV.
1294
+ */
1295
+ async decrypt(conversationId, ciphertext) {
1296
+ const key = this.sessionKeys.get(conversationId);
1297
+ if (!key) throw new Error(`No session key for conversation ${conversationId}. Call deriveSessionKey() first.`);
1298
+ const combined = base64ToArrayBuffer(ciphertext);
1299
+ const iv = combined.slice(0, IV_LENGTH);
1300
+ const data = combined.slice(IV_LENGTH);
1301
+ const decrypted = await subtle().decrypt(
1302
+ { name: "AES-GCM", iv: new Uint8Array(iv) },
1303
+ key,
1304
+ data
1305
+ );
1306
+ return new TextDecoder().decode(decrypted);
1307
+ }
1308
+ /**
1309
+ * Check if a session key exists for a conversation.
1310
+ */
1311
+ hasSessionKey(conversationId) {
1312
+ return this.sessionKeys.has(conversationId);
1313
+ }
1314
+ /**
1315
+ * Remove session key for a conversation.
1316
+ */
1317
+ removeSessionKey(conversationId) {
1318
+ this.sessionKeys.delete(conversationId);
1319
+ }
1320
+ /**
1321
+ * Clear all keys and reset state.
1322
+ */
1323
+ destroy() {
1324
+ this.masterKey = null;
1325
+ this.keyPair = null;
1326
+ this.sessionKeys.clear();
1327
+ this.salt = null;
1328
+ this.messageCount = 0;
1329
+ }
1330
+ /**
1331
+ * High-level encrypt-for-send pipeline.
1332
+ * Encrypts content, builds metadata, and handles key rotation.
1333
+ *
1334
+ * Returns { encryptedContent, metadata } ready to send.
1335
+ */
1336
+ async encryptForSend(conversationId, content) {
1337
+ if (!this.hasSessionKey(conversationId)) {
1338
+ throw new Error("No session key for this conversation. Call deriveSessionKey() first.");
1339
+ }
1340
+ const needsRotation = this.shouldRotateKey();
1341
+ const encryptedContent = await this.encrypt(conversationId, content);
1342
+ this.messageCount++;
1343
+ return {
1344
+ encryptedContent,
1345
+ metadata: {
1346
+ encrypted: true,
1347
+ encryptionVersion: 1,
1348
+ ...needsRotation && { keyRotationRequested: true }
1349
+ }
1350
+ };
1351
+ }
1352
+ /**
1353
+ * High-level decrypt-on-receive pipeline.
1354
+ * Decrypts content and validates metadata.
1355
+ */
1356
+ async decryptOnReceive(conversationId, encryptedContent, metadata) {
1357
+ if (!this.hasSessionKey(conversationId)) {
1358
+ throw new Error("No session key for this conversation. Call deriveSessionKey() first.");
1359
+ }
1360
+ return this.decrypt(conversationId, encryptedContent);
1361
+ }
1362
+ /**
1363
+ * High-level file encryption pipeline.
1364
+ */
1365
+ async encryptFile(conversationId, fileData) {
1366
+ const base64Data = arrayBufferToBase64(fileData);
1367
+ const encryptedData = await this.encrypt(conversationId, base64Data);
1368
+ return {
1369
+ encryptedData,
1370
+ metadata: {
1371
+ encrypted: true,
1372
+ encryptionVersion: 1,
1373
+ fileEncrypted: true
1374
+ }
1375
+ };
1376
+ }
1377
+ /**
1378
+ * High-level file decryption pipeline.
1379
+ */
1380
+ async decryptFile(conversationId, encryptedData) {
1381
+ const base64Data = await this.decrypt(conversationId, encryptedData);
1382
+ return base64ToArrayBuffer(base64Data);
1383
+ }
1384
+ /**
1385
+ * Check if key rotation is needed (1000 messages or 24 hours).
1386
+ */
1387
+ shouldRotateKey() {
1388
+ if (this.messageCount >= _E2EEncryption.KEY_ROTATION_THRESHOLD) {
1389
+ return true;
1390
+ }
1391
+ if (Date.now() - this.lastRotation >= _E2EEncryption.KEY_ROTATION_INTERVAL_MS) {
1392
+ return true;
1393
+ }
1394
+ return false;
1395
+ }
1396
+ /**
1397
+ * Perform key rotation: generate new ECDH keypair and reset counters.
1398
+ * The caller is responsible for re-exchanging keys with peers.
1399
+ */
1400
+ async rotateKeys() {
1401
+ this.keyPair = await subtle().generateKey(
1402
+ { name: "ECDH", namedCurve: "P-256" },
1403
+ false,
1404
+ ["deriveKey"]
1405
+ );
1406
+ this.messageCount = 0;
1407
+ this.lastRotation = Date.now();
1408
+ this.sessionKeys.clear();
1409
+ return this.exportPublicKey();
1410
+ }
1411
+ };
1412
+ _E2EEncryption.KEY_ROTATION_THRESHOLD = 1e3;
1413
+ _E2EEncryption.KEY_ROTATION_INTERVAL_MS = 24 * 60 * 60 * 1e3;
1414
+ var E2EEncryption = _E2EEncryption;
1415
+ function arrayBufferToBase64(buffer) {
1416
+ if (typeof btoa !== "undefined") {
1417
+ const bytes = new Uint8Array(buffer);
1418
+ let binary = "";
1419
+ for (let i = 0; i < bytes.byteLength; i++) {
1420
+ binary += String.fromCharCode(bytes[i]);
1421
+ }
1422
+ return btoa(binary);
1423
+ }
1424
+ return Buffer.from(buffer).toString("base64");
1425
+ }
1426
+ function base64ToArrayBuffer(base64) {
1427
+ if (typeof atob !== "undefined") {
1428
+ const binary = atob(base64);
1429
+ const bytes = new Uint8Array(binary.length);
1430
+ for (let i = 0; i < binary.length; i++) {
1431
+ bytes[i] = binary.charCodeAt(i);
1432
+ }
1433
+ return bytes.buffer;
1434
+ }
1435
+ const buf = Buffer.from(base64, "base64");
1436
+ return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
1437
+ }
1438
+
1116
1439
  // src/index.ts
1117
1440
  var AccountClient = class {
1118
1441
  constructor(_r) {
@@ -1238,8 +1561,8 @@ var MessagesClient = class {
1238
1561
  return this._r("GET", `/api/im/messages/${conversationId}`, void 0, query);
1239
1562
  }
1240
1563
  /** Edit a message */
1241
- async edit(conversationId, messageId, content) {
1242
- return this._r("PATCH", `/api/im/messages/${conversationId}/${messageId}`, { content });
1564
+ async edit(conversationId, messageId, content, options) {
1565
+ return this._r("PATCH", `/api/im/messages/${conversationId}/${messageId}`, { content, ...options?.metadata ? { metadata: options.metadata } : {} });
1243
1566
  }
1244
1567
  /** Delete a message */
1245
1568
  async delete(conversationId, messageId) {
@@ -1326,6 +1649,560 @@ var WorkspaceClient = class {
1326
1649
  return this._r("GET", "/api/im/workspace/mentions/autocomplete", void 0, q);
1327
1650
  }
1328
1651
  };
1652
+ var TasksClient = class {
1653
+ constructor(_r) {
1654
+ this._r = _r;
1655
+ }
1656
+ /** Create a new task */
1657
+ async create(options) {
1658
+ return this._r("POST", "/api/im/tasks", options);
1659
+ }
1660
+ /** List tasks with optional filters */
1661
+ async list(options) {
1662
+ const query = {};
1663
+ if (options?.status) query.status = options.status;
1664
+ if (options?.capability) query.capability = options.capability;
1665
+ if (options?.assigneeId) query.assigneeId = options.assigneeId;
1666
+ if (options?.creatorId) query.creatorId = options.creatorId;
1667
+ if (options?.scheduleType) query.scheduleType = options.scheduleType;
1668
+ if (options?.limit != null) query.limit = String(options.limit);
1669
+ if (options?.cursor) query.cursor = options.cursor;
1670
+ return this._r("GET", "/api/im/tasks", void 0, query);
1671
+ }
1672
+ /** Get task details with logs */
1673
+ async get(taskId) {
1674
+ return this._r("GET", `/api/im/tasks/${taskId}`);
1675
+ }
1676
+ /** Update a task */
1677
+ async update(taskId, options) {
1678
+ return this._r("PATCH", `/api/im/tasks/${taskId}`, options);
1679
+ }
1680
+ /** Claim a pending task */
1681
+ async claim(taskId) {
1682
+ return this._r("POST", `/api/im/tasks/${taskId}/claim`);
1683
+ }
1684
+ /** Report progress on a task */
1685
+ async progress(taskId, options) {
1686
+ return this._r("POST", `/api/im/tasks/${taskId}/progress`, options);
1687
+ }
1688
+ /** Complete a task with result */
1689
+ async complete(taskId, options) {
1690
+ return this._r("POST", `/api/im/tasks/${taskId}/complete`, options);
1691
+ }
1692
+ /** Fail a task with error */
1693
+ async fail(taskId, error, metadata) {
1694
+ return this._r("POST", `/api/im/tasks/${taskId}/fail`, { error, metadata });
1695
+ }
1696
+ };
1697
+ var MemoryClient = class {
1698
+ constructor(_r) {
1699
+ this._r = _r;
1700
+ }
1701
+ /** Create a memory file */
1702
+ async createFile(options) {
1703
+ return this._r("POST", "/api/im/memory/files", options);
1704
+ }
1705
+ /** List memory files */
1706
+ async listFiles(options) {
1707
+ const query = {};
1708
+ if (options?.scope) query.scope = options.scope;
1709
+ if (options?.path) query.path = options.path;
1710
+ return this._r("GET", "/api/im/memory/files", void 0, query);
1711
+ }
1712
+ /** Get a memory file by ID */
1713
+ async getFile(fileId) {
1714
+ return this._r("GET", `/api/im/memory/files/${fileId}`);
1715
+ }
1716
+ /** Update a memory file (append, replace, or replace_section) */
1717
+ async updateFile(fileId, options) {
1718
+ return this._r("PATCH", `/api/im/memory/files/${fileId}`, options);
1719
+ }
1720
+ /** Delete a memory file */
1721
+ async deleteFile(fileId) {
1722
+ return this._r("DELETE", `/api/im/memory/files/${fileId}`);
1723
+ }
1724
+ /** Compact conversation messages into a summary */
1725
+ async compact(options) {
1726
+ return this._r("POST", "/api/im/memory/compact", options);
1727
+ }
1728
+ /** Get compaction summaries for a conversation */
1729
+ async getCompaction(conversationId) {
1730
+ return this._r("GET", `/api/im/memory/compact/${conversationId}`);
1731
+ }
1732
+ /** Load memory for session context */
1733
+ async load(scope) {
1734
+ const query = {};
1735
+ if (scope) query.scope = scope;
1736
+ return this._r("GET", "/api/im/memory/load", void 0, query);
1737
+ }
1738
+ };
1739
+ var IdentityClient = class {
1740
+ constructor(_r) {
1741
+ this._r = _r;
1742
+ }
1743
+ /** Get server public key */
1744
+ async getServerKey() {
1745
+ return this._r("GET", "/api/im/keys/server");
1746
+ }
1747
+ /** Register or rotate an identity key */
1748
+ async registerKey(options) {
1749
+ return this._r("PUT", "/api/im/keys/identity", options);
1750
+ }
1751
+ /** Get a user's identity key */
1752
+ async getKey(userId) {
1753
+ return this._r("GET", `/api/im/keys/identity/${userId}`);
1754
+ }
1755
+ /** Revoke own identity key */
1756
+ async revokeKey() {
1757
+ return this._r("POST", "/api/im/keys/identity/revoke");
1758
+ }
1759
+ /** Get key audit log for a user */
1760
+ async getAuditLog(userId) {
1761
+ return this._r("GET", `/api/im/keys/audit/${userId}`);
1762
+ }
1763
+ /** Verify key audit log integrity */
1764
+ async verifyAuditLog(userId) {
1765
+ return this._r("GET", `/api/im/keys/audit/${userId}/verify`);
1766
+ }
1767
+ };
1768
+ var SecurityClient = class {
1769
+ constructor(_r) {
1770
+ this._r = _r;
1771
+ }
1772
+ /** Get conversation security settings */
1773
+ async getConversationSecurity(conversationId) {
1774
+ return this._r("GET", `/api/im/conversations/${conversationId}/security`);
1775
+ }
1776
+ /** Update conversation security settings */
1777
+ async setConversationSecurity(conversationId, options) {
1778
+ return this._r("PATCH", `/api/im/conversations/${conversationId}/security`, options);
1779
+ }
1780
+ /** Upload a public key for a conversation */
1781
+ async uploadKey(conversationId, publicKey, algorithm) {
1782
+ const body = { publicKey };
1783
+ if (algorithm) body.algorithm = algorithm;
1784
+ return this._r("POST", `/api/im/conversations/${conversationId}/keys`, body);
1785
+ }
1786
+ /** Get keys for a conversation */
1787
+ async getKeys(conversationId) {
1788
+ return this._r("GET", `/api/im/conversations/${conversationId}/keys`);
1789
+ }
1790
+ /** Revoke a key for a specific user in a conversation */
1791
+ async revokeKey(conversationId, keyUserId) {
1792
+ return this._r("DELETE", `/api/im/conversations/${conversationId}/keys/${keyUserId}`);
1793
+ }
1794
+ };
1795
+ var EvolutionClient = class {
1796
+ constructor(_r) {
1797
+ this._r = _r;
1798
+ }
1799
+ // ── Public endpoints (no auth required) ──
1800
+ /** Get evolution stats */
1801
+ async getStats() {
1802
+ return this._r("GET", "/api/im/evolution/public/stats");
1803
+ }
1804
+ /** Get hot/trending genes */
1805
+ async getHotGenes(limit) {
1806
+ const query = {};
1807
+ if (limit != null) query.limit = String(limit);
1808
+ return this._r("GET", "/api/im/evolution/public/hot", void 0, query);
1809
+ }
1810
+ /** Browse published genes */
1811
+ async browseGenes(options) {
1812
+ const query = {};
1813
+ if (options?.category) query.category = options.category;
1814
+ if (options?.search) query.search = options.search;
1815
+ if (options?.sort) query.sort = options.sort;
1816
+ if (options?.page != null) query.page = String(options.page);
1817
+ if (options?.limit != null) query.limit = String(options.limit);
1818
+ return this._r("GET", "/api/im/evolution/public/genes", void 0, query);
1819
+ }
1820
+ /** Get a public gene by ID */
1821
+ async getPublicGene(geneId) {
1822
+ return this._r("GET", `/api/im/evolution/public/genes/${geneId}`);
1823
+ }
1824
+ /** Get capsules for a public gene */
1825
+ async getGeneCapsules(geneId, limit) {
1826
+ const query = {};
1827
+ if (limit != null) query.limit = String(limit);
1828
+ return this._r("GET", `/api/im/evolution/public/genes/${geneId}/capsules`, void 0, query);
1829
+ }
1830
+ /** Get gene lineage (parent + children) */
1831
+ async getGeneLineage(geneId) {
1832
+ return this._r("GET", `/api/im/evolution/public/genes/${geneId}/lineage`);
1833
+ }
1834
+ /** Get public evolution feed */
1835
+ async getFeed(limit) {
1836
+ const query = {};
1837
+ if (limit != null) query.limit = String(limit);
1838
+ return this._r("GET", "/api/im/evolution/public/feed", void 0, query);
1839
+ }
1840
+ // ── Authenticated endpoints ──
1841
+ /** Analyze signals and get gene recommendation */
1842
+ async analyze(options) {
1843
+ const { scope, ...body } = options;
1844
+ const q = {};
1845
+ if (scope) q.scope = scope;
1846
+ return this._r("POST", "/api/im/evolution/analyze", body, q);
1847
+ }
1848
+ /** Record an outcome (success/failure) for a gene */
1849
+ async record(options) {
1850
+ const { scope, ...body } = options;
1851
+ const q = {};
1852
+ if (scope) q.scope = scope;
1853
+ return this._r("POST", "/api/im/evolution/record", body, q);
1854
+ }
1855
+ /**
1856
+ * One-step evolution: analyze context → get gene recommendation → auto-record outcome.
1857
+ * Combines analyze() + record() into a single call for the common case.
1858
+ *
1859
+ * Usage:
1860
+ * const result = await client.evolution.evolve({
1861
+ * error: 'Connection timeout after 10s',
1862
+ * outcome: 'success',
1863
+ * score: 0.85,
1864
+ * summary: 'Fixed with exponential backoff',
1865
+ * });
1866
+ */
1867
+ async evolve(options) {
1868
+ const { outcome, score, summary, strategy_used, scope, ...analyzeOpts } = options;
1869
+ const analysis = await this.analyze({ ...analyzeOpts, ...scope ? { scope } : {} });
1870
+ if (!analysis.ok || !analysis.data) {
1871
+ return { ok: false, error: analysis.error };
1872
+ }
1873
+ const data = analysis.data;
1874
+ const geneId = data.gene_id;
1875
+ if (geneId && (data.action === "apply_gene" || data.action === "explore")) {
1876
+ const recordResult = await this.record({
1877
+ gene_id: geneId,
1878
+ signals: data.signals || analyzeOpts.signals || [],
1879
+ outcome,
1880
+ score: score ?? (outcome === "success" ? 0.8 : 0.2),
1881
+ summary: summary || `${outcome === "success" ? "Resolved" : "Failed to resolve"} using ${geneId}`,
1882
+ strategy_used,
1883
+ ...scope ? { scope } : {}
1884
+ });
1885
+ return {
1886
+ ok: true,
1887
+ data: {
1888
+ analysis: data,
1889
+ recorded: true,
1890
+ edge_updated: recordResult.data?.edge_updated
1891
+ }
1892
+ };
1893
+ }
1894
+ return {
1895
+ ok: true,
1896
+ data: { analysis: data, recorded: false }
1897
+ };
1898
+ }
1899
+ /** Trigger gene distillation */
1900
+ async distill(dryRun) {
1901
+ const query = {};
1902
+ if (dryRun) query.dry_run = "true";
1903
+ return this._r("POST", "/api/im/evolution/distill", void 0, query);
1904
+ }
1905
+ /** List own genes */
1906
+ async listGenes(signals, scope) {
1907
+ const query = {};
1908
+ if (signals) query.signals = signals;
1909
+ if (scope) query.scope = scope;
1910
+ return this._r("GET", "/api/im/evolution/genes", void 0, query);
1911
+ }
1912
+ /** Create a new gene */
1913
+ async createGene(options) {
1914
+ const { scope, ...body } = options;
1915
+ const q = {};
1916
+ if (scope) q.scope = scope;
1917
+ return this._r("POST", "/api/im/evolution/genes", body, q);
1918
+ }
1919
+ /** Delete a gene */
1920
+ async deleteGene(geneId) {
1921
+ return this._r("DELETE", `/api/im/evolution/genes/${encodeURIComponent(geneId)}`);
1922
+ }
1923
+ /** Publish a gene. Pass skipCanary=true to bypass canary validation (MVP/admin). */
1924
+ async publishGene(geneId, options) {
1925
+ return this._r("POST", `/api/im/evolution/genes/${encodeURIComponent(geneId)}/publish`, options?.skipCanary ? { skipCanary: true } : void 0);
1926
+ }
1927
+ /** Import a published gene */
1928
+ async importGene(geneId) {
1929
+ return this._r("POST", "/api/im/evolution/genes/import", { gene_id: geneId });
1930
+ }
1931
+ /** Fork a gene with modifications */
1932
+ async forkGene(options) {
1933
+ return this._r("POST", "/api/im/evolution/genes/fork", options);
1934
+ }
1935
+ /** Get signal-gene edges */
1936
+ async getEdges(options) {
1937
+ const query = {};
1938
+ if (options?.signalKey) query.signal_key = options.signalKey;
1939
+ if (options?.geneId) query.gene_id = options.geneId;
1940
+ if (options?.limit != null) query.limit = String(options.limit);
1941
+ if (options?.scope) query.scope = options.scope;
1942
+ return this._r("GET", "/api/im/evolution/edges", void 0, query);
1943
+ }
1944
+ /** Get agent personality profile */
1945
+ async getPersonality(agentId) {
1946
+ return this._r("GET", `/api/im/evolution/personality/${agentId}`);
1947
+ }
1948
+ /** Get own capsule history */
1949
+ async getCapsules(options) {
1950
+ const query = {};
1951
+ if (options?.page != null) query.page = String(options.page);
1952
+ if (options?.limit != null) query.limit = String(options.limit);
1953
+ if (options?.scope) query.scope = options.scope;
1954
+ return this._r("GET", "/api/im/evolution/capsules", void 0, query);
1955
+ }
1956
+ /** Get evolution report */
1957
+ async getReport(agentId, scope) {
1958
+ const query = {};
1959
+ if (agentId) query.agent_id = agentId;
1960
+ if (scope) query.scope = scope;
1961
+ return this._r("GET", "/api/im/evolution/report", void 0, query);
1962
+ }
1963
+ /** List available evolution scopes */
1964
+ async listScopes() {
1965
+ return this._r("GET", "/api/im/evolution/scopes");
1966
+ }
1967
+ // ─── v0.3.1: Stories, Metrics, Skills ──────────────
1968
+ /** Get recent evolution stories (for L1 narrative embedding) */
1969
+ async getStories(options) {
1970
+ const query = {};
1971
+ if (options?.limit != null) query.limit = String(options.limit);
1972
+ if (options?.since != null) query.since = String(options.since);
1973
+ return this._r("GET", "/api/im/evolution/stories", void 0, query);
1974
+ }
1975
+ /** Get north-star metrics comparison (standard vs hypergraph) */
1976
+ async getMetrics() {
1977
+ return this._r("GET", "/api/im/evolution/metrics");
1978
+ }
1979
+ /** Trigger metrics collection snapshot */
1980
+ async collectMetrics(windowHours) {
1981
+ return this._r("POST", "/api/im/evolution/metrics/collect", { window_hours: windowHours ?? 1 });
1982
+ }
1983
+ /** Search skills catalog */
1984
+ async searchSkills(options) {
1985
+ const q = {};
1986
+ if (options?.query) q.query = options.query;
1987
+ if (options?.category) q.category = options.category;
1988
+ if (options?.limit != null) q.limit = String(options.limit);
1989
+ return this._r("GET", "/api/im/skills/search", void 0, q);
1990
+ }
1991
+ /** Get skill catalog stats */
1992
+ async getSkillStats() {
1993
+ return this._r("GET", "/api/im/skills/stats");
1994
+ }
1995
+ /** Install a skill — creates Gene + returns content + install guide */
1996
+ async installSkill(slugOrId) {
1997
+ return this._r("POST", `/api/im/skills/${encodeURIComponent(slugOrId)}/install`);
1998
+ }
1999
+ /** Uninstall a skill */
2000
+ async uninstallSkill(slugOrId) {
2001
+ return this._r("DELETE", `/api/im/skills/${encodeURIComponent(slugOrId)}/install`);
2002
+ }
2003
+ /** List installed skills for this agent */
2004
+ async installedSkills() {
2005
+ return this._r("GET", "/api/im/skills/installed");
2006
+ }
2007
+ /** Get full skill content (SKILL.md + package info) */
2008
+ async getSkillContent(slugOrId) {
2009
+ return this._r("GET", `/api/im/skills/${encodeURIComponent(slugOrId)}/content`);
2010
+ }
2011
+ /** Create/submit a community skill */
2012
+ async createSkill(input) {
2013
+ return this._r("POST", "/api/im/skills", input);
2014
+ }
2015
+ /** Star a skill (increment community rating) */
2016
+ async starSkill(skillId) {
2017
+ return this._r("POST", `/api/im/skills/${encodeURIComponent(skillId)}/star`);
2018
+ }
2019
+ /**
2020
+ * Install a skill and write SKILL.md to local filesystem.
2021
+ * Combines cloud install + local file sync for Claude Code / OpenClaw / OpenCode.
2022
+ * @param slugOrId - Skill slug or ID
2023
+ * @param options - Local install options
2024
+ */
2025
+ async installSkillLocal(slugOrId, options) {
2026
+ const result = await this.installSkill(slugOrId);
2027
+ if (!result.ok || !result.data) return result;
2028
+ let content = result.data.skill?.content || "";
2029
+ if (!content) {
2030
+ const contentResult = await this.getSkillContent(slugOrId);
2031
+ content = contentResult.data?.content || "";
2032
+ }
2033
+ if (!content) {
2034
+ return { ...result, data: { ...result.data, localPaths: [] } };
2035
+ }
2036
+ const rawSlug = result.data.skill?.slug || slugOrId;
2037
+ const slug = rawSlug.replace(/[\/\\]/g, "").replace(/\.\./g, "");
2038
+ if (!slug) {
2039
+ return { ...result, data: { ...result.data, localPaths: [] } };
2040
+ }
2041
+ const localPaths = [];
2042
+ try {
2043
+ const fs2 = await import("fs");
2044
+ const path2 = await import("path");
2045
+ const os2 = await import("os");
2046
+ const home = os2.homedir();
2047
+ const pluginBase = process.env.PRISMER_PLUGIN_DIR || path2.join(home, ".claude", "plugins", "prismer");
2048
+ const platformPaths = options?.project ? {
2049
+ "claude-code": path2.join(options.projectRoot || ".", ".claude", "skills", slug),
2050
+ "openclaw": path2.join(options.projectRoot || ".", "skills", slug),
2051
+ "opencode": path2.join(options.projectRoot || ".", ".opencode", "skills", slug),
2052
+ "plugin": path2.join(options.projectRoot || ".", ".claude", "plugins", "prismer", "skills", slug)
2053
+ } : {
2054
+ "claude-code": path2.join(home, ".claude", "skills", slug),
2055
+ "openclaw": path2.join(home, ".openclaw", "skills", slug),
2056
+ "opencode": path2.join(home, ".config", "opencode", "skills", slug),
2057
+ "plugin": path2.join(pluginBase, "skills", slug)
2058
+ };
2059
+ const targets = options?.platforms || Object.keys(platformPaths);
2060
+ for (const platform of targets) {
2061
+ const dir = platformPaths[platform];
2062
+ if (!dir) continue;
2063
+ try {
2064
+ fs2.mkdirSync(dir, { recursive: true });
2065
+ const filePath = path2.join(dir, "SKILL.md");
2066
+ fs2.writeFileSync(filePath, content, "utf-8");
2067
+ localPaths.push(filePath);
2068
+ } catch {
2069
+ }
2070
+ }
2071
+ } catch {
2072
+ }
2073
+ return { ...result, data: { ...result.data, localPaths } };
2074
+ }
2075
+ /**
2076
+ * Uninstall a skill and remove local SKILL.md files.
2077
+ */
2078
+ async uninstallSkillLocal(slugOrId) {
2079
+ const result = await this.uninstallSkill(slugOrId);
2080
+ const removedPaths = [];
2081
+ const slug = safeSlug(slugOrId);
2082
+ if (!slug) return { ...result, data: { uninstalled: result.data?.uninstalled ?? false, removedPaths } };
2083
+ try {
2084
+ const fs2 = await import("fs");
2085
+ const path2 = await import("path");
2086
+ const os2 = await import("os");
2087
+ const home = os2.homedir();
2088
+ const pluginBase = process.env.PRISMER_PLUGIN_DIR || path2.join(home, ".claude", "plugins", "prismer");
2089
+ const dirs = [
2090
+ path2.join(home, ".claude", "skills", slug),
2091
+ path2.join(home, ".openclaw", "skills", slug),
2092
+ path2.join(home, ".config", "opencode", "skills", slug),
2093
+ path2.join(pluginBase, "skills", slug)
2094
+ ];
2095
+ for (const dir of dirs) {
2096
+ try {
2097
+ if (fs2.existsSync(dir)) {
2098
+ fs2.rmSync(dir, { recursive: true });
2099
+ removedPaths.push(dir);
2100
+ }
2101
+ } catch {
2102
+ }
2103
+ }
2104
+ } catch {
2105
+ }
2106
+ return { ...result, data: { uninstalled: result.data?.uninstalled ?? false, removedPaths } };
2107
+ }
2108
+ /**
2109
+ * Sync all installed skills to local filesystem.
2110
+ */
2111
+ async syncSkillsLocal(options) {
2112
+ const installed = await this.installedSkills();
2113
+ if (!installed.ok || !installed.data) return { synced: 0, failed: 0, paths: [] };
2114
+ let synced = 0;
2115
+ let failed = 0;
2116
+ const paths = [];
2117
+ for (const record of installed.data) {
2118
+ const rawSlug = record.skill?.slug;
2119
+ if (!rawSlug) {
2120
+ failed++;
2121
+ continue;
2122
+ }
2123
+ const slug = rawSlug.replace(/[\/\\]/g, "").replace(/\.\./g, "");
2124
+ if (!slug) {
2125
+ failed++;
2126
+ continue;
2127
+ }
2128
+ try {
2129
+ const contentResult = await this.getSkillContent(slug);
2130
+ const content = contentResult.data?.content;
2131
+ if (!content) {
2132
+ failed++;
2133
+ continue;
2134
+ }
2135
+ const fs2 = await import("fs");
2136
+ const path2 = await import("path");
2137
+ const os2 = await import("os");
2138
+ const home = os2.homedir();
2139
+ const pluginBase = process.env.PRISMER_PLUGIN_DIR || path2.join(home, ".claude", "plugins", "prismer");
2140
+ const platformPaths = {
2141
+ "claude-code": path2.join(home, ".claude", "skills", slug),
2142
+ "openclaw": path2.join(home, ".openclaw", "skills", slug),
2143
+ "opencode": path2.join(home, ".config", "opencode", "skills", slug),
2144
+ "plugin": path2.join(pluginBase, "skills", slug)
2145
+ };
2146
+ const targets = options?.platforms || Object.keys(platformPaths);
2147
+ for (const platform of targets) {
2148
+ const dir = platformPaths[platform];
2149
+ if (!dir) continue;
2150
+ try {
2151
+ fs2.mkdirSync(dir, { recursive: true });
2152
+ const filePath = path2.join(dir, "SKILL.md");
2153
+ fs2.writeFileSync(filePath, content, "utf-8");
2154
+ paths.push(filePath);
2155
+ } catch {
2156
+ }
2157
+ }
2158
+ synced++;
2159
+ } catch {
2160
+ failed++;
2161
+ }
2162
+ }
2163
+ return { synced, failed, paths };
2164
+ }
2165
+ /** Export a Gene as a Skill */
2166
+ async exportAsSkill(geneId, options) {
2167
+ return this._r("POST", `/api/im/evolution/genes/${geneId}/export-skill`, options);
2168
+ }
2169
+ // ─── P0: Report, Achievements, Sync ──────────────
2170
+ /** Submit a raw-context evolution report (auto-creates signals + gene match) */
2171
+ async submitReport(options) {
2172
+ return this._r("POST", "/api/im/evolution/report", {
2173
+ raw_context: options.rawContext,
2174
+ outcome: options.outcome,
2175
+ task_context: options.taskContext,
2176
+ task_error: options.taskError,
2177
+ task_id: options.taskId,
2178
+ metadata: options.metadata
2179
+ });
2180
+ }
2181
+ /** Get status of a submitted report by traceId */
2182
+ async getReportStatus(traceId) {
2183
+ return this._r("GET", `/api/im/evolution/report/${traceId}`);
2184
+ }
2185
+ /** Get evolution achievements for the current agent */
2186
+ async getAchievements() {
2187
+ return this._r("GET", "/api/im/evolution/achievements");
2188
+ }
2189
+ /** Get a sync snapshot (global gene/edge state since a sequence number) */
2190
+ async getSyncSnapshot(since) {
2191
+ const query = { scope: "global" };
2192
+ if (since != null) query.since = String(since);
2193
+ return this._r("GET", "/api/im/evolution/sync/snapshot", void 0, query);
2194
+ }
2195
+ /** Bidirectional sync: push local outcomes and pull remote updates */
2196
+ async sync(options) {
2197
+ const body = {};
2198
+ if (options?.pushOutcomes) body.push = { outcomes: options.pushOutcomes };
2199
+ if (options?.pullSince != null) body.pull = { since: options.pullSince };
2200
+ return this._r("POST", "/api/im/evolution/sync", body);
2201
+ }
2202
+ };
2203
+ function safeSlug(input) {
2204
+ return input.replace(/[\/\\]/g, "").replace(/\.\./g, "").replace(/\0/g, "");
2205
+ }
1329
2206
  function guessMimeType(fileName) {
1330
2207
  const ext = fileName.split(".").pop()?.toLowerCase() || "";
1331
2208
  const map = {
@@ -1564,6 +2441,11 @@ var IMClient = class {
1564
2441
  this.bindings = new BindingsClient(request);
1565
2442
  this.credits = new CreditsClient(request);
1566
2443
  this.workspace = new WorkspaceClient(request);
2444
+ this.tasks = new TasksClient(request);
2445
+ this.memory = new MemoryClient(request);
2446
+ this.identity = new IdentityClient(request);
2447
+ this.security = new SecurityClient(request);
2448
+ this.evolution = new EvolutionClient(request);
1567
2449
  this.files = new FilesClient(request, wsBase, fetchFn, getAuthHeaders);
1568
2450
  this.realtime = new IMRealtimeClient(wsBase);
1569
2451
  this.offline = offlineManager ?? null;
@@ -1733,41 +2615,2386 @@ var PrismerClient = class {
1733
2615
  }
1734
2616
  };
1735
2617
 
1736
- // src/cli.ts
1737
- var cliVersion = "1.3.3";
1738
- try {
1739
- const pkgPath = path.join(__dirname, "..", "package.json");
1740
- const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
1741
- cliVersion = pkg.version || cliVersion;
1742
- } catch {
1743
- }
1744
- var CONFIG_DIR = path.join(os.homedir(), ".prismer");
1745
- var CONFIG_PATH = path.join(CONFIG_DIR, "config.toml");
1746
- function ensureConfigDir() {
2618
+ // src/commands/im.ts
2619
+ function register(parent, getIMClient2, _getAPIClient) {
2620
+ const im = parent.command("im").description("IM messaging, groups, conversations, and credits");
2621
+ im.command("send <user-id> <message>").description("Send a direct message to a user").option("-t, --type <type>", "Message type: text, markdown, code, file, etc.", "text").option("--reply-to <msg-id>", "Reply to a specific message ID (parentId)").option("--json", "Output raw JSON response").action(async (userId, message, opts) => {
2622
+ const client = getIMClient2();
2623
+ try {
2624
+ const sendOpts = {
2625
+ type: opts.type
2626
+ };
2627
+ if (opts.replyTo) sendOpts.parentId = opts.replyTo;
2628
+ const res = await client.im.direct.send(userId, message, sendOpts);
2629
+ if (!res.ok) {
2630
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
2631
+ `);
2632
+ process.exit(1);
2633
+ }
2634
+ if (opts.json) {
2635
+ process.stdout.write(JSON.stringify(res.data, null, 2) + "\n");
2636
+ return;
2637
+ }
2638
+ process.stdout.write(`Message sent (conversationId: ${res.data?.conversationId})
2639
+ `);
2640
+ } catch (err) {
2641
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
2642
+ `);
2643
+ process.exit(1);
2644
+ }
2645
+ });
2646
+ im.command("messages <user-id>").description("View direct message history with a user").option("-n, --limit <n>", "Max number of messages to fetch", "20").option("--json", "Output raw JSON response").action(async (userId, opts) => {
2647
+ const client = getIMClient2();
2648
+ try {
2649
+ const res = await client.im.direct.getMessages(userId, { limit: parseInt(opts.limit, 10) });
2650
+ if (!res.ok) {
2651
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
2652
+ `);
2653
+ process.exit(1);
2654
+ }
2655
+ const msgs = res.data || [];
2656
+ if (opts.json) {
2657
+ process.stdout.write(JSON.stringify(msgs, null, 2) + "\n");
2658
+ return;
2659
+ }
2660
+ if (msgs.length === 0) {
2661
+ process.stdout.write("No messages.\n");
2662
+ return;
2663
+ }
2664
+ for (const m of msgs) {
2665
+ const ts = m.createdAt ? new Date(m.createdAt).toLocaleString() : "";
2666
+ process.stdout.write(`[${ts}] ${m.senderId || "?"}: ${m.content}
2667
+ `);
2668
+ }
2669
+ } catch (err) {
2670
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
2671
+ `);
2672
+ process.exit(1);
2673
+ }
2674
+ });
2675
+ im.command("edit <conversation-id> <message-id> <content>").description("Edit an existing message").option("--json", "Output raw JSON response").action(async (convId, msgId, content, opts) => {
2676
+ const client = getIMClient2();
2677
+ try {
2678
+ const res = await client.im.messages.edit(convId, msgId, content);
2679
+ if (!res.ok) {
2680
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
2681
+ `);
2682
+ process.exit(1);
2683
+ }
2684
+ if (opts.json) {
2685
+ process.stdout.write(JSON.stringify(res.data, null, 2) + "\n");
2686
+ return;
2687
+ }
2688
+ process.stdout.write(`Message ${msgId} updated.
2689
+ `);
2690
+ } catch (err) {
2691
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
2692
+ `);
2693
+ process.exit(1);
2694
+ }
2695
+ });
2696
+ im.command("delete <conversation-id> <message-id>").description("Delete a message").option("--json", "Output raw JSON response").action(async (convId, msgId, opts) => {
2697
+ const client = getIMClient2();
2698
+ try {
2699
+ const res = await client.im.messages.delete(convId, msgId);
2700
+ if (!res.ok) {
2701
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
2702
+ `);
2703
+ process.exit(1);
2704
+ }
2705
+ if (opts.json) {
2706
+ process.stdout.write(JSON.stringify(res.data, null, 2) + "\n");
2707
+ return;
2708
+ }
2709
+ process.stdout.write(`Message ${msgId} deleted.
2710
+ `);
2711
+ } catch (err) {
2712
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
2713
+ `);
2714
+ process.exit(1);
2715
+ }
2716
+ });
2717
+ im.command("discover").description("Discover available agents").option("--type <type>", "Filter by agent type").option("--capability <cap>", "Filter by capability").option("--json", "Output raw JSON response").action(async (opts) => {
2718
+ const client = getIMClient2();
2719
+ try {
2720
+ const discoverOpts = {};
2721
+ if (opts.type) discoverOpts.type = opts.type;
2722
+ if (opts.capability) discoverOpts.capability = opts.capability;
2723
+ const res = await client.im.contacts.discover(Object.keys(discoverOpts).length ? discoverOpts : void 0);
2724
+ if (!res.ok) {
2725
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
2726
+ `);
2727
+ process.exit(1);
2728
+ }
2729
+ const agents = res.data || [];
2730
+ if (opts.json) {
2731
+ process.stdout.write(JSON.stringify(agents, null, 2) + "\n");
2732
+ return;
2733
+ }
2734
+ if (agents.length === 0) {
2735
+ process.stdout.write("No agents found.\n");
2736
+ return;
2737
+ }
2738
+ process.stdout.write(
2739
+ "Username".padEnd(20) + "Type".padEnd(14) + "Status".padEnd(10) + "Display Name\n"
2740
+ );
2741
+ for (const a of agents) {
2742
+ process.stdout.write(
2743
+ `${(a.username || "").padEnd(20)}${(a.agentType || "").padEnd(14)}${(a.status || "").padEnd(10)}${a.displayName || ""}
2744
+ `
2745
+ );
2746
+ }
2747
+ } catch (err) {
2748
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
2749
+ `);
2750
+ process.exit(1);
2751
+ }
2752
+ });
2753
+ im.command("contacts").description("List contacts").option("--json", "Output raw JSON response").action(async (opts) => {
2754
+ const client = getIMClient2();
2755
+ try {
2756
+ const res = await client.im.contacts.list();
2757
+ if (!res.ok) {
2758
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
2759
+ `);
2760
+ process.exit(1);
2761
+ }
2762
+ const contacts = res.data || [];
2763
+ if (opts.json) {
2764
+ process.stdout.write(JSON.stringify(contacts, null, 2) + "\n");
2765
+ return;
2766
+ }
2767
+ if (contacts.length === 0) {
2768
+ process.stdout.write("No contacts.\n");
2769
+ return;
2770
+ }
2771
+ process.stdout.write(
2772
+ "Username".padEnd(20) + "Role".padEnd(10) + "Unread".padEnd(8) + "Display Name\n"
2773
+ );
2774
+ for (const c of contacts) {
2775
+ process.stdout.write(
2776
+ `${(c.username || "").padEnd(20)}${(c.role || "").padEnd(10)}${String(c.unreadCount ?? 0).padEnd(8)}${c.displayName || ""}
2777
+ `
2778
+ );
2779
+ }
2780
+ } catch (err) {
2781
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
2782
+ `);
2783
+ process.exit(1);
2784
+ }
2785
+ });
2786
+ im.command("conversations").description("List conversations").option("--unread", "Show only conversations with unread messages").option("--json", "Output raw JSON response").action(async (opts) => {
2787
+ const client = getIMClient2();
2788
+ try {
2789
+ const listOpts = {};
2790
+ if (opts.unread) {
2791
+ listOpts.withUnread = true;
2792
+ listOpts.unreadOnly = true;
2793
+ }
2794
+ const res = await client.im.conversations.list(listOpts);
2795
+ if (!res.ok) {
2796
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
2797
+ `);
2798
+ process.exit(1);
2799
+ }
2800
+ const list = res.data || [];
2801
+ if (opts.json) {
2802
+ process.stdout.write(JSON.stringify(list, null, 2) + "\n");
2803
+ return;
2804
+ }
2805
+ if (list.length === 0) {
2806
+ process.stdout.write("No conversations.\n");
2807
+ return;
2808
+ }
2809
+ for (const c of list) {
2810
+ const unread = c.unreadCount ? ` (${c.unreadCount} unread)` : "";
2811
+ process.stdout.write(`${c.id || ""} ${c.type || ""} ${c.title || ""}${unread}
2812
+ `);
2813
+ }
2814
+ } catch (err) {
2815
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
2816
+ `);
2817
+ process.exit(1);
2818
+ }
2819
+ });
2820
+ im.command("read <conversation-id>").description("Mark a conversation as read").action(async (convId) => {
2821
+ const client = getIMClient2();
2822
+ try {
2823
+ const res = await client.im.conversations.markAsRead(convId);
2824
+ if (!res.ok) {
2825
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
2826
+ `);
2827
+ process.exit(1);
2828
+ }
2829
+ process.stdout.write("Marked as read.\n");
2830
+ } catch (err) {
2831
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
2832
+ `);
2833
+ process.exit(1);
2834
+ }
2835
+ });
2836
+ const groups = im.command("groups").description("Group chat management");
2837
+ groups.command("create <title>").description("Create a new group").option("-m, --members <ids>", "Comma-separated member user IDs to add").option("--json", "Output raw JSON response").action(async (title, opts) => {
2838
+ const client = getIMClient2();
2839
+ try {
2840
+ const members = opts.members ? opts.members.split(",").map((s) => s.trim()) : [];
2841
+ const res = await client.im.groups.create({ title, members });
2842
+ if (!res.ok) {
2843
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
2844
+ `);
2845
+ process.exit(1);
2846
+ }
2847
+ if (opts.json) {
2848
+ process.stdout.write(JSON.stringify(res.data, null, 2) + "\n");
2849
+ return;
2850
+ }
2851
+ process.stdout.write(`Group created (groupId: ${res.data?.groupId})
2852
+ `);
2853
+ } catch (err) {
2854
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
2855
+ `);
2856
+ process.exit(1);
2857
+ }
2858
+ });
2859
+ groups.command("list").description("List groups you belong to").option("--json", "Output raw JSON response").action(async (opts) => {
2860
+ const client = getIMClient2();
2861
+ try {
2862
+ const res = await client.im.groups.list();
2863
+ if (!res.ok) {
2864
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
2865
+ `);
2866
+ process.exit(1);
2867
+ }
2868
+ const list = res.data || [];
2869
+ if (opts.json) {
2870
+ process.stdout.write(JSON.stringify(list, null, 2) + "\n");
2871
+ return;
2872
+ }
2873
+ if (list.length === 0) {
2874
+ process.stdout.write("No groups.\n");
2875
+ return;
2876
+ }
2877
+ for (const g of list) {
2878
+ process.stdout.write(`${g.groupId || ""} ${g.title || ""} (${g.members?.length || "?"} members)
2879
+ `);
2880
+ }
2881
+ } catch (err) {
2882
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
2883
+ `);
2884
+ process.exit(1);
2885
+ }
2886
+ });
2887
+ groups.command("send <group-id> <message>").description("Send a message to a group").option("--json", "Output raw JSON response").action(async (groupId, message, opts) => {
2888
+ const client = getIMClient2();
2889
+ try {
2890
+ const res = await client.im.groups.send(groupId, message);
2891
+ if (!res.ok) {
2892
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
2893
+ `);
2894
+ process.exit(1);
2895
+ }
2896
+ if (opts.json) {
2897
+ process.stdout.write(JSON.stringify(res.data, null, 2) + "\n");
2898
+ return;
2899
+ }
2900
+ process.stdout.write("Message sent to group.\n");
2901
+ } catch (err) {
2902
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
2903
+ `);
2904
+ process.exit(1);
2905
+ }
2906
+ });
2907
+ groups.command("messages <group-id>").description("View group message history").option("-n, --limit <n>", "Max number of messages to fetch", "20").option("--json", "Output raw JSON response").action(async (groupId, opts) => {
2908
+ const client = getIMClient2();
2909
+ try {
2910
+ const res = await client.im.groups.getMessages(groupId, { limit: parseInt(opts.limit, 10) });
2911
+ if (!res.ok) {
2912
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
2913
+ `);
2914
+ process.exit(1);
2915
+ }
2916
+ const msgs = res.data || [];
2917
+ if (opts.json) {
2918
+ process.stdout.write(JSON.stringify(msgs, null, 2) + "\n");
2919
+ return;
2920
+ }
2921
+ if (msgs.length === 0) {
2922
+ process.stdout.write("No messages.\n");
2923
+ return;
2924
+ }
2925
+ for (const m of msgs) {
2926
+ const ts = m.createdAt ? new Date(m.createdAt).toLocaleString() : "";
2927
+ process.stdout.write(`[${ts}] ${m.senderId || "?"}: ${m.content}
2928
+ `);
2929
+ }
2930
+ } catch (err) {
2931
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
2932
+ `);
2933
+ process.exit(1);
2934
+ }
2935
+ });
2936
+ im.command("me").description("Show current identity, agent card, credits, and stats").option("--json", "Output raw JSON response").action(async (opts) => {
2937
+ const client = getIMClient2();
2938
+ try {
2939
+ const res = await client.im.account.me();
2940
+ if (!res.ok) {
2941
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
2942
+ `);
2943
+ process.exit(1);
2944
+ }
2945
+ const d = res.data;
2946
+ if (opts.json) {
2947
+ process.stdout.write(JSON.stringify(d, null, 2) + "\n");
2948
+ return;
2949
+ }
2950
+ process.stdout.write(`Display Name: ${d?.user?.displayName || "-"}
2951
+ `);
2952
+ process.stdout.write(`Username: ${d?.user?.username || "-"}
2953
+ `);
2954
+ process.stdout.write(`Role: ${d?.user?.role || "-"}
2955
+ `);
2956
+ process.stdout.write(`Agent Type: ${d?.agentCard?.agentType || "-"}
2957
+ `);
2958
+ process.stdout.write(`Credits: ${d?.credits?.balance ?? "-"}
2959
+ `);
2960
+ process.stdout.write(`Messages: ${d?.stats?.messagesSent ?? "-"}
2961
+ `);
2962
+ process.stdout.write(`Unread: ${d?.stats?.unreadCount ?? "-"}
2963
+ `);
2964
+ } catch (err) {
2965
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
2966
+ `);
2967
+ process.exit(1);
2968
+ }
2969
+ });
2970
+ im.command("credits").description("Show credits balance").option("--json", "Output raw JSON response").action(async (opts) => {
2971
+ const client = getIMClient2();
2972
+ try {
2973
+ const res = await client.im.credits.get();
2974
+ if (!res.ok) {
2975
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
2976
+ `);
2977
+ process.exit(1);
2978
+ }
2979
+ if (opts.json) {
2980
+ process.stdout.write(JSON.stringify(res.data, null, 2) + "\n");
2981
+ return;
2982
+ }
2983
+ process.stdout.write(`Balance: ${res.data?.balance ?? "-"}
2984
+ `);
2985
+ } catch (err) {
2986
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
2987
+ `);
2988
+ process.exit(1);
2989
+ }
2990
+ });
2991
+ im.command("transactions").description("Show credit transaction history").option("-n, --limit <n>", "Max number of transactions to fetch", "20").option("--json", "Output raw JSON response").action(async (opts) => {
2992
+ const client = getIMClient2();
2993
+ try {
2994
+ const res = await client.im.credits.transactions({ limit: parseInt(opts.limit, 10) });
2995
+ if (!res.ok) {
2996
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
2997
+ `);
2998
+ process.exit(1);
2999
+ }
3000
+ const txns = res.data || [];
3001
+ if (opts.json) {
3002
+ process.stdout.write(JSON.stringify(txns, null, 2) + "\n");
3003
+ return;
3004
+ }
3005
+ if (txns.length === 0) {
3006
+ process.stdout.write("No transactions.\n");
3007
+ return;
3008
+ }
3009
+ process.stdout.write(
3010
+ "Date".padEnd(24) + "Type".padEnd(20) + "Amount".padEnd(12) + "Description\n"
3011
+ );
3012
+ for (const t of txns) {
3013
+ const date = t.createdAt ? new Date(t.createdAt).toLocaleString() : "";
3014
+ process.stdout.write(
3015
+ `${date.padEnd(24)}${(t.type || "").padEnd(20)}${String(t.amount ?? "").padEnd(12)}${t.description || ""}
3016
+ `
3017
+ );
3018
+ }
3019
+ } catch (err) {
3020
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
3021
+ `);
3022
+ process.exit(1);
3023
+ }
3024
+ });
3025
+ im.command("heartbeat").description("Send agent heartbeat (online/busy/offline) with optional load").option("--status <status>", "Presence status: online, busy, or offline", "online").option("--load <n>", "Current load factor (0.0 to 1.0)").option("--json", "Output raw JSON response").action(async (opts) => {
3026
+ const client = getIMClient2();
3027
+ try {
3028
+ const body = { status: opts.status };
3029
+ if (opts.load !== void 0) {
3030
+ const load = parseFloat(opts.load);
3031
+ if (!isNaN(load)) body.load = load;
3032
+ }
3033
+ const res = await client.im.account._r("POST", "/api/im/agents/heartbeat", body);
3034
+ if (!res.ok) {
3035
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
3036
+ `);
3037
+ process.exit(1);
3038
+ }
3039
+ if (opts.json) {
3040
+ process.stdout.write(JSON.stringify(res.data, null, 2) + "\n");
3041
+ return;
3042
+ }
3043
+ process.stdout.write(`Heartbeat sent (status: ${opts.status}${opts.load !== void 0 ? `, load: ${opts.load}` : ""}).
3044
+ `);
3045
+ } catch (err) {
3046
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
3047
+ `);
3048
+ process.exit(1);
3049
+ }
3050
+ });
3051
+ im.command("health").description("Check IM service health").action(async () => {
3052
+ const client = getIMClient2();
3053
+ try {
3054
+ const res = await client.im.health();
3055
+ if (!res.ok) {
3056
+ process.stderr.write(`IM Service: ERROR
3057
+ `);
3058
+ process.stderr.write(`${JSON.stringify(res.error)}
3059
+ `);
3060
+ process.exit(1);
3061
+ }
3062
+ process.stdout.write("IM Service: OK\n");
3063
+ } catch (err) {
3064
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
3065
+ `);
3066
+ process.exit(1);
3067
+ }
3068
+ });
3069
+ }
3070
+
3071
+ // src/commands/context.ts
3072
+ function register2(parent, _getIMClient, getAPIClient2) {
3073
+ const ctx = parent.command("context").description("Context loading, searching, and caching");
3074
+ ctx.command("load <urls...>").description("Load one or more URLs into context").option("-f, --format <fmt>", "output format: hqcc, raw, or both", "hqcc").option("--json", "output raw JSON response").action(async (urls, opts) => {
3075
+ const client = getAPIClient2();
3076
+ try {
3077
+ const input = urls.length === 1 ? urls[0] : urls;
3078
+ const format = opts.format;
3079
+ const res = await client.load(input, {
3080
+ return: { format }
3081
+ });
3082
+ if (opts.json) {
3083
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3084
+ return;
3085
+ }
3086
+ if (!res.success) {
3087
+ process.stderr.write(`Error: ${res.error?.message || "Unknown error"}
3088
+ `);
3089
+ process.exit(1);
3090
+ }
3091
+ const results = res.results ?? (res.result ? [res.result] : []);
3092
+ if (results.length === 0) {
3093
+ process.stdout.write("No results returned.\n");
3094
+ return;
3095
+ }
3096
+ for (const item of results) {
3097
+ process.stdout.write(`
3098
+ --- ${item.url ?? item.input ?? "result"} ---
3099
+ `);
3100
+ const hqcc = item.hqcc ?? item.content ?? "";
3101
+ if (hqcc) {
3102
+ const truncated = hqcc.length > 2e3 ? hqcc.slice(0, 2e3) + "... [truncated]" : hqcc;
3103
+ process.stdout.write(truncated + "\n");
3104
+ }
3105
+ if (item.cached !== void 0) {
3106
+ process.stdout.write(`[cached: ${item.cached}]
3107
+ `);
3108
+ }
3109
+ }
3110
+ } catch (err) {
3111
+ const message = err instanceof Error ? err.message : String(err);
3112
+ process.stderr.write(`Error: ${message}
3113
+ `);
3114
+ process.exit(1);
3115
+ }
3116
+ });
3117
+ ctx.command("search <query>").description("Search for content using a natural language query").option("-k, --top-k <n>", "number of results to return", "5").option("--json", "output raw JSON response").action(async (query, opts) => {
3118
+ const client = getAPIClient2();
3119
+ try {
3120
+ const topK = parseInt(opts.topK, 10);
3121
+ const res = await client.search(query, { topK });
3122
+ if (opts.json) {
3123
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3124
+ return;
3125
+ }
3126
+ if (!res.success) {
3127
+ process.stderr.write(`Error: ${res.error?.message || "Unknown error"}
3128
+ `);
3129
+ process.exit(1);
3130
+ }
3131
+ const results = res.results ?? (res.result ? [res.result] : []);
3132
+ if (results.length === 0) {
3133
+ process.stdout.write("No results found.\n");
3134
+ return;
3135
+ }
3136
+ process.stdout.write(`Search results for: "${query}"
3137
+
3138
+ `);
3139
+ results.forEach((item, i) => {
3140
+ process.stdout.write(`[${i + 1}] ${item.url ?? item.input ?? "result"}
3141
+ `);
3142
+ const hqcc = item.hqcc ?? item.content ?? "";
3143
+ if (hqcc) {
3144
+ const truncated = hqcc.length > 2e3 ? hqcc.slice(0, 2e3) + "... [truncated]" : hqcc;
3145
+ process.stdout.write(truncated + "\n");
3146
+ }
3147
+ process.stdout.write("\n");
3148
+ });
3149
+ } catch (err) {
3150
+ const message = err instanceof Error ? err.message : String(err);
3151
+ process.stderr.write(`Error: ${message}
3152
+ `);
3153
+ process.exit(1);
3154
+ }
3155
+ });
3156
+ ctx.command("save <url> <hqcc>").description("Save a URL and its HQCC content to the context cache").option("--json", "output raw JSON response").action(async (url, hqcc, opts) => {
3157
+ const client = getAPIClient2();
3158
+ try {
3159
+ const res = await client.save({ url, hqcc });
3160
+ if (opts.json) {
3161
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3162
+ return;
3163
+ }
3164
+ if (!res.success) {
3165
+ process.stderr.write(`Error: ${res.error?.message || "Unknown error"}
3166
+ `);
3167
+ process.exit(1);
3168
+ }
3169
+ process.stdout.write(`Saved: ${url}
3170
+ `);
3171
+ } catch (err) {
3172
+ const message = err instanceof Error ? err.message : String(err);
3173
+ process.stderr.write(`Error: ${message}
3174
+ `);
3175
+ process.exit(1);
3176
+ }
3177
+ });
3178
+ }
3179
+
3180
+ // src/commands/evolve.ts
3181
+ function parseSignals(raw) {
3182
+ if (!raw) return void 0;
3183
+ const trimmed = raw.trim();
3184
+ if (trimmed.startsWith("[")) {
3185
+ try {
3186
+ const parsed = JSON.parse(trimmed);
3187
+ if (Array.isArray(parsed)) return parsed.map(String);
3188
+ } catch {
3189
+ }
3190
+ }
3191
+ return trimmed.split(",").map((s) => s.trim()).filter(Boolean);
3192
+ }
3193
+ function handleError(err) {
3194
+ const message = err instanceof Error ? err.message : String(err);
3195
+ process.stderr.write(`Error: ${message}
3196
+ `);
3197
+ process.exit(1);
3198
+ }
3199
+ function printResult(res, label) {
3200
+ if (!res.ok) {
3201
+ const errMsg = res.error && typeof res.error === "object" && "message" in res.error ? res.error.message : JSON.stringify(res.error);
3202
+ process.stderr.write(`Error: ${errMsg || "Unknown error"}
3203
+ `);
3204
+ process.exit(1);
3205
+ }
3206
+ if (label) {
3207
+ process.stdout.write(`${label}
3208
+ `);
3209
+ }
3210
+ }
3211
+ function register3(parent, getIMClient2, _getAPIClient) {
3212
+ const evolve = parent.command("evolve").description("Evolution engine \u2014 analyze signals, manage genes, track learning");
3213
+ evolve.command("analyze").description("Analyze signals to find matching evolution strategies").option("-e, --error <msg>", "error message to analyze").option("-s, --signals <signals>", "signals as JSON array or comma-separated list").option("--task-status <status>", "task status (e.g. failed, timeout)").option("--provider <name>", "provider name (e.g. openai, exa)").option("--stage <stage>", "pipeline stage").option("--severity <level>", "severity level (low, medium, high, critical)").option("--tags <tags>", "comma-separated tags").option("--scope <scope>", "evolution scope (default: global)").option("--json", "output raw JSON response").action(async (opts) => {
3214
+ const client = getIMClient2();
3215
+ try {
3216
+ const signals = parseSignals(opts.signals);
3217
+ const tags = opts.tags ? opts.tags.split(",").map((t) => t.trim()).filter(Boolean) : void 0;
3218
+ const res = await client.im.evolution.analyze({
3219
+ signals,
3220
+ error: opts.error,
3221
+ task_status: opts.taskStatus,
3222
+ provider: opts.provider,
3223
+ stage: opts.stage,
3224
+ severity: opts.severity,
3225
+ tags,
3226
+ scope: opts.scope
3227
+ });
3228
+ if (opts.json) {
3229
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3230
+ return;
3231
+ }
3232
+ printResult(res);
3233
+ const data = res.data;
3234
+ if (data) {
3235
+ const matches = data.matches;
3236
+ const count = matches?.length ?? 0;
3237
+ process.stdout.write(`Matched ${count} gene(s)
3238
+ `);
3239
+ if (matches && count > 0) {
3240
+ for (const m of matches) {
3241
+ const id = m.gene_id ?? m.id ?? "?";
3242
+ const title = m.title ?? m.name ?? "";
3243
+ const score = m.score !== void 0 ? ` (score: ${m.score})` : "";
3244
+ process.stdout.write(` \u2022 ${id}${title ? ` \u2014 ${title}` : ""}${score}
3245
+ `);
3246
+ }
3247
+ }
3248
+ }
3249
+ } catch (err) {
3250
+ handleError(err);
3251
+ }
3252
+ });
3253
+ evolve.command("record").description("Record an outcome against an evolution gene").requiredOption("-g, --gene <id>", "gene ID to record against").requiredOption("-o, --outcome <outcome>", "outcome: success, failure, partial").option("-s, --signals <signals>", "signals as JSON array or comma-separated list").option("--score <n>", "outcome score (0-1)").option("--summary <text>", "brief summary of the outcome").option("--scope <scope>", "evolution scope (default: global)").option("--json", "output raw JSON response").action(async (opts) => {
3254
+ const client = getIMClient2();
3255
+ try {
3256
+ const signals = parseSignals(opts.signals);
3257
+ const score = opts.score !== void 0 ? parseFloat(opts.score) : void 0;
3258
+ const res = await client.im.evolution.record({
3259
+ gene_id: opts.gene,
3260
+ signals,
3261
+ outcome: opts.outcome,
3262
+ score,
3263
+ summary: opts.summary,
3264
+ scope: opts.scope
3265
+ });
3266
+ if (opts.json) {
3267
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3268
+ return;
3269
+ }
3270
+ printResult(res, `Recorded outcome "${opts.outcome}" for gene ${opts.gene}`);
3271
+ } catch (err) {
3272
+ handleError(err);
3273
+ }
3274
+ });
3275
+ evolve.command("report").description("Submit a full evolution report (error + status context)").requiredOption("-e, --error <msg>", "raw error message or context").requiredOption("--status <outcome>", "final task outcome (success, failure, partial)").option("--task <context>", "task context description").option("--wait", "poll for report completion (max 60s)").option("--json", "output raw JSON response").action(async (opts) => {
3276
+ const client = getIMClient2();
3277
+ try {
3278
+ const res = await client.im.evolution.submitReport({
3279
+ rawContext: opts.error,
3280
+ outcome: opts.status,
3281
+ taskContext: opts.task
3282
+ });
3283
+ if (opts.json && !opts.wait) {
3284
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3285
+ return;
3286
+ }
3287
+ if (!res.ok) {
3288
+ const errMsg = res.error && typeof res.error === "object" && "message" in res.error ? res.error.message : JSON.stringify(res.error);
3289
+ process.stderr.write(`Error: ${errMsg || "Unknown error"}
3290
+ `);
3291
+ process.exit(1);
3292
+ }
3293
+ const submitData = res.data;
3294
+ const traceId = submitData?.trace_id;
3295
+ if (!opts.wait || !traceId) {
3296
+ if (opts.json) {
3297
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3298
+ } else {
3299
+ process.stdout.write(`Report submitted. trace_id: ${traceId ?? "unknown"}
3300
+ `);
3301
+ if (submitData?.fast_signals) {
3302
+ process.stdout.write(`Fast signals: ${JSON.stringify(submitData.fast_signals)}
3303
+ `);
3304
+ }
3305
+ }
3306
+ return;
3307
+ }
3308
+ if (!opts.json) {
3309
+ process.stdout.write(`Waiting for report ${traceId} `);
3310
+ }
3311
+ const maxIterations = 30;
3312
+ let lastStatus;
3313
+ for (let i = 0; i < maxIterations; i++) {
3314
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
3315
+ if (!opts.json) process.stdout.write(".");
3316
+ const statusRes = await client.im.evolution.getReportStatus(traceId);
3317
+ if (!statusRes.ok) break;
3318
+ const statusData = statusRes.data;
3319
+ lastStatus = statusData;
3320
+ if (statusData?.status === "done" || statusData?.status === "complete" || statusData?.status === "completed") {
3321
+ if (!opts.json) {
3322
+ process.stdout.write("\n");
3323
+ process.stdout.write(`Status: ${statusData.status}
3324
+ `);
3325
+ if (statusData.root_cause) process.stdout.write(`Root cause: ${statusData.root_cause}
3326
+ `);
3327
+ if (statusData.extracted_signals) process.stdout.write(`Extracted signals: ${JSON.stringify(statusData.extracted_signals)}
3328
+ `);
3329
+ } else {
3330
+ process.stdout.write(JSON.stringify({ trace_id: traceId, ...statusData }, null, 2) + "\n");
3331
+ }
3332
+ return;
3333
+ }
3334
+ }
3335
+ if (!opts.json) {
3336
+ process.stdout.write("\n");
3337
+ process.stdout.write(`Timed out waiting for report. Last status: ${JSON.stringify(lastStatus)}
3338
+ `);
3339
+ } else {
3340
+ process.stdout.write(JSON.stringify({ trace_id: traceId, status: "timeout", last: lastStatus }, null, 2) + "\n");
3341
+ }
3342
+ process.exit(1);
3343
+ } catch (err) {
3344
+ handleError(err);
3345
+ }
3346
+ });
3347
+ evolve.command("report-status <trace-id>").description("Check the status of a submitted evolution report").option("--json", "output raw JSON response").action(async (traceId, opts) => {
3348
+ const client = getIMClient2();
3349
+ try {
3350
+ const res = await client.im.evolution.getReportStatus(traceId);
3351
+ if (opts.json) {
3352
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3353
+ return;
3354
+ }
3355
+ printResult(res);
3356
+ const data = res.data;
3357
+ process.stdout.write(`trace_id: ${traceId}
3358
+ `);
3359
+ process.stdout.write(`status: ${data?.status ?? "unknown"}
3360
+ `);
3361
+ if (data?.root_cause) process.stdout.write(`root_cause: ${data.root_cause}
3362
+ `);
3363
+ if (data?.extracted_signals) process.stdout.write(`extracted_signals: ${JSON.stringify(data.extracted_signals)}
3364
+ `);
3365
+ } catch (err) {
3366
+ handleError(err);
3367
+ }
3368
+ });
3369
+ evolve.command("create").description("Create a new evolution gene").requiredOption("-c, --category <cat>", "gene category").requiredOption("-s, --signals <signals>", "trigger signals as JSON array or comma-separated list").requiredOption("--strategy <steps...>", "strategy steps (variadic)").option("-n, --name <title>", "gene title / display name").option("--scope <scope>", "evolution scope (default: global)").option("--json", "output raw JSON response").action(async (opts) => {
3370
+ const client = getIMClient2();
3371
+ try {
3372
+ const signals_match = parseSignals(opts.signals) ?? [];
3373
+ const res = await client.im.evolution.createGene({
3374
+ category: opts.category,
3375
+ signals_match,
3376
+ strategy: opts.strategy,
3377
+ title: opts.name,
3378
+ scope: opts.scope
3379
+ });
3380
+ if (opts.json) {
3381
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3382
+ return;
3383
+ }
3384
+ printResult(res);
3385
+ const data = res.data;
3386
+ const id = data?.gene_id ?? data?.id ?? "unknown";
3387
+ process.stdout.write(`Gene created: ${id}
3388
+ `);
3389
+ if (opts.name) process.stdout.write(`Title: ${opts.name}
3390
+ `);
3391
+ process.stdout.write(`Category: ${opts.category}
3392
+ `);
3393
+ } catch (err) {
3394
+ handleError(err);
3395
+ }
3396
+ });
3397
+ evolve.command("genes").description("List your own evolution genes").option("--scope <scope>", "filter by evolution scope").option("--json", "output raw JSON response").action(async (opts) => {
3398
+ const client = getIMClient2();
3399
+ try {
3400
+ const res = await client.im.evolution.listGenes(void 0, opts.scope);
3401
+ if (opts.json) {
3402
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3403
+ return;
3404
+ }
3405
+ printResult(res);
3406
+ const data = res.data;
3407
+ const genes = Array.isArray(data) ? data : data?.genes ?? data?.items ?? [];
3408
+ if (genes.length === 0) {
3409
+ process.stdout.write("No genes found.\n");
3410
+ return;
3411
+ }
3412
+ process.stdout.write(`${genes.length} gene(s):
3413
+ `);
3414
+ for (const g of genes) {
3415
+ const id = g.gene_id ?? g.id ?? "?";
3416
+ const title = g.title ?? g.name ?? "";
3417
+ const category = g.category ? ` [${g.category}]` : "";
3418
+ const scope = g.scope ? ` (${g.scope})` : "";
3419
+ process.stdout.write(` \u2022 ${id}${title ? ` \u2014 ${title}` : ""}${category}${scope}
3420
+ `);
3421
+ }
3422
+ } catch (err) {
3423
+ handleError(err);
3424
+ }
3425
+ });
3426
+ evolve.command("stats").description("Show public evolution statistics").option("--json", "output raw JSON response").action(async (opts) => {
3427
+ const client = getIMClient2();
3428
+ try {
3429
+ const res = await client.im.evolution.getStats();
3430
+ if (opts.json) {
3431
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3432
+ return;
3433
+ }
3434
+ printResult(res);
3435
+ const data = res.data;
3436
+ if (data) {
3437
+ for (const [key, val] of Object.entries(data)) {
3438
+ process.stdout.write(`${key}: ${JSON.stringify(val)}
3439
+ `);
3440
+ }
3441
+ }
3442
+ } catch (err) {
3443
+ handleError(err);
3444
+ }
3445
+ });
3446
+ evolve.command("metrics").description("Show A/B experiment metrics").option("--json", "output raw JSON response").action(async (opts) => {
3447
+ const client = getIMClient2();
3448
+ try {
3449
+ const res = await client.im.evolution.getMetrics();
3450
+ if (opts.json) {
3451
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3452
+ return;
3453
+ }
3454
+ printResult(res);
3455
+ const data = res.data;
3456
+ if (data) {
3457
+ for (const [key, val] of Object.entries(data)) {
3458
+ process.stdout.write(`${key}: ${JSON.stringify(val)}
3459
+ `);
3460
+ }
3461
+ }
3462
+ } catch (err) {
3463
+ handleError(err);
3464
+ }
3465
+ });
3466
+ evolve.command("achievements").description("Show your evolution achievements").option("--json", "output raw JSON response").action(async (opts) => {
3467
+ const client = getIMClient2();
3468
+ try {
3469
+ const res = await client.im.evolution.getAchievements();
3470
+ if (opts.json) {
3471
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3472
+ return;
3473
+ }
3474
+ printResult(res);
3475
+ const data = res.data;
3476
+ const achievements = Array.isArray(data) ? data : data?.achievements ?? data?.items ?? [];
3477
+ if (achievements.length === 0) {
3478
+ process.stdout.write("No achievements yet.\n");
3479
+ return;
3480
+ }
3481
+ process.stdout.write(`${achievements.length} achievement(s):
3482
+ `);
3483
+ for (const a of achievements) {
3484
+ const id = a.id ?? "?";
3485
+ const title = a.title ?? a.name ?? "";
3486
+ const desc = a.description ? ` \u2014 ${a.description}` : "";
3487
+ process.stdout.write(` \u2022 ${id}${title ? ` ${title}` : ""}${desc}
3488
+ `);
3489
+ }
3490
+ } catch (err) {
3491
+ handleError(err);
3492
+ }
3493
+ });
3494
+ evolve.command("sync").description("Get a sync snapshot of recent evolution data").option("--json", "output raw JSON response").action(async (opts) => {
3495
+ const client = getIMClient2();
3496
+ try {
3497
+ const res = await client.im.evolution.getSyncSnapshot();
3498
+ if (opts.json) {
3499
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3500
+ return;
3501
+ }
3502
+ printResult(res);
3503
+ const data = res.data;
3504
+ if (data) {
3505
+ const since = data.since ?? data.timestamp ?? data.generated_at;
3506
+ if (since) process.stdout.write(`Snapshot since: ${since}
3507
+ `);
3508
+ const genes = data.genes;
3509
+ const signals = data.signals;
3510
+ if (genes !== void 0) process.stdout.write(`Genes: ${genes.length}
3511
+ `);
3512
+ if (signals !== void 0) process.stdout.write(`Signals: ${signals.length}
3513
+ `);
3514
+ }
3515
+ } catch (err) {
3516
+ handleError(err);
3517
+ }
3518
+ });
3519
+ evolve.command("export-skill <gene-id>").description("Export a gene as a reusable skill").option("--slug <slug>", "skill slug identifier").option("--name <displayName>", "skill display name").option("--json", "output raw JSON response").action(async (geneId, opts) => {
3520
+ const client = getIMClient2();
3521
+ try {
3522
+ const res = await client.im.evolution.exportAsSkill(geneId, {
3523
+ slug: opts.slug,
3524
+ displayName: opts.name
3525
+ });
3526
+ if (opts.json) {
3527
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3528
+ return;
3529
+ }
3530
+ printResult(res);
3531
+ const data = res.data;
3532
+ process.stdout.write(`Skill exported from gene: ${geneId}
3533
+ `);
3534
+ if (data?.skill_id) process.stdout.write(`skill_id: ${data.skill_id}
3535
+ `);
3536
+ if (data?.slug) process.stdout.write(`slug: ${data.slug}
3537
+ `);
3538
+ if (data?.display_name) process.stdout.write(`display_name: ${data.display_name}
3539
+ `);
3540
+ } catch (err) {
3541
+ handleError(err);
3542
+ }
3543
+ });
3544
+ evolve.command("scopes").description("List available evolution scopes").option("--json", "output raw JSON response").action(async (opts) => {
3545
+ const client = getIMClient2();
3546
+ try {
3547
+ const res = await client.im.evolution.listScopes();
3548
+ if (opts.json) {
3549
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3550
+ return;
3551
+ }
3552
+ printResult(res);
3553
+ const data = res.data;
3554
+ const scopes = Array.isArray(data) ? data : data?.scopes ?? data?.items ?? [];
3555
+ if (scopes.length === 0) {
3556
+ process.stdout.write("No scopes found.\n");
3557
+ return;
3558
+ }
3559
+ process.stdout.write(`${scopes.length} scope(s):
3560
+ `);
3561
+ for (const s of scopes) {
3562
+ if (typeof s === "string") {
3563
+ process.stdout.write(` \u2022 ${s}
3564
+ `);
3565
+ } else {
3566
+ const name = s.name ?? s.scope ?? s.id ?? JSON.stringify(s);
3567
+ process.stdout.write(` \u2022 ${name}
3568
+ `);
3569
+ }
3570
+ }
3571
+ } catch (err) {
3572
+ handleError(err);
3573
+ }
3574
+ });
3575
+ evolve.command("browse").description("Browse published evolution genes").option("-c, --category <cat>", "filter by category").option("--search <query>", "full-text search query").option("--sort <field>", "sort field (e.g. score, created_at)").option("-n, --limit <n>", "max results to return", "20").option("--json", "output raw JSON response").action(async (opts) => {
3576
+ const client = getIMClient2();
3577
+ try {
3578
+ const limit = parseInt(opts.limit ?? "20", 10);
3579
+ const res = await client.im.evolution.browseGenes({
3580
+ category: opts.category,
3581
+ search: opts.search,
3582
+ sort: opts.sort,
3583
+ limit
3584
+ });
3585
+ if (opts.json) {
3586
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3587
+ return;
3588
+ }
3589
+ printResult(res);
3590
+ const data = res.data;
3591
+ const genes = Array.isArray(data) ? data : data?.genes ?? data?.items ?? data?.results ?? [];
3592
+ if (genes.length === 0) {
3593
+ process.stdout.write("No genes found.\n");
3594
+ return;
3595
+ }
3596
+ process.stdout.write(`${genes.length} gene(s):
3597
+ `);
3598
+ for (const g of genes) {
3599
+ const id = g.gene_id ?? g.id ?? "?";
3600
+ const title = g.title ?? g.name ?? "";
3601
+ const category = g.category ? ` [${g.category}]` : "";
3602
+ const score = g.score !== void 0 ? ` score=${g.score}` : "";
3603
+ process.stdout.write(` \u2022 ${id}${title ? ` \u2014 ${title}` : ""}${category}${score}
3604
+ `);
3605
+ }
3606
+ } catch (err) {
3607
+ handleError(err);
3608
+ }
3609
+ });
3610
+ evolve.command("publish <gene-id>").description("Publish a private gene to the evolution network").option("--skip-canary", "skip canary phase and publish directly").option("--json", "output raw JSON response").action(async (geneId, opts) => {
3611
+ const client = getIMClient2();
3612
+ try {
3613
+ const res = await client.im.evolution.publishGene(geneId, { skipCanary: opts.skipCanary });
3614
+ if (opts.json) {
3615
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3616
+ return;
3617
+ }
3618
+ printResult(res, `Gene ${geneId} published${opts.skipCanary ? " (skipped canary)" : " (canary phase)"}`);
3619
+ } catch (err) {
3620
+ handleError(err);
3621
+ }
3622
+ });
3623
+ evolve.command("fork <gene-id>").description("Fork a public gene with optional modifications").option("--strategy <steps...>", "override strategy steps").option("--json", "output raw JSON response").action(async (geneId, opts) => {
3624
+ const client = getIMClient2();
3625
+ try {
3626
+ const res = await client.im.evolution.forkGene({
3627
+ gene_id: geneId,
3628
+ modifications: opts.strategy ? { strategy: opts.strategy } : void 0
3629
+ });
3630
+ if (opts.json) {
3631
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3632
+ return;
3633
+ }
3634
+ printResult(res);
3635
+ const data = res.data;
3636
+ const newId = data?.id ?? data?.gene_id ?? "unknown";
3637
+ process.stdout.write(`Forked gene ${geneId} \u2192 ${newId}
3638
+ `);
3639
+ } catch (err) {
3640
+ handleError(err);
3641
+ }
3642
+ });
3643
+ evolve.command("delete <gene-id>").description("Delete a gene you own").option("--json", "output raw JSON response").action(async (geneId, opts) => {
3644
+ const client = getIMClient2();
3645
+ try {
3646
+ const res = await client.im.evolution.deleteGene(geneId);
3647
+ if (opts.json) {
3648
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3649
+ return;
3650
+ }
3651
+ printResult(res, `Gene ${geneId} deleted`);
3652
+ } catch (err) {
3653
+ handleError(err);
3654
+ }
3655
+ });
3656
+ evolve.command("import <gene-id>").description("Import a published gene into your collection").option("--json", "output raw JSON response").action(async (geneId, opts) => {
3657
+ const client = getIMClient2();
3658
+ try {
3659
+ const res = await client.im.evolution.importGene(geneId);
3660
+ if (opts.json) {
3661
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3662
+ return;
3663
+ }
3664
+ printResult(res, `Gene imported: ${geneId}`);
3665
+ } catch (err) {
3666
+ handleError(err);
3667
+ }
3668
+ });
3669
+ evolve.command("distill").description("Trigger gene distillation (consolidate learnings)").option("--dry-run", "preview distillation without applying changes").option("--json", "output raw JSON response").action(async (opts) => {
3670
+ const client = getIMClient2();
3671
+ try {
3672
+ const res = await client.im.evolution.distill(opts.dryRun);
3673
+ if (opts.json) {
3674
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3675
+ return;
3676
+ }
3677
+ printResult(res);
3678
+ const data = res.data;
3679
+ if (opts.dryRun) {
3680
+ process.stdout.write("Dry-run distillation preview:\n");
3681
+ } else {
3682
+ process.stdout.write("Distillation triggered.\n");
3683
+ }
3684
+ if (data) {
3685
+ for (const [key, val] of Object.entries(data)) {
3686
+ process.stdout.write(` ${key}: ${JSON.stringify(val)}
3687
+ `);
3688
+ }
3689
+ }
3690
+ } catch (err) {
3691
+ handleError(err);
3692
+ }
3693
+ });
3694
+ }
3695
+
3696
+ // src/commands/task.ts
3697
+ function register4(parent, getIMClient2, _getAPIClient) {
3698
+ const task = parent.command("task").description("Manage tasks in the task marketplace");
3699
+ task.command("create").description("Create a new task").requiredOption("--title <title>", "task title").option("--description <description>", "task description").option("--priority <priority>", "priority: low, normal, high, urgent").option("--capability <capability>", "required agent capability").option("--budget <budget>", "budget in credits", parseFloat).option("--json", "output raw JSON response").action(async (opts) => {
3700
+ const client = getIMClient2();
3701
+ try {
3702
+ const res = await client.im.tasks.create({
3703
+ title: opts.title,
3704
+ description: opts.description,
3705
+ priority: opts.priority,
3706
+ requiredCapability: opts.capability,
3707
+ budget: opts.budget
3708
+ });
3709
+ if (opts.json) {
3710
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3711
+ return;
3712
+ }
3713
+ if (!res.ok) {
3714
+ process.stderr.write(`Error: ${res.error?.message || "Unknown error"}
3715
+ `);
3716
+ process.exit(1);
3717
+ }
3718
+ const t = res.data;
3719
+ process.stdout.write(`Task created successfully
3720
+
3721
+ `);
3722
+ process.stdout.write(`ID: ${t.id}
3723
+ `);
3724
+ process.stdout.write(`Title: ${t.title}
3725
+ `);
3726
+ process.stdout.write(`Status: ${t.status}
3727
+ `);
3728
+ process.stdout.write(`Priority: ${t.priority}
3729
+ `);
3730
+ if (t.description) process.stdout.write(`Description: ${t.description}
3731
+ `);
3732
+ if (t.requiredCapability) process.stdout.write(`Capability: ${t.requiredCapability}
3733
+ `);
3734
+ if (t.budget !== void 0) process.stdout.write(`Budget: ${t.budget}
3735
+ `);
3736
+ } catch (err) {
3737
+ const message = err instanceof Error ? err.message : String(err);
3738
+ process.stderr.write(`Error: ${message}
3739
+ `);
3740
+ process.exit(1);
3741
+ }
3742
+ });
3743
+ task.command("list").description("List tasks").option("--status <status>", "filter by status").option("--capability <capability>", "filter by required capability").option("-n, --limit <n>", "maximum number of tasks to return", "20").option("--json", "output raw JSON response").action(async (opts) => {
3744
+ const client = getIMClient2();
3745
+ try {
3746
+ const res = await client.im.tasks.list({
3747
+ status: opts.status,
3748
+ capability: opts.capability,
3749
+ limit: parseInt(opts.limit, 10)
3750
+ });
3751
+ if (opts.json) {
3752
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3753
+ return;
3754
+ }
3755
+ if (!res.ok) {
3756
+ process.stderr.write(`Error: ${res.error?.message || "Unknown error"}
3757
+ `);
3758
+ process.exit(1);
3759
+ }
3760
+ const tasks = res.data;
3761
+ if (!tasks || tasks.length === 0) {
3762
+ process.stdout.write("No tasks found.\n");
3763
+ return;
3764
+ }
3765
+ const idW = 24;
3766
+ const statusW = 10;
3767
+ const priorityW = 10;
3768
+ const titleW = 40;
3769
+ const header = "ID".padEnd(idW) + "STATUS".padEnd(statusW) + "PRIORITY".padEnd(priorityW) + "TITLE";
3770
+ const sep = "-".repeat(idW + statusW + priorityW + titleW);
3771
+ process.stdout.write(header + "\n");
3772
+ process.stdout.write(sep + "\n");
3773
+ for (const t of tasks) {
3774
+ const title = t.title.length > titleW ? t.title.slice(0, titleW - 3) + "..." : t.title;
3775
+ process.stdout.write(
3776
+ String(t.id).padEnd(idW) + String(t.status).padEnd(statusW) + String(t.priority).padEnd(priorityW) + title + "\n"
3777
+ );
3778
+ }
3779
+ process.stdout.write(`
3780
+ ${tasks.length} task(s) listed.
3781
+ `);
3782
+ } catch (err) {
3783
+ const message = err instanceof Error ? err.message : String(err);
3784
+ process.stderr.write(`Error: ${message}
3785
+ `);
3786
+ process.exit(1);
3787
+ }
3788
+ });
3789
+ task.command("get <task-id>").description("Get task details and logs").option("--json", "output raw JSON response").action(async (taskId, opts) => {
3790
+ const client = getIMClient2();
3791
+ try {
3792
+ const res = await client.im.tasks.get(taskId);
3793
+ if (opts.json) {
3794
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3795
+ return;
3796
+ }
3797
+ if (!res.ok) {
3798
+ process.stderr.write(`Error: ${res.error?.message || "Unknown error"}
3799
+ `);
3800
+ process.exit(1);
3801
+ }
3802
+ const t = res.data;
3803
+ process.stdout.write(`ID: ${t.id}
3804
+ `);
3805
+ process.stdout.write(`Title: ${t.title}
3806
+ `);
3807
+ process.stdout.write(`Status: ${t.status}
3808
+ `);
3809
+ process.stdout.write(`Priority: ${t.priority}
3810
+ `);
3811
+ if (t.description) process.stdout.write(`Description: ${t.description}
3812
+ `);
3813
+ if (t.requiredCapability) process.stdout.write(`Capability: ${t.requiredCapability}
3814
+ `);
3815
+ if (t.budget !== void 0) process.stdout.write(`Budget: ${t.budget}
3816
+ `);
3817
+ if (t.creatorId) process.stdout.write(`Creator: ${t.creatorId}
3818
+ `);
3819
+ if (t.assigneeId) process.stdout.write(`Assignee: ${t.assigneeId}
3820
+ `);
3821
+ if (t.createdAt) process.stdout.write(`Created: ${t.createdAt}
3822
+ `);
3823
+ if (t.updatedAt) process.stdout.write(`Updated: ${t.updatedAt}
3824
+ `);
3825
+ if (t.result) process.stdout.write(`Result: ${t.result}
3826
+ `);
3827
+ if (t.error) process.stdout.write(`Error: ${t.error}
3828
+ `);
3829
+ const logs = t.logs ?? t.taskLogs ?? [];
3830
+ if (logs.length > 0) {
3831
+ process.stdout.write(`
3832
+ Logs (${logs.length}):
3833
+ `);
3834
+ for (const log of logs) {
3835
+ const ts = log.createdAt ?? log.timestamp ?? "";
3836
+ const msg = log.message ?? log.content ?? JSON.stringify(log);
3837
+ process.stdout.write(` [${ts}] ${msg}
3838
+ `);
3839
+ }
3840
+ }
3841
+ } catch (err) {
3842
+ const message = err instanceof Error ? err.message : String(err);
3843
+ process.stderr.write(`Error: ${message}
3844
+ `);
3845
+ process.exit(1);
3846
+ }
3847
+ });
3848
+ task.command("claim <task-id>").description("Claim a pending task").option("--json", "output raw JSON response").action(async (taskId, opts) => {
3849
+ const client = getIMClient2();
3850
+ try {
3851
+ const res = await client.im.tasks.claim(taskId);
3852
+ if (opts.json) {
3853
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3854
+ return;
3855
+ }
3856
+ if (!res.ok) {
3857
+ process.stderr.write(`Error: ${res.error?.message || "Unknown error"}
3858
+ `);
3859
+ process.exit(1);
3860
+ }
3861
+ const t = res.data;
3862
+ process.stdout.write(`Task claimed successfully
3863
+
3864
+ `);
3865
+ process.stdout.write(`ID: ${t.id}
3866
+ `);
3867
+ process.stdout.write(`Title: ${t.title}
3868
+ `);
3869
+ process.stdout.write(`Status: ${t.status}
3870
+ `);
3871
+ process.stdout.write(`Priority: ${t.priority}
3872
+ `);
3873
+ } catch (err) {
3874
+ const message = err instanceof Error ? err.message : String(err);
3875
+ process.stderr.write(`Error: ${message}
3876
+ `);
3877
+ process.exit(1);
3878
+ }
3879
+ });
3880
+ task.command("update <task-id>").description("Update a task").option("--title <title>", "new title").option("--description <description>", "new description").option("--priority <priority>", "new priority: low, normal, high, urgent").option("--json", "output raw JSON response").action(async (taskId, opts) => {
3881
+ const client = getIMClient2();
3882
+ try {
3883
+ const res = await client.im.tasks.update(taskId, {
3884
+ title: opts.title,
3885
+ description: opts.description,
3886
+ priority: opts.priority
3887
+ });
3888
+ if (opts.json) {
3889
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3890
+ return;
3891
+ }
3892
+ if (!res.ok) {
3893
+ process.stderr.write(`Error: ${res.error?.message || "Unknown error"}
3894
+ `);
3895
+ process.exit(1);
3896
+ }
3897
+ const t = res.data;
3898
+ process.stdout.write(`Task updated successfully
3899
+
3900
+ `);
3901
+ process.stdout.write(`ID: ${t.id}
3902
+ `);
3903
+ process.stdout.write(`Title: ${t.title}
3904
+ `);
3905
+ process.stdout.write(`Status: ${t.status}
3906
+ `);
3907
+ process.stdout.write(`Priority: ${t.priority}
3908
+ `);
3909
+ } catch (err) {
3910
+ const message = err instanceof Error ? err.message : String(err);
3911
+ process.stderr.write(`Error: ${message}
3912
+ `);
3913
+ process.exit(1);
3914
+ }
3915
+ });
3916
+ task.command("complete <task-id>").description("Mark a task as complete").option("--result <result>", "result or output of the task").option("--json", "output raw JSON response").action(async (taskId, opts) => {
3917
+ const client = getIMClient2();
3918
+ try {
3919
+ const res = await client.im.tasks.complete(taskId, {
3920
+ result: opts.result
3921
+ });
3922
+ if (opts.json) {
3923
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3924
+ return;
3925
+ }
3926
+ if (!res.ok) {
3927
+ process.stderr.write(`Error: ${res.error?.message || "Unknown error"}
3928
+ `);
3929
+ process.exit(1);
3930
+ }
3931
+ const t = res.data;
3932
+ process.stdout.write(`Task completed successfully
3933
+
3934
+ `);
3935
+ process.stdout.write(`ID: ${t.id}
3936
+ `);
3937
+ process.stdout.write(`Title: ${t.title}
3938
+ `);
3939
+ process.stdout.write(`Status: ${t.status}
3940
+ `);
3941
+ if (t.result) process.stdout.write(`Result: ${t.result}
3942
+ `);
3943
+ } catch (err) {
3944
+ const message = err instanceof Error ? err.message : String(err);
3945
+ process.stderr.write(`Error: ${message}
3946
+ `);
3947
+ process.exit(1);
3948
+ }
3949
+ });
3950
+ task.command("fail <task-id>").description("Mark a task as failed").requiredOption("--error <error>", "error message describing why the task failed").option("--json", "output raw JSON response").action(async (taskId, opts) => {
3951
+ const client = getIMClient2();
3952
+ try {
3953
+ const res = await client.im.tasks.fail(taskId, opts.error);
3954
+ if (opts.json) {
3955
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3956
+ return;
3957
+ }
3958
+ if (!res.ok) {
3959
+ process.stderr.write(`Error: ${res.error?.message || "Unknown error"}
3960
+ `);
3961
+ process.exit(1);
3962
+ }
3963
+ const t = res.data;
3964
+ process.stdout.write(`Task marked as failed
3965
+
3966
+ `);
3967
+ process.stdout.write(`ID: ${t.id}
3968
+ `);
3969
+ process.stdout.write(`Title: ${t.title}
3970
+ `);
3971
+ process.stdout.write(`Status: ${t.status}
3972
+ `);
3973
+ if (t.error) process.stdout.write(`Error: ${t.error}
3974
+ `);
3975
+ } catch (err) {
3976
+ const message = err instanceof Error ? err.message : String(err);
3977
+ process.stderr.write(`Error: ${message}
3978
+ `);
3979
+ process.exit(1);
3980
+ }
3981
+ });
3982
+ }
3983
+
3984
+ // src/commands/memory.ts
3985
+ function register5(parent, getIMClient2, _getAPIClient) {
3986
+ const mem = parent.command("memory").description("Agent memory file management");
3987
+ mem.command("write").description("Write a memory file").requiredOption("-s, --scope <scope>", "memory scope").requiredOption("-p, --path <path>", "file path within scope").requiredOption("-c, --content <content>", "file content").option("--json", "output raw JSON response").action(async (opts) => {
3988
+ const client = getIMClient2();
3989
+ try {
3990
+ const res = await client.im.memory.createFile({
3991
+ scope: opts.scope,
3992
+ path: opts.path,
3993
+ content: opts.content
3994
+ });
3995
+ if (opts.json) {
3996
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
3997
+ return;
3998
+ }
3999
+ if (!res.ok) {
4000
+ process.stderr.write(`Error: ${res.error?.message || "Unknown error"}
4001
+ `);
4002
+ process.exit(1);
4003
+ }
4004
+ const file = res.data;
4005
+ process.stdout.write(`Memory file created
4006
+ `);
4007
+ process.stdout.write(` ID: ${file.id}
4008
+ `);
4009
+ process.stdout.write(` Scope: ${file.scope}
4010
+ `);
4011
+ process.stdout.write(` Path: ${file.path}
4012
+ `);
4013
+ } catch (err) {
4014
+ const message = err instanceof Error ? err.message : String(err);
4015
+ process.stderr.write(`Error: ${message}
4016
+ `);
4017
+ process.exit(1);
4018
+ }
4019
+ });
4020
+ mem.command("read [file-id]").description("Read a memory file by ID, or filter by scope/path").option("-s, --scope <scope>", "filter by scope (used when no file-id given)").option("-p, --path <path>", "filter by path (used when no file-id given)").option("--json", "output raw JSON response").action(async (fileId, opts) => {
4021
+ const client = getIMClient2();
4022
+ try {
4023
+ if (fileId) {
4024
+ const res = await client.im.memory.getFile(fileId);
4025
+ if (opts.json) {
4026
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
4027
+ return;
4028
+ }
4029
+ if (!res.ok) {
4030
+ process.stderr.write(`Error: ${res.error?.message || "Unknown error"}
4031
+ `);
4032
+ process.exit(1);
4033
+ }
4034
+ const file = res.data;
4035
+ process.stdout.write(`ID: ${file.id}
4036
+ `);
4037
+ process.stdout.write(`Scope: ${file.scope}
4038
+ `);
4039
+ process.stdout.write(`Path: ${file.path}
4040
+ `);
4041
+ process.stdout.write(`
4042
+ ${file.content ?? ""}
4043
+ `);
4044
+ return;
4045
+ }
4046
+ const listRes = await client.im.memory.listFiles({
4047
+ scope: opts.scope,
4048
+ path: opts.path
4049
+ });
4050
+ if (opts.json) {
4051
+ if (listRes.ok && Array.isArray(listRes.data) && listRes.data.length === 1) {
4052
+ const detailRes = await client.im.memory.getFile(listRes.data[0].id);
4053
+ process.stdout.write(JSON.stringify(detailRes, null, 2) + "\n");
4054
+ } else {
4055
+ process.stdout.write(JSON.stringify(listRes, null, 2) + "\n");
4056
+ }
4057
+ return;
4058
+ }
4059
+ if (!listRes.ok) {
4060
+ process.stderr.write(`Error: ${listRes.error?.message || "Unknown error"}
4061
+ `);
4062
+ process.exit(1);
4063
+ }
4064
+ const files = listRes.data;
4065
+ if (files.length === 0) {
4066
+ process.stdout.write("No memory files found.\n");
4067
+ return;
4068
+ }
4069
+ if (files.length === 1) {
4070
+ const detailRes = await client.im.memory.getFile(files[0].id);
4071
+ if (!detailRes.ok) {
4072
+ process.stderr.write(`Error: ${detailRes.error?.message || "Unknown error"}
4073
+ `);
4074
+ process.exit(1);
4075
+ }
4076
+ const file = detailRes.data;
4077
+ process.stdout.write(`ID: ${file.id}
4078
+ `);
4079
+ process.stdout.write(`Scope: ${file.scope}
4080
+ `);
4081
+ process.stdout.write(`Path: ${file.path}
4082
+ `);
4083
+ process.stdout.write(`
4084
+ ${file.content ?? ""}
4085
+ `);
4086
+ return;
4087
+ }
4088
+ printFileTable(files);
4089
+ } catch (err) {
4090
+ const message = err instanceof Error ? err.message : String(err);
4091
+ process.stderr.write(`Error: ${message}
4092
+ `);
4093
+ process.exit(1);
4094
+ }
4095
+ });
4096
+ mem.command("list").description("List memory files").option("-s, --scope <scope>", "filter by scope").option("--json", "output raw JSON response").action(async (opts) => {
4097
+ const client = getIMClient2();
4098
+ try {
4099
+ const res = await client.im.memory.listFiles({ scope: opts.scope });
4100
+ if (opts.json) {
4101
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
4102
+ return;
4103
+ }
4104
+ if (!res.ok) {
4105
+ process.stderr.write(`Error: ${res.error?.message || "Unknown error"}
4106
+ `);
4107
+ process.exit(1);
4108
+ }
4109
+ const files = res.data;
4110
+ if (files.length === 0) {
4111
+ process.stdout.write("No memory files found.\n");
4112
+ return;
4113
+ }
4114
+ printFileTable(files);
4115
+ } catch (err) {
4116
+ const message = err instanceof Error ? err.message : String(err);
4117
+ process.stderr.write(`Error: ${message}
4118
+ `);
4119
+ process.exit(1);
4120
+ }
4121
+ });
4122
+ mem.command("delete <file-id>").description("Delete a memory file by ID").option("--json", "output raw JSON response").action(async (fileId, opts) => {
4123
+ const client = getIMClient2();
4124
+ try {
4125
+ const res = await client.im.memory.deleteFile(fileId);
4126
+ if (opts.json) {
4127
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
4128
+ return;
4129
+ }
4130
+ if (!res.ok) {
4131
+ process.stderr.write(`Error: ${res.error?.message || "Unknown error"}
4132
+ `);
4133
+ process.exit(1);
4134
+ }
4135
+ process.stdout.write(`Deleted memory file: ${fileId}
4136
+ `);
4137
+ } catch (err) {
4138
+ const message = err instanceof Error ? err.message : String(err);
4139
+ process.stderr.write(`Error: ${message}
4140
+ `);
4141
+ process.exit(1);
4142
+ }
4143
+ });
4144
+ mem.command("compact <conversation-id>").description("Create a compaction summary for a conversation").option("--json", "output raw JSON response").action(async (conversationId, opts) => {
4145
+ const client = getIMClient2();
4146
+ try {
4147
+ const res = await client.im.memory.compact({ conversationId });
4148
+ if (opts.json) {
4149
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
4150
+ return;
4151
+ }
4152
+ if (!res.ok) {
4153
+ process.stderr.write(`Error: ${res.error?.message || "Unknown error"}
4154
+ `);
4155
+ process.exit(1);
4156
+ }
4157
+ const summary = res.data;
4158
+ process.stdout.write(`Compaction complete
4159
+ `);
4160
+ if (summary?.id) {
4161
+ process.stdout.write(` Summary ID: ${summary.id}
4162
+ `);
4163
+ }
4164
+ if (summary?.conversationId) {
4165
+ process.stdout.write(` Conversation ID: ${summary.conversationId}
4166
+ `);
4167
+ }
4168
+ } catch (err) {
4169
+ const message = err instanceof Error ? err.message : String(err);
4170
+ process.stderr.write(`Error: ${message}
4171
+ `);
4172
+ process.exit(1);
4173
+ }
4174
+ });
4175
+ mem.command("load").description("Load session memory context").option("-s, --scope <scope>", "scope to load").option("--json", "output raw JSON response").action(async (opts) => {
4176
+ const client = getIMClient2();
4177
+ try {
4178
+ const res = await client.im.memory.load(opts.scope);
4179
+ if (opts.json) {
4180
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
4181
+ return;
4182
+ }
4183
+ if (!res.ok) {
4184
+ process.stderr.write(`Error: ${res.error?.message || "Unknown error"}
4185
+ `);
4186
+ process.exit(1);
4187
+ }
4188
+ const context = res.data;
4189
+ if (!context || typeof context === "object" && Object.keys(context).length === 0) {
4190
+ process.stdout.write("No memory context available.\n");
4191
+ return;
4192
+ }
4193
+ process.stdout.write("Memory context loaded:\n\n");
4194
+ if (typeof context === "string") {
4195
+ process.stdout.write(context + "\n");
4196
+ } else {
4197
+ process.stdout.write(JSON.stringify(context, null, 2) + "\n");
4198
+ }
4199
+ } catch (err) {
4200
+ const message = err instanceof Error ? err.message : String(err);
4201
+ process.stderr.write(`Error: ${message}
4202
+ `);
4203
+ process.exit(1);
4204
+ }
4205
+ });
4206
+ }
4207
+ function printFileTable(files) {
4208
+ const idLen = Math.max(2, ...files.map((f) => f.id.length));
4209
+ const scopeLen = Math.max(5, ...files.map((f) => f.scope.length));
4210
+ const pathLen = Math.max(4, ...files.map((f) => f.path.length));
4211
+ const row = (id, scope, path2) => `${id.padEnd(idLen)} ${scope.padEnd(scopeLen)} ${path2.padEnd(pathLen)}`;
4212
+ process.stdout.write(row("ID", "SCOPE", "PATH") + "\n");
4213
+ process.stdout.write(`${"-".repeat(idLen)} ${"-".repeat(scopeLen)} ${"-".repeat(pathLen)}
4214
+ `);
4215
+ for (const f of files) {
4216
+ process.stdout.write(row(f.id, f.scope, f.path) + "\n");
4217
+ }
4218
+ }
4219
+
4220
+ // src/commands/skill.ts
4221
+ function padEnd(str, len) {
4222
+ if (str.length >= len) return str.slice(0, len);
4223
+ return str + " ".repeat(len - str.length);
4224
+ }
4225
+ function formatTable(rows) {
4226
+ if (rows.length === 0) return "";
4227
+ const cols = rows[0].length;
4228
+ const widths = Array(cols).fill(0);
4229
+ for (const row of rows) {
4230
+ for (let i = 0; i < cols; i++) {
4231
+ widths[i] = Math.max(widths[i], (row[i] ?? "").length);
4232
+ }
4233
+ }
4234
+ return rows.map((row) => row.map((cell, i) => padEnd(cell ?? "", widths[i])).join(" ")).join("\n");
4235
+ }
4236
+ function register6(parent, getIMClient2, _getAPIClient) {
4237
+ const skill = parent.command("skill").description("Browse, install, and manage skills");
4238
+ skill.command("find [query]").description("Search the skill marketplace").option("-c, --category <category>", "filter by category").option("-n, --limit <n>", "max results to return", "20").option("--json", "output raw JSON response").action(async (query, opts) => {
4239
+ const client = getIMClient2();
4240
+ try {
4241
+ const limit = parseInt(opts.limit, 10);
4242
+ const res = await client.im.evolution.searchSkills({
4243
+ query,
4244
+ category: opts.category,
4245
+ limit
4246
+ });
4247
+ if (opts.json) {
4248
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
4249
+ return;
4250
+ }
4251
+ const skills = Array.isArray(res) ? res : res?.skills ?? [];
4252
+ if (skills.length === 0) {
4253
+ process.stdout.write("No skills found.\n");
4254
+ return;
4255
+ }
4256
+ const header = ["Slug", "Name", "Installs", "Category"];
4257
+ const rows = skills.map((s) => {
4258
+ const sk = s;
4259
+ return [
4260
+ String(sk.slug ?? sk.id ?? ""),
4261
+ String(sk.name ?? ""),
4262
+ String(sk.installCount ?? sk.installs ?? "0"),
4263
+ String(sk.category ?? "")
4264
+ ];
4265
+ });
4266
+ process.stdout.write(formatTable([header, ...rows]) + "\n");
4267
+ } catch (err) {
4268
+ const message = err instanceof Error ? err.message : String(err);
4269
+ process.stderr.write(`Error: ${message}
4270
+ `);
4271
+ process.exit(1);
4272
+ }
4273
+ });
4274
+ skill.command("install <slug>").description("Install a skill").option("--platform <platform>", "target platform: claude-code, openclaw, opencode, or all", "all").option("--project <path>", "project directory for local file writes").option("--no-local", "cloud-only install, do not write local files").option("--json", "output raw JSON response").action(async (slug, opts) => {
4275
+ const client = getIMClient2();
4276
+ try {
4277
+ let res;
4278
+ if (!opts.local) {
4279
+ res = await client.im.evolution.installSkill(slug);
4280
+ } else {
4281
+ const platforms = opts.platform === "all" ? void 0 : [opts.platform];
4282
+ res = await client.im.evolution.installSkillLocal(slug, {
4283
+ platforms,
4284
+ project: opts.project
4285
+ });
4286
+ }
4287
+ if (opts.json) {
4288
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
4289
+ return;
4290
+ }
4291
+ const result = res;
4292
+ if (result?.ok === false) {
4293
+ process.stderr.write(`Install failed.
4294
+ `);
4295
+ process.exit(1);
4296
+ }
4297
+ const skillData = result?.data?.skill ?? {};
4298
+ const name = String(skillData.name ?? slug);
4299
+ process.stdout.write(`Installed: ${name}
4300
+ `);
4301
+ const localPaths = result?.data?.localPaths ?? [];
4302
+ if (localPaths.length > 0) {
4303
+ process.stdout.write("Local files written:\n");
4304
+ for (const p of localPaths) {
4305
+ process.stdout.write(` ${p}
4306
+ `);
4307
+ }
4308
+ } else if (!opts.local) {
4309
+ process.stdout.write("Cloud-only install complete (no local files written).\n");
4310
+ }
4311
+ } catch (err) {
4312
+ const message = err instanceof Error ? err.message : String(err);
4313
+ process.stderr.write(`Error: ${message}
4314
+ `);
4315
+ process.exit(1);
4316
+ }
4317
+ });
4318
+ skill.command("list").description("List installed skills").option("--json", "output raw JSON response").action(async (opts) => {
4319
+ const client = getIMClient2();
4320
+ try {
4321
+ const res = await client.im.evolution.installedSkills();
4322
+ if (opts.json) {
4323
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
4324
+ return;
4325
+ }
4326
+ const records = Array.isArray(res) ? res : res?.skills ?? [];
4327
+ if (records.length === 0) {
4328
+ process.stdout.write("No skills installed.\n");
4329
+ return;
4330
+ }
4331
+ const header = ["Slug", "Name", "Installs", "Category"];
4332
+ const rows = records.map((r) => {
4333
+ const rec = r;
4334
+ const sk = rec.skill ?? rec;
4335
+ return [
4336
+ String(sk.slug ?? sk.id ?? ""),
4337
+ String(sk.name ?? ""),
4338
+ String(sk.installCount ?? sk.installs ?? "0"),
4339
+ String(sk.category ?? "")
4340
+ ];
4341
+ });
4342
+ process.stdout.write(formatTable([header, ...rows]) + "\n");
4343
+ } catch (err) {
4344
+ const message = err instanceof Error ? err.message : String(err);
4345
+ process.stderr.write(`Error: ${message}
4346
+ `);
4347
+ process.exit(1);
4348
+ }
4349
+ });
4350
+ skill.command("show <slug>").description("Show skill content and details").option("--json", "output raw JSON response").action(async (slug, opts) => {
4351
+ const client = getIMClient2();
4352
+ try {
4353
+ const res = await client.im.evolution.getSkillContent(slug);
4354
+ if (opts.json) {
4355
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
4356
+ return;
4357
+ }
4358
+ const result = res;
4359
+ if (result?.packageUrl) {
4360
+ process.stdout.write(`Package URL: ${result.packageUrl}
4361
+ `);
4362
+ }
4363
+ if (result?.checksum) {
4364
+ process.stdout.write(`Checksum: ${result.checksum}
4365
+ `);
4366
+ }
4367
+ if (result?.files && result.files.length > 0) {
4368
+ process.stdout.write(`Files:
4369
+ `);
4370
+ for (const f of result.files) {
4371
+ process.stdout.write(` ${f}
4372
+ `);
4373
+ }
4374
+ }
4375
+ if (result?.content) {
4376
+ process.stdout.write(`
4377
+ ${result.content}
4378
+ `);
4379
+ }
4380
+ } catch (err) {
4381
+ const message = err instanceof Error ? err.message : String(err);
4382
+ process.stderr.write(`Error: ${message}
4383
+ `);
4384
+ process.exit(1);
4385
+ }
4386
+ });
4387
+ skill.command("uninstall <slug>").description("Uninstall a skill").option("--no-local", "cloud-only uninstall, do not remove local files").option("--json", "output raw JSON response").action(async (slug, opts) => {
4388
+ const client = getIMClient2();
4389
+ try {
4390
+ let res;
4391
+ if (!opts.local) {
4392
+ res = await client.im.evolution.uninstallSkill(slug);
4393
+ } else {
4394
+ res = await client.im.evolution.uninstallSkillLocal(slug);
4395
+ }
4396
+ if (opts.json) {
4397
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
4398
+ return;
4399
+ }
4400
+ const result = res;
4401
+ if (result?.ok === false) {
4402
+ process.stderr.write(`Uninstall failed.
4403
+ `);
4404
+ process.exit(1);
4405
+ }
4406
+ process.stdout.write(`Uninstalled: ${slug}
4407
+ `);
4408
+ const removedPaths = result?.data?.removedPaths ?? [];
4409
+ if (removedPaths.length > 0) {
4410
+ process.stdout.write("Local files removed:\n");
4411
+ for (const p of removedPaths) {
4412
+ process.stdout.write(` ${p}
4413
+ `);
4414
+ }
4415
+ } else if (!opts.local) {
4416
+ process.stdout.write("Cloud-only uninstall complete (no local files removed).\n");
4417
+ }
4418
+ } catch (err) {
4419
+ const message = err instanceof Error ? err.message : String(err);
4420
+ process.stderr.write(`Error: ${message}
4421
+ `);
4422
+ process.exit(1);
4423
+ }
4424
+ });
4425
+ skill.command("sync").description("Re-sync all installed skills to local filesystem").option("--platform <platform>", "target platform: claude-code, openclaw, opencode, or all", "all").option("--json", "output raw JSON response").action(async (opts) => {
4426
+ const client = getIMClient2();
4427
+ try {
4428
+ const platforms = opts.platform === "all" ? void 0 : [opts.platform];
4429
+ const res = await client.im.evolution.syncSkillsLocal({ platforms });
4430
+ if (opts.json) {
4431
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
4432
+ return;
4433
+ }
4434
+ const result = res;
4435
+ const synced = result?.synced ?? 0;
4436
+ const failed = result?.failed ?? 0;
4437
+ process.stdout.write(`Synced: ${synced} skill(s)`);
4438
+ if (failed > 0) {
4439
+ process.stdout.write(`, failed: ${failed}`);
4440
+ }
4441
+ process.stdout.write("\n");
4442
+ const paths = result?.paths ?? [];
4443
+ if (paths.length > 0) {
4444
+ process.stdout.write("Files written:\n");
4445
+ for (const p of paths) {
4446
+ process.stdout.write(` ${p}
4447
+ `);
4448
+ }
4449
+ }
4450
+ } catch (err) {
4451
+ const message = err instanceof Error ? err.message : String(err);
4452
+ process.stderr.write(`Error: ${message}
4453
+ `);
4454
+ process.exit(1);
4455
+ }
4456
+ });
4457
+ }
4458
+
4459
+ // src/commands/files.ts
4460
+ function register7(parent, getIMClient2, _getAPIClient) {
4461
+ const file = parent.command("file").description("File upload, transfer, quota, and type management");
4462
+ file.command("upload <path>").description("Upload a file and get its upload ID and CDN URL").option("--mime <type>", "Override MIME type (e.g. image/png)").option("--json", "Output raw JSON response").action(async (filePath, opts) => {
4463
+ const client = getIMClient2();
4464
+ try {
4465
+ const uploadOpts = {};
4466
+ if (opts.mime) uploadOpts.mimeType = opts.mime;
4467
+ const res = await client.im.files.upload(filePath, Object.keys(uploadOpts).length ? uploadOpts : void 0);
4468
+ if (opts.json) {
4469
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
4470
+ return;
4471
+ }
4472
+ process.stdout.write(`Uploaded: ${res.fileName}
4473
+ `);
4474
+ process.stdout.write(`Upload ID: ${res.uploadId}
4475
+ `);
4476
+ process.stdout.write(`CDN URL: ${res.cdnUrl}
4477
+ `);
4478
+ process.stdout.write(`Size: ${res.fileSize} bytes
4479
+ `);
4480
+ process.stdout.write(`MIME: ${res.mimeType}
4481
+ `);
4482
+ } catch (err) {
4483
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
4484
+ `);
4485
+ process.exit(1);
4486
+ }
4487
+ });
4488
+ file.command("send <conversation-id> <path>").description("Upload a file and send it as a message in a conversation").option("-c, --content <text>", "Optional text caption to accompany the file").option("--mime <type>", "Override MIME type").option("--json", "Output raw JSON response").action(async (conversationId, filePath, opts) => {
4489
+ const client = getIMClient2();
4490
+ try {
4491
+ const sendOpts = {};
4492
+ if (opts.content) sendOpts.content = opts.content;
4493
+ if (opts.mime) sendOpts.mimeType = opts.mime;
4494
+ const res = await client.im.files.sendFile(
4495
+ conversationId,
4496
+ filePath,
4497
+ Object.keys(sendOpts).length ? sendOpts : void 0
4498
+ );
4499
+ if (opts.json) {
4500
+ process.stdout.write(JSON.stringify(res, null, 2) + "\n");
4501
+ return;
4502
+ }
4503
+ process.stdout.write(`File sent (messageId: ${res.message?.id || res.message?.messageId || "-"})
4504
+ `);
4505
+ process.stdout.write(`Upload ID: ${res.upload?.uploadId || "-"}
4506
+ `);
4507
+ process.stdout.write(`CDN URL: ${res.upload?.cdnUrl || "-"}
4508
+ `);
4509
+ } catch (err) {
4510
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
4511
+ `);
4512
+ process.exit(1);
4513
+ }
4514
+ });
4515
+ file.command("quota").description("Show file storage quota and usage").option("--json", "Output raw JSON response").action(async (opts) => {
4516
+ const client = getIMClient2();
4517
+ const res = await client.im.files.quota();
4518
+ if (!res.ok) {
4519
+ process.stderr.write(`Error: ${JSON.stringify(res)}
4520
+ `);
4521
+ process.exit(1);
4522
+ }
4523
+ if (opts.json) {
4524
+ process.stdout.write(JSON.stringify(res.data, null, 2) + "\n");
4525
+ return;
4526
+ }
4527
+ const d = res.data;
4528
+ process.stdout.write(`Tier: ${d?.tier || "-"}
4529
+ `);
4530
+ process.stdout.write(`Used: ${d?.used ?? "-"} bytes
4531
+ `);
4532
+ process.stdout.write(`Limit: ${d?.limit ?? "-"} bytes
4533
+ `);
4534
+ process.stdout.write(`File Count: ${d?.fileCount ?? "-"}
4535
+ `);
4536
+ });
4537
+ file.command("delete <upload-id>").description("Delete an uploaded file by its upload ID").action(async (uploadId) => {
4538
+ const client = getIMClient2();
4539
+ const res = await client.im.files.delete(uploadId);
4540
+ if (!res.ok) {
4541
+ process.stderr.write(`Error: ${JSON.stringify(res)}
4542
+ `);
4543
+ process.exit(1);
4544
+ }
4545
+ process.stdout.write(`File ${uploadId} deleted.
4546
+ `);
4547
+ });
4548
+ file.command("types").description("List allowed MIME types for file uploads").option("--json", "Output raw JSON response").action(async (opts) => {
4549
+ const client = getIMClient2();
4550
+ const res = await client.im.files.types();
4551
+ if (!res.ok) {
4552
+ process.stderr.write(`Error: ${JSON.stringify(res)}
4553
+ `);
4554
+ process.exit(1);
4555
+ }
4556
+ if (opts.json) {
4557
+ process.stdout.write(JSON.stringify(res.data, null, 2) + "\n");
4558
+ return;
4559
+ }
4560
+ const types = res.data?.allowedMimeTypes || [];
4561
+ if (types.length === 0) {
4562
+ process.stdout.write("No allowed MIME types returned.\n");
4563
+ return;
4564
+ }
4565
+ process.stdout.write("Allowed MIME types:\n");
4566
+ for (const t of types) {
4567
+ process.stdout.write(` ${t}
4568
+ `);
4569
+ }
4570
+ });
4571
+ }
4572
+
4573
+ // src/commands/workspace.ts
4574
+ function register8(parent, getIMClient2, _getAPIClient) {
4575
+ const workspace = parent.command("workspace").description("Workspace management \u2014 init, groups, and agent assignment");
4576
+ workspace.command("init <name>").description("Initialize a workspace with a user and agent").requiredOption("--user-id <id>", "User ID").requiredOption("--user-name <name>", "User display name").requiredOption("--agent-id <id>", "Agent ID").requiredOption("--agent-name <name>", "Agent display name").option("--agent-type <type>", "Agent type", "assistant").option("--agent-capabilities <caps>", "Comma-separated list of agent capabilities").option("--json", "Output raw JSON response").action(async (name, opts) => {
4577
+ const client = getIMClient2();
4578
+ try {
4579
+ const capabilities = opts.agentCapabilities ? opts.agentCapabilities.split(",").map((s) => s.trim()) : void 0;
4580
+ const res = await client.im.workspace.init({
4581
+ name,
4582
+ userId: opts.userId,
4583
+ userName: opts.userName,
4584
+ agentId: opts.agentId,
4585
+ agentName: opts.agentName,
4586
+ agentType: opts.agentType,
4587
+ ...capabilities !== void 0 && { agentCapabilities: capabilities }
4588
+ });
4589
+ if (!res.ok) {
4590
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
4591
+ `);
4592
+ process.exit(1);
4593
+ }
4594
+ if (opts.json) {
4595
+ process.stdout.write(JSON.stringify(res.data, null, 2) + "\n");
4596
+ return;
4597
+ }
4598
+ process.stdout.write(`Workspace initialized (workspaceId: ${res.data?.workspaceId})
4599
+ `);
4600
+ } catch (err) {
4601
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
4602
+ `);
4603
+ process.exit(1);
4604
+ }
4605
+ });
4606
+ workspace.command("init-group <name>").description("Initialize a group workspace with a set of members").requiredOption("--members <json>", "JSON array of member objects").option("--json", "Output raw JSON response").action(async (name, opts) => {
4607
+ const client = getIMClient2();
4608
+ try {
4609
+ let members;
4610
+ try {
4611
+ members = JSON.parse(opts.members);
4612
+ } catch {
4613
+ process.stderr.write("Error: --members must be a valid JSON array\n");
4614
+ process.exit(1);
4615
+ }
4616
+ const res = await client.im.workspace.initGroup({ name, members });
4617
+ if (!res.ok) {
4618
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
4619
+ `);
4620
+ process.exit(1);
4621
+ }
4622
+ if (opts.json) {
4623
+ process.stdout.write(JSON.stringify(res.data, null, 2) + "\n");
4624
+ return;
4625
+ }
4626
+ process.stdout.write(`Group workspace initialized (workspaceId: ${res.data?.workspaceId})
4627
+ `);
4628
+ } catch (err) {
4629
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
4630
+ `);
4631
+ process.exit(1);
4632
+ }
4633
+ });
4634
+ workspace.command("add-agent <workspace-id> <agent-id>").description("Add an agent to a workspace").option("--json", "Output raw JSON response").action(async (workspaceId, agentId, opts) => {
4635
+ const client = getIMClient2();
4636
+ try {
4637
+ const res = await client.im.workspace.addAgent(workspaceId, agentId);
4638
+ if (!res.ok) {
4639
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
4640
+ `);
4641
+ process.exit(1);
4642
+ }
4643
+ if (opts.json) {
4644
+ process.stdout.write(JSON.stringify(res.data, null, 2) + "\n");
4645
+ return;
4646
+ }
4647
+ process.stdout.write(`Agent ${agentId} added to workspace ${workspaceId}.
4648
+ `);
4649
+ } catch (err) {
4650
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
4651
+ `);
4652
+ process.exit(1);
4653
+ }
4654
+ });
4655
+ workspace.command("agents <workspace-id>").description("List agents in a workspace").option("--json", "Output raw JSON response").action(async (workspaceId, opts) => {
4656
+ const client = getIMClient2();
4657
+ try {
4658
+ const res = await client.im.workspace.listAgents(workspaceId);
4659
+ if (!res.ok) {
4660
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
4661
+ `);
4662
+ process.exit(1);
4663
+ }
4664
+ const agents = res.data || [];
4665
+ if (opts.json) {
4666
+ process.stdout.write(JSON.stringify(agents, null, 2) + "\n");
4667
+ return;
4668
+ }
4669
+ if (agents.length === 0) {
4670
+ process.stdout.write("No agents in this workspace.\n");
4671
+ return;
4672
+ }
4673
+ process.stdout.write("Agent ID".padEnd(36) + "Type".padEnd(14) + "Name\n");
4674
+ for (const a of agents) {
4675
+ process.stdout.write(
4676
+ `${(a.agentId || a.id || "").padEnd(36)}${(a.agentType || "").padEnd(14)}${a.name || a.displayName || ""}
4677
+ `
4678
+ );
4679
+ }
4680
+ } catch (err) {
4681
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
4682
+ `);
4683
+ process.exit(1);
4684
+ }
4685
+ });
4686
+ }
4687
+
4688
+ // src/commands/security.ts
4689
+ function register9(parent, getIMClient2, _getAPIClient) {
4690
+ const security = parent.command("security").description("Per-conversation encryption and key management");
4691
+ security.command("get <conversation-id>").description("Get security settings for a conversation").option("--json", "Output raw JSON response").action(async (convId, opts) => {
4692
+ const client = getIMClient2();
4693
+ try {
4694
+ const res = await client.im.security.getConversationSecurity(convId);
4695
+ if (!res.ok) {
4696
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
4697
+ `);
4698
+ process.exit(1);
4699
+ }
4700
+ if (opts.json) {
4701
+ process.stdout.write(JSON.stringify(res.data, null, 2) + "\n");
4702
+ return;
4703
+ }
4704
+ const d = res.data;
4705
+ process.stdout.write(`Encryption Mode: ${d?.encryptionMode ?? "-"}
4706
+ `);
4707
+ process.stdout.write(`Signing Policy: ${d?.signingPolicy ?? "-"}
4708
+ `);
4709
+ } catch (err) {
4710
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
4711
+ `);
4712
+ process.exit(1);
4713
+ }
4714
+ });
4715
+ security.command("set <conversation-id>").description("Set encryption mode for a conversation").requiredOption("--mode <mode>", "Encryption mode: none, available, or required").option("--json", "Output raw JSON response").action(async (convId, opts) => {
4716
+ const client = getIMClient2();
4717
+ try {
4718
+ const res = await client.im.security.setConversationSecurity(convId, {
4719
+ encryptionMode: opts.mode
4720
+ });
4721
+ if (!res.ok) {
4722
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
4723
+ `);
4724
+ process.exit(1);
4725
+ }
4726
+ if (opts.json) {
4727
+ process.stdout.write(JSON.stringify(res.data, null, 2) + "\n");
4728
+ return;
4729
+ }
4730
+ process.stdout.write(`Encryption mode set to: ${opts.mode}
4731
+ `);
4732
+ } catch (err) {
4733
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
4734
+ `);
4735
+ process.exit(1);
4736
+ }
4737
+ });
4738
+ security.command("upload-key <conversation-id>").description("Upload an ECDH public key for a conversation").requiredOption("--key <base64>", "Base64-encoded public key").option("--algorithm <alg>", "Key algorithm", "ecdh-p256").option("--json", "Output raw JSON response").action(async (convId, opts) => {
4739
+ const client = getIMClient2();
4740
+ try {
4741
+ const res = await client.im.security.uploadKey(convId, opts.key, opts.algorithm);
4742
+ if (!res.ok) {
4743
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
4744
+ `);
4745
+ process.exit(1);
4746
+ }
4747
+ if (opts.json) {
4748
+ process.stdout.write(JSON.stringify(res.data, null, 2) + "\n");
4749
+ return;
4750
+ }
4751
+ process.stdout.write(`Key uploaded (algorithm: ${opts.algorithm})
4752
+ `);
4753
+ } catch (err) {
4754
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
4755
+ `);
4756
+ process.exit(1);
4757
+ }
4758
+ });
4759
+ security.command("keys <conversation-id>").description("List all member public keys for a conversation").option("--json", "Output raw JSON response").action(async (convId, opts) => {
4760
+ const client = getIMClient2();
4761
+ try {
4762
+ const res = await client.im.security.getKeys(convId);
4763
+ if (!res.ok) {
4764
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
4765
+ `);
4766
+ process.exit(1);
4767
+ }
4768
+ const keys = res.data;
4769
+ if (opts.json) {
4770
+ process.stdout.write(JSON.stringify(keys, null, 2) + "\n");
4771
+ return;
4772
+ }
4773
+ if (!keys || Array.isArray(keys) && keys.length === 0) {
4774
+ process.stdout.write("No keys found.\n");
4775
+ return;
4776
+ }
4777
+ process.stdout.write("User ID".padEnd(36) + "Algorithm".padEnd(16) + "Public Key\n");
4778
+ for (const k of keys) {
4779
+ process.stdout.write(
4780
+ `${String(k.userId ?? "").padEnd(36)}${String(k.algorithm ?? "").padEnd(16)}${String(k.publicKey ?? "")}
4781
+ `
4782
+ );
4783
+ }
4784
+ } catch (err) {
4785
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
4786
+ `);
4787
+ process.exit(1);
4788
+ }
4789
+ });
4790
+ security.command("revoke-key <conversation-id> <user-id>").description("Revoke a member key from a conversation").option("--json", "Output raw JSON response").action(async (convId, userId, opts) => {
4791
+ const client = getIMClient2();
4792
+ try {
4793
+ const res = await client.im.security.revokeKey(convId, userId);
4794
+ if (!res.ok) {
4795
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
4796
+ `);
4797
+ process.exit(1);
4798
+ }
4799
+ if (opts.json) {
4800
+ process.stdout.write(JSON.stringify(res.data, null, 2) + "\n");
4801
+ return;
4802
+ }
4803
+ process.stdout.write(`Key revoked for user: ${userId}
4804
+ `);
4805
+ } catch (err) {
4806
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
4807
+ `);
4808
+ process.exit(1);
4809
+ }
4810
+ });
4811
+ const identity = parent.command("identity").description("Identity key management and audit log verification");
4812
+ identity.command("server-key").description("Get the server's identity public key").option("--json", "Output raw JSON response").action(async (opts) => {
4813
+ const client = getIMClient2();
4814
+ try {
4815
+ const res = await client.im.identity.getServerKey();
4816
+ if (!res.ok) {
4817
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
4818
+ `);
4819
+ process.exit(1);
4820
+ }
4821
+ if (opts.json) {
4822
+ process.stdout.write(JSON.stringify(res.data, null, 2) + "\n");
4823
+ return;
4824
+ }
4825
+ const d = res.data;
4826
+ process.stdout.write(`Server Public Key: ${d?.publicKey ?? "-"}
4827
+ `);
4828
+ } catch (err) {
4829
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
4830
+ `);
4831
+ process.exit(1);
4832
+ }
4833
+ });
4834
+ identity.command("register-key").description("Register an identity public key").requiredOption("--algorithm <alg>", "Key algorithm (e.g. ed25519, ecdh-p256)").requiredOption("--public-key <base64>", "Base64-encoded public key").option("--json", "Output raw JSON response").action(async (opts) => {
4835
+ const client = getIMClient2();
4836
+ try {
4837
+ const res = await client.im.identity.registerKey({
4838
+ algorithm: opts.algorithm,
4839
+ publicKey: opts.publicKey
4840
+ });
4841
+ if (!res.ok) {
4842
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
4843
+ `);
4844
+ process.exit(1);
4845
+ }
4846
+ if (opts.json) {
4847
+ process.stdout.write(JSON.stringify(res.data, null, 2) + "\n");
4848
+ return;
4849
+ }
4850
+ process.stdout.write(`Identity key registered (algorithm: ${opts.algorithm})
4851
+ `);
4852
+ } catch (err) {
4853
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
4854
+ `);
4855
+ process.exit(1);
4856
+ }
4857
+ });
4858
+ identity.command("get-key <user-id>").description("Get a user's identity public key").option("--json", "Output raw JSON response").action(async (userId, opts) => {
4859
+ const client = getIMClient2();
4860
+ try {
4861
+ const res = await client.im.identity.getKey(userId);
4862
+ if (!res.ok) {
4863
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
4864
+ `);
4865
+ process.exit(1);
4866
+ }
4867
+ if (opts.json) {
4868
+ process.stdout.write(JSON.stringify(res.data, null, 2) + "\n");
4869
+ return;
4870
+ }
4871
+ const d = res.data;
4872
+ process.stdout.write(`Algorithm: ${d?.algorithm ?? "-"}
4873
+ `);
4874
+ process.stdout.write(`Public Key: ${d?.publicKey ?? "-"}
4875
+ `);
4876
+ } catch (err) {
4877
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
4878
+ `);
4879
+ process.exit(1);
4880
+ }
4881
+ });
4882
+ identity.command("revoke-key").description("Revoke your own identity key").option("--json", "Output raw JSON response").action(async (opts) => {
4883
+ const client = getIMClient2();
4884
+ try {
4885
+ const res = await client.im.identity.revokeKey();
4886
+ if (!res.ok) {
4887
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
4888
+ `);
4889
+ process.exit(1);
4890
+ }
4891
+ if (opts.json) {
4892
+ process.stdout.write(JSON.stringify(res.data, null, 2) + "\n");
4893
+ return;
4894
+ }
4895
+ process.stdout.write("Identity key revoked.\n");
4896
+ } catch (err) {
4897
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
4898
+ `);
4899
+ process.exit(1);
4900
+ }
4901
+ });
4902
+ identity.command("audit-log <user-id>").description("Get key audit log entries for a user").option("--json", "Output raw JSON response").action(async (userId, opts) => {
4903
+ const client = getIMClient2();
4904
+ try {
4905
+ const res = await client.im.identity.getAuditLog(userId);
4906
+ if (!res.ok) {
4907
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
4908
+ `);
4909
+ process.exit(1);
4910
+ }
4911
+ const entries = res.data;
4912
+ if (opts.json) {
4913
+ process.stdout.write(JSON.stringify(entries, null, 2) + "\n");
4914
+ return;
4915
+ }
4916
+ if (!entries || Array.isArray(entries) && entries.length === 0) {
4917
+ process.stdout.write("No audit log entries.\n");
4918
+ return;
4919
+ }
4920
+ process.stdout.write("Date".padEnd(24) + "Action".padEnd(20) + "Details\n");
4921
+ for (const e of entries) {
4922
+ const date = e.createdAt ? new Date(String(e.createdAt)).toLocaleString() : "";
4923
+ process.stdout.write(
4924
+ `${date.padEnd(24)}${String(e.action ?? "").padEnd(20)}${e.details ? JSON.stringify(e.details) : ""}
4925
+ `
4926
+ );
4927
+ }
4928
+ } catch (err) {
4929
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
4930
+ `);
4931
+ process.exit(1);
4932
+ }
4933
+ });
4934
+ identity.command("verify-audit <user-id>").description("Verify the integrity of the key audit log for a user").option("--json", "Output raw JSON response").action(async (userId, opts) => {
4935
+ const client = getIMClient2();
4936
+ try {
4937
+ const res = await client.im.identity.verifyAuditLog(userId);
4938
+ if (!res.ok) {
4939
+ process.stderr.write(`Error: ${res.error?.message || JSON.stringify(res.error)}
4940
+ `);
4941
+ process.exit(1);
4942
+ }
4943
+ if (opts.json) {
4944
+ process.stdout.write(JSON.stringify(res.data, null, 2) + "\n");
4945
+ return;
4946
+ }
4947
+ const d = res.data;
4948
+ if (d?.valid) {
4949
+ process.stdout.write("Audit log verified: VALID\n");
4950
+ } else {
4951
+ process.stdout.write("Audit log verified: INVALID\n");
4952
+ if (d?.errors && Array.isArray(d.errors) && d.errors.length > 0) {
4953
+ process.stdout.write("Errors:\n");
4954
+ for (const err of d.errors) {
4955
+ process.stdout.write(` - ${JSON.stringify(err)}
4956
+ `);
4957
+ }
4958
+ }
4959
+ }
4960
+ } catch (err) {
4961
+ process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}
4962
+ `);
4963
+ process.exit(1);
4964
+ }
4965
+ });
4966
+ }
4967
+
4968
+ // src/cli.ts
4969
+ var cliVersion = "1.7.2";
4970
+ try {
4971
+ const pkgPath = path.join(__dirname, "..", "package.json");
4972
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
4973
+ cliVersion = pkg.version || cliVersion;
4974
+ } catch {
4975
+ }
4976
+ var CONFIG_DIR = path.join(os.homedir(), ".prismer");
4977
+ var CONFIG_PATH = path.join(CONFIG_DIR, "config.toml");
4978
+ function ensureConfigDir() {
1747
4979
  if (!fs.existsSync(CONFIG_DIR)) {
1748
4980
  fs.mkdirSync(CONFIG_DIR, { recursive: true });
1749
4981
  }
1750
4982
  }
1751
4983
  function readConfig() {
1752
- if (!fs.existsSync(CONFIG_PATH)) {
1753
- return {};
1754
- }
4984
+ if (!fs.existsSync(CONFIG_PATH)) return {};
1755
4985
  const raw = fs.readFileSync(CONFIG_PATH, "utf-8");
1756
4986
  return TOML.parse(raw);
1757
4987
  }
1758
4988
  function writeConfig(config) {
1759
4989
  ensureConfigDir();
1760
- const content = TOML.stringify(config);
1761
- fs.writeFileSync(CONFIG_PATH, content, "utf-8");
4990
+ fs.writeFileSync(CONFIG_PATH, TOML.stringify(config), { encoding: "utf-8", mode: 384 });
1762
4991
  }
1763
4992
  function setNestedValue(obj, dotPath, value) {
1764
4993
  const parts = dotPath.split(".");
1765
4994
  let current = obj;
1766
4995
  for (let i = 0; i < parts.length - 1; i++) {
1767
4996
  const key = parts[i];
1768
- if (current[key] === void 0 || typeof current[key] !== "object") {
1769
- current[key] = {};
1770
- }
4997
+ if (current[key] === void 0 || typeof current[key] !== "object") current[key] = {};
1771
4998
  current = current[key];
1772
4999
  }
1773
5000
  current[parts[parts.length - 1]] = value;
@@ -1776,7 +5003,7 @@ function getIMClient() {
1776
5003
  const cfg = readConfig();
1777
5004
  const token = cfg?.auth?.im_token;
1778
5005
  if (!token) {
1779
- console.error('No IM token. Run "prismer register" first.');
5006
+ console.error('No IM token. Run "prismer setup --agent" or "prismer register <username>" first.');
1780
5007
  process.exit(1);
1781
5008
  }
1782
5009
  const env = cfg?.default?.environment || "production";
@@ -1787,35 +5014,200 @@ function getAPIClient() {
1787
5014
  const cfg = readConfig();
1788
5015
  const apiKey = cfg?.default?.api_key;
1789
5016
  if (!apiKey) {
1790
- console.error('No API key. Run "prismer init <api-key>" first.');
5017
+ console.error('No API key. Run "prismer setup" to sign in and get your key.');
1791
5018
  process.exit(1);
1792
5019
  }
1793
5020
  const env = cfg?.default?.environment || "production";
1794
5021
  const baseUrl = cfg?.default?.base_url || "";
1795
5022
  return new PrismerClient({ apiKey, environment: env, ...baseUrl ? { baseUrl } : {} });
1796
5023
  }
1797
- var program = new import_commander.Command();
1798
- program.name("prismer").description("Prismer Cloud SDK CLI").version(cliVersion);
1799
- program.command("init <api-key>").description("Store API key in ~/.prismer/config.toml").action((apiKey) => {
1800
- const config = readConfig();
1801
- if (!config.default) {
1802
- config.default = {};
1803
- }
1804
- config.default.api_key = apiKey;
1805
- if (!config.default.environment) {
1806
- config.default.environment = "production";
1807
- }
1808
- if (config.default.base_url === void 0) {
1809
- config.default.base_url = "";
1810
- }
1811
- writeConfig(config);
1812
- console.log("API key saved to ~/.prismer/config.toml");
5024
+ var program = new import_commander.Command();
5025
+ program.name("prismer").description("Prismer Cloud SDK CLI").version(cliVersion);
5026
+ async function verifyAndSaveKey(config, apiKey) {
5027
+ if (!apiKey) {
5028
+ console.error("No key provided.");
5029
+ process.exit(1);
5030
+ }
5031
+ if (!apiKey.startsWith("sk-prismer-")) {
5032
+ console.error("Invalid key format. API keys start with sk-prismer-");
5033
+ console.error("Get your key at: https://prismer.cloud/setup");
5034
+ process.exit(1);
5035
+ }
5036
+ const baseUrl = config.default?.base_url || "https://prismer.cloud";
5037
+ try {
5038
+ const res = await fetch(`${baseUrl}/api/version`, {
5039
+ headers: { Authorization: `Bearer ${apiKey}` }
5040
+ });
5041
+ if (res.status === 401) {
5042
+ console.error("API key is invalid or expired.");
5043
+ console.error("Get a new key at: https://prismer.cloud/setup");
5044
+ process.exit(1);
5045
+ }
5046
+ console.log("API key verified \u2713");
5047
+ } catch (err) {
5048
+ console.warn(`Could not verify key (${err.message}). Saving anyway.`);
5049
+ }
5050
+ if (!config.default) config.default = {};
5051
+ config.default.api_key = apiKey;
5052
+ if (!config.default.environment) config.default.environment = "production";
5053
+ writeConfig(config);
5054
+ console.log("");
5055
+ console.log("Saved to ~/.prismer/config.toml");
5056
+ console.log("You can now use: CLI commands, MCP tools, Claude Code plugin, and all SDKs.");
5057
+ }
5058
+ function openBrowser(url) {
5059
+ const { execFile } = require("child_process");
5060
+ if (process.platform === "darwin") {
5061
+ execFile("open", [url], (err) => {
5062
+ if (err) console.warn("Could not open browser. Please open the URL above manually.");
5063
+ });
5064
+ } else if (process.platform === "win32") {
5065
+ execFile("cmd.exe", ["/c", "start", "", url], (err) => {
5066
+ if (err) console.warn("Could not open browser. Please open the URL above manually.");
5067
+ });
5068
+ } else {
5069
+ execFile("xdg-open", [url], (err) => {
5070
+ if (err) console.warn("Could not open browser. Please open the URL above manually.");
5071
+ });
5072
+ }
5073
+ }
5074
+ async function runSetup(opts, apiKey) {
5075
+ const config = readConfig();
5076
+ if (!config.default) config.default = {};
5077
+ const baseUrl = config.default.base_url || "https://prismer.cloud";
5078
+ if (!opts.force && config.default.api_key?.startsWith("sk-prismer-")) {
5079
+ const masked = config.default.api_key.slice(0, 12) + "..." + config.default.api_key.slice(-4);
5080
+ console.log(`Already configured: ${masked}`);
5081
+ console.log("");
5082
+ console.log("To reconfigure, run: prismer setup --force");
5083
+ console.log("To check status: prismer status");
5084
+ return;
5085
+ }
5086
+ if (apiKey) {
5087
+ await verifyAndSaveKey(config, apiKey);
5088
+ return;
5089
+ }
5090
+ if (opts.agent) {
5091
+ if (!opts.force && config.auth?.im_token) {
5092
+ console.log("Already registered as agent (IM token exists).");
5093
+ console.log("For API key access, run: prismer setup");
5094
+ return;
5095
+ }
5096
+ const username = `agent-${Date.now().toString(36)}`;
5097
+ try {
5098
+ const res = await fetch(`${baseUrl}/api/im/register`, {
5099
+ method: "POST",
5100
+ headers: { "Content-Type": "application/json" },
5101
+ body: JSON.stringify({ username, displayName: username, type: "agent" })
5102
+ });
5103
+ const data = await res.json();
5104
+ if (!data.ok) throw new Error(data.error?.message || "Registration failed");
5105
+ if (!config.auth) config.auth = {};
5106
+ config.auth.im_token = data.data?.token;
5107
+ config.auth.im_user_id = data.data?.imUserId || data.data?.userId;
5108
+ config.auth.im_username = data.data?.username || username;
5109
+ writeConfig(config);
5110
+ console.log("Agent registered with free credits \u2713");
5111
+ console.log(` Username: ${config.auth.im_username}`);
5112
+ console.log(` User ID: ${config.auth.im_user_id}`);
5113
+ console.log("");
5114
+ console.log("For full API access, sign in: prismer setup");
5115
+ } catch (err) {
5116
+ console.error(`Agent registration failed: ${err.message}`);
5117
+ console.error("Try signing in instead: prismer setup");
5118
+ process.exit(1);
5119
+ }
5120
+ return;
5121
+ }
5122
+ if (opts.manual) {
5123
+ const setupUrl = `${baseUrl}/setup?utm_source=cli&utm_medium=manual`;
5124
+ console.log("Opening browser to sign in...");
5125
+ console.log(` ${setupUrl}`);
5126
+ console.log("");
5127
+ openBrowser(setupUrl);
5128
+ console.log("After signing in, copy the API key from the page and paste it below.");
5129
+ console.log("");
5130
+ const readline = require("readline");
5131
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
5132
+ rl.question("Paste your API key: ", (key) => {
5133
+ rl.close();
5134
+ verifyAndSaveKey(config, key.trim()).catch((err) => {
5135
+ console.error(`Setup failed: ${err.message}`);
5136
+ process.exit(1);
5137
+ });
5138
+ });
5139
+ return;
5140
+ }
5141
+ const http = require("http");
5142
+ const crypto2 = require("crypto");
5143
+ const state = crypto2.randomBytes(16).toString("hex");
5144
+ let resolved = false;
5145
+ const server = http.createServer((req, res) => {
5146
+ const url = new URL(req.url, `http://localhost`);
5147
+ if (url.pathname === "/callback") {
5148
+ const key = url.searchParams.get("key");
5149
+ const returnedState = url.searchParams.get("state");
5150
+ res.writeHead(200, { "Content-Type": "text/html" });
5151
+ if (!key || !returnedState || returnedState !== state) {
5152
+ res.end('<html><head><meta name="referrer" content="no-referrer"></head><body style="font-family:system-ui;text-align:center;padding:60px"><h2>Setup failed</h2><p>Invalid or missing parameters. Please try again.</p></body></html>');
5153
+ return;
5154
+ }
5155
+ if (!key.startsWith("sk-prismer-")) {
5156
+ res.end('<html><head><meta name="referrer" content="no-referrer"></head><body style="font-family:system-ui;text-align:center;padding:60px"><h2>Invalid key</h2><p>The key format is unexpected. Please try again.</p></body></html>');
5157
+ return;
5158
+ }
5159
+ res.end('<html><head><meta name="referrer" content="no-referrer"></head><body style="font-family:system-ui;text-align:center;padding:60px"><h2>Done!</h2><p>API key received. You can close this tab.</p></body></html>');
5160
+ resolved = true;
5161
+ verifyAndSaveKey(config, key).then(() => {
5162
+ server.close();
5163
+ process.exit(0);
5164
+ }).catch((err) => {
5165
+ console.error(`Setup failed: ${err.message}`);
5166
+ server.close();
5167
+ process.exit(1);
5168
+ });
5169
+ } else {
5170
+ res.writeHead(404);
5171
+ res.end("Not found");
5172
+ }
5173
+ });
5174
+ server.listen(0, "127.0.0.1", () => {
5175
+ const port = server.address().port;
5176
+ const callbackUrl = `http://127.0.0.1:${port}/callback`;
5177
+ const setupUrl = `${baseUrl}/setup?callback=${encodeURIComponent(callbackUrl)}&state=${state}&utm_source=cli&utm_medium=auto`;
5178
+ console.log("Opening browser to sign in...");
5179
+ console.log("");
5180
+ openBrowser(setupUrl);
5181
+ console.log("Waiting for authentication...");
5182
+ console.log("(If the browser didn't open, visit this URL manually:)");
5183
+ console.log(` ${setupUrl}`);
5184
+ console.log("");
5185
+ setTimeout(() => {
5186
+ if (!resolved) {
5187
+ console.error("Timed out waiting for authentication (5 min).");
5188
+ console.error("");
5189
+ console.error("Alternatives:");
5190
+ console.error(" prismer setup --manual Paste key manually");
5191
+ console.error(" prismer setup --agent Register as agent (free credits, no browser)");
5192
+ server.close();
5193
+ process.exit(1);
5194
+ }
5195
+ }, 5 * 60 * 1e3);
5196
+ });
5197
+ }
5198
+ program.command("setup [api-key]").description("Set up Prismer \u2014 sign in via browser, register as agent, or provide your API key").option("--manual", "Paste API key manually instead of browser auto-flow").option("--agent", "Register as agent with free credits (no browser, for CI/scripts)").option("--force", "Reconfigure even if already set up").action(async (apiKey, opts) => {
5199
+ await runSetup(opts, apiKey);
1813
5200
  });
1814
- program.command("register <username>").description("Register an IM agent and store the token").option("--type <type>", "Identity type: agent or human", "agent").option("--display-name <name>", "Display name for the agent").option("--agent-type <agentType>", "Agent type: assistant, specialist, orchestrator, tool, or bot").option("--capabilities <caps>", "Comma-separated list of capabilities").action(async (username, opts) => {
5201
+ program.command("init [api-key]").description('Alias for "prismer setup" (deprecated, use setup instead)').option("--manual", "Paste API key manually").option("--agent", "Register as agent with free credits").option("--force", "Reconfigure even if already set up").action(async (apiKey, opts) => {
5202
+ console.log('Note: "prismer init" is deprecated. Use "prismer setup" instead.');
5203
+ console.log("");
5204
+ await runSetup(opts, apiKey);
5205
+ });
5206
+ program.command("register <username>").description("Register an IM identity and store the token").option("--type <type>", "Identity type: agent or human", "agent").option("--display-name <name>", "Display name").option("--agent-type <agentType>", "Agent type: assistant, specialist, orchestrator, tool, bot").option("--capabilities <caps>", "Comma-separated capabilities").option("--endpoint <url>", "Webhook endpoint URL").option("--webhook-secret <secret>", "Webhook HMAC secret").action(async (username, opts) => {
1815
5207
  const config = readConfig();
1816
5208
  const apiKey = config.default?.api_key;
1817
5209
  if (!apiKey) {
1818
- console.error('Error: No API key configured. Run "prismer init <api-key>" first.');
5210
+ console.error('No API key. Run "prismer setup" first.');
1819
5211
  process.exit(1);
1820
5212
  }
1821
5213
  const client = new PrismerClient({
@@ -1828,12 +5220,10 @@ program.command("register <username>").description("Register an IM agent and sto
1828
5220
  username,
1829
5221
  displayName: opts.displayName || username
1830
5222
  };
1831
- if (opts.agentType) {
1832
- registerOpts.agentType = opts.agentType;
1833
- }
1834
- if (opts.capabilities) {
1835
- registerOpts.capabilities = opts.capabilities.split(",").map((c) => c.trim());
1836
- }
5223
+ if (opts.agentType) registerOpts.agentType = opts.agentType;
5224
+ if (opts.capabilities) registerOpts.capabilities = opts.capabilities.split(",").map((c) => c.trim());
5225
+ if (opts.endpoint) registerOpts.endpoint = opts.endpoint;
5226
+ if (opts.webhookSecret) registerOpts.webhookSecret = opts.webhookSecret;
1837
5227
  try {
1838
5228
  const result = await client.im.account.register(registerOpts);
1839
5229
  if (!result.ok || !result.data) {
@@ -1841,9 +5231,7 @@ program.command("register <username>").description("Register an IM agent and sto
1841
5231
  process.exit(1);
1842
5232
  }
1843
5233
  const data = result.data;
1844
- if (!config.auth) {
1845
- config.auth = {};
1846
- }
5234
+ if (!config.auth) config.auth = {};
1847
5235
  config.auth.im_token = data.token;
1848
5236
  config.auth.im_user_id = data.imUserId;
1849
5237
  config.auth.im_username = data.username;
@@ -1855,18 +5243,15 @@ program.command("register <username>").description("Register an IM agent and sto
1855
5243
  console.log(` Display: ${data.displayName}`);
1856
5244
  console.log(` Role: ${data.role}`);
1857
5245
  console.log(` New: ${data.isNew}`);
1858
- console.log(` Expires: ${data.expiresIn}`);
1859
- console.log("");
1860
5246
  console.log("Token stored in ~/.prismer/config.toml");
1861
5247
  } catch (err) {
1862
5248
  console.error("Registration failed:", err instanceof Error ? err.message : err);
1863
5249
  process.exit(1);
1864
5250
  }
1865
5251
  });
1866
- program.command("status").description("Show current config and token status").action(async () => {
5252
+ program.command("status").description("Show current config and live info").action(async () => {
1867
5253
  const config = readConfig();
1868
- console.log("=== Prismer Status ===");
1869
- console.log("");
5254
+ console.log("=== Prismer Status ===\n");
1870
5255
  const apiKey = config.default?.api_key;
1871
5256
  if (apiKey) {
1872
5257
  const masked = apiKey.length > 16 ? apiKey.slice(0, 12) + "..." + apiKey.slice(-4) : "***";
@@ -1875,8 +5260,8 @@ program.command("status").description("Show current config and token status").ac
1875
5260
  console.log("API Key: (not set)");
1876
5261
  }
1877
5262
  console.log(`Environment: ${config.default?.environment || "(not set)"}`);
1878
- console.log(`Base URL: ${config.default?.base_url || "(default)"}`);
1879
- console.log("");
5263
+ console.log(`Base URL: ${config.default?.base_url || "(default)"}
5264
+ `);
1880
5265
  const token = config.auth?.im_token;
1881
5266
  if (token) {
1882
5267
  console.log(`IM User ID: ${config.auth?.im_user_id || "(unknown)"}`);
@@ -1885,9 +5270,7 @@ program.command("status").description("Show current config and token status").ac
1885
5270
  if (expires) {
1886
5271
  const expiresDate = new Date(expires);
1887
5272
  if (!isNaN(expiresDate.getTime())) {
1888
- const now = /* @__PURE__ */ new Date();
1889
- const isExpired = expiresDate <= now;
1890
- const label = isExpired ? "EXPIRED" : "valid";
5273
+ const label = expiresDate <= /* @__PURE__ */ new Date() ? "EXPIRED" : "valid";
1891
5274
  console.log(`IM Token: ${label} (expires ${expiresDate.toISOString()})`);
1892
5275
  } else {
1893
5276
  console.log(`IM Token: set (expires in ${expires})`);
@@ -1895,12 +5278,7 @@ program.command("status").description("Show current config and token status").ac
1895
5278
  } else {
1896
5279
  console.log("IM Token: set (expiry unknown)");
1897
5280
  }
1898
- } else {
1899
- console.log("IM Token: (not registered)");
1900
- }
1901
- if (token) {
1902
- console.log("");
1903
- console.log("--- Live Info ---");
5281
+ console.log("\n--- Live Info ---");
1904
5282
  try {
1905
5283
  const client = new PrismerClient({
1906
5284
  apiKey: token,
@@ -1920,355 +5298,79 @@ program.command("status").description("Show current config and token status").ac
1920
5298
  } catch (err) {
1921
5299
  console.log(`Could not fetch live info: ${err instanceof Error ? err.message : err}`);
1922
5300
  }
5301
+ } else {
5302
+ console.log("IM Token: (not registered)");
1923
5303
  }
1924
5304
  });
1925
5305
  var configCmd = program.command("config").description("Manage config file");
1926
- configCmd.command("show").description("Print config file contents").action(() => {
5306
+ configCmd.command("show").description("Print config file").action(() => {
1927
5307
  if (!fs.existsSync(CONFIG_PATH)) {
1928
- console.log("No config file found at ~/.prismer/config.toml");
1929
- console.log('Run "prismer init <api-key>" to create one.');
5308
+ console.log('No config file. Run "prismer setup" to create one.');
1930
5309
  return;
1931
5310
  }
1932
- const raw = fs.readFileSync(CONFIG_PATH, "utf-8");
1933
- console.log(raw);
5311
+ console.log(fs.readFileSync(CONFIG_PATH, "utf-8"));
1934
5312
  });
1935
- configCmd.command("set <key> <value>").description("Set a config value (e.g., prismer config set default.api_key sk-prismer-...)").action((key, value) => {
5313
+ configCmd.command("set <key> <value>").description("Set a config value (e.g. default.base_url)").action((key, value) => {
1936
5314
  const config = readConfig();
1937
5315
  setNestedValue(config, key, value);
1938
5316
  writeConfig(config);
1939
5317
  console.log(`Set ${key} = ${value}`);
1940
5318
  });
1941
- var im = program.command("im").description("IM messaging commands");
1942
- im.command("me").description("Show current identity and stats").option("--json", "JSON output").action(async (opts) => {
1943
- const client = getIMClient();
1944
- const res = await client.im.account.me();
1945
- if (!res.ok) {
1946
- console.error("Error:", res.error);
1947
- process.exit(1);
1948
- }
1949
- const d = res.data;
1950
- if (opts.json) {
1951
- console.log(JSON.stringify(d, null, 2));
1952
- return;
1953
- }
1954
- console.log(`Display Name: ${d?.user?.displayName || "-"}`);
1955
- console.log(`Username: ${d?.user?.username || "-"}`);
1956
- console.log(`Role: ${d?.user?.role || "-"}`);
1957
- console.log(`Agent Type: ${d?.agentCard?.agentType || "-"}`);
1958
- console.log(`Credits: ${d?.credits?.balance ?? "-"}`);
1959
- console.log(`Messages: ${d?.stats?.messagesSent ?? "-"}`);
1960
- console.log(`Unread: ${d?.stats?.unreadCount ?? "-"}`);
1961
- });
1962
- im.command("health").description("Check IM service health").action(async () => {
1963
- const client = getIMClient();
1964
- const res = await client.im.health();
1965
- console.log(`IM Service: ${res.ok ? "OK" : "ERROR"}`);
1966
- if (!res.ok) {
1967
- console.error(res.error);
1968
- process.exit(1);
1969
- }
1970
- });
1971
- im.command("send").description("Send a direct message").argument("<user-id>", "Target user ID").argument("<message>", "Message content").option("--json", "JSON output").action(async (userId, message, opts) => {
1972
- const client = getIMClient();
1973
- const res = await client.im.direct.send(userId, message);
1974
- if (!res.ok) {
1975
- console.error("Error:", res.error);
1976
- process.exit(1);
1977
- }
1978
- if (opts.json) {
1979
- console.log(JSON.stringify(res.data, null, 2));
1980
- return;
1981
- }
1982
- console.log(`Message sent (conversationId: ${res.data?.conversationId})`);
1983
- });
1984
- im.command("messages").description("View direct message history").argument("<user-id>", "Target user ID").option("-n, --limit <n>", "Max messages", "20").option("--json", "JSON output").action(async (userId, opts) => {
1985
- const client = getIMClient();
1986
- const res = await client.im.direct.getMessages(userId, { limit: parseInt(opts.limit) });
1987
- if (!res.ok) {
1988
- console.error("Error:", res.error);
1989
- process.exit(1);
1990
- }
1991
- const msgs = res.data || [];
1992
- if (opts.json) {
1993
- console.log(JSON.stringify(msgs, null, 2));
1994
- return;
1995
- }
1996
- if (msgs.length === 0) {
1997
- console.log("No messages.");
1998
- return;
1999
- }
2000
- for (const m of msgs) {
2001
- const ts = m.createdAt ? new Date(m.createdAt).toLocaleString() : "";
2002
- console.log(`[${ts}] ${m.senderId || "?"}: ${m.content}`);
2003
- }
2004
- });
2005
- im.command("discover").description("Discover available agents").option("--type <type>", "Filter by type").option("--capability <cap>", "Filter by capability").option("--json", "JSON output").action(async (opts) => {
2006
- const client = getIMClient();
2007
- const discoverOpts = {};
2008
- if (opts.type) discoverOpts.type = opts.type;
2009
- if (opts.capability) discoverOpts.capability = opts.capability;
2010
- const res = await client.im.contacts.discover(discoverOpts);
2011
- if (!res.ok) {
2012
- console.error("Error:", res.error);
2013
- process.exit(1);
2014
- }
2015
- const agents = res.data || [];
2016
- if (opts.json) {
2017
- console.log(JSON.stringify(agents, null, 2));
2018
- return;
2019
- }
2020
- if (agents.length === 0) {
2021
- console.log("No agents found.");
2022
- return;
2023
- }
2024
- console.log("Username".padEnd(20) + "Type".padEnd(14) + "Status".padEnd(10) + "Display Name");
2025
- for (const a of agents) {
2026
- console.log(`${(a.username || "").padEnd(20)}${(a.agentType || "").padEnd(14)}${(a.status || "").padEnd(10)}${a.displayName || ""}`);
2027
- }
2028
- });
2029
- im.command("contacts").description("List contacts").option("--json", "JSON output").action(async (opts) => {
2030
- const client = getIMClient();
2031
- const res = await client.im.contacts.list();
2032
- if (!res.ok) {
2033
- console.error("Error:", res.error);
2034
- process.exit(1);
2035
- }
2036
- const contacts = res.data || [];
2037
- if (opts.json) {
2038
- console.log(JSON.stringify(contacts, null, 2));
2039
- return;
2040
- }
2041
- if (contacts.length === 0) {
2042
- console.log("No contacts.");
2043
- return;
2044
- }
2045
- console.log("Username".padEnd(20) + "Role".padEnd(10) + "Unread".padEnd(8) + "Display Name");
2046
- for (const c of contacts) {
2047
- console.log(`${(c.username || "").padEnd(20)}${(c.role || "").padEnd(10)}${String(c.unreadCount ?? 0).padEnd(8)}${c.displayName || ""}`);
2048
- }
2049
- });
2050
- var groups = im.command("groups").description("Group management");
2051
- groups.command("list").description("List groups").option("--json", "JSON output").action(async (opts) => {
2052
- const client = getIMClient();
2053
- const res = await client.im.groups.list();
2054
- if (!res.ok) {
2055
- console.error("Error:", res.error);
2056
- process.exit(1);
2057
- }
2058
- const list = res.data || [];
2059
- if (opts.json) {
2060
- console.log(JSON.stringify(list, null, 2));
2061
- return;
2062
- }
2063
- if (list.length === 0) {
2064
- console.log("No groups.");
2065
- return;
2066
- }
2067
- for (const g of list) {
2068
- console.log(`${g.groupId || ""} ${g.title || ""} (${g.members?.length || "?"} members)`);
2069
- }
2070
- });
2071
- groups.command("create").description("Create a group").argument("<title>", "Group title").option("-m, --members <ids>", "Comma-separated member IDs").option("--json", "JSON output").action(async (title, opts) => {
2072
- const client = getIMClient();
2073
- const members = opts.members ? opts.members.split(",").map((s) => s.trim()) : [];
2074
- const res = await client.im.groups.create({ title, members });
2075
- if (!res.ok) {
2076
- console.error("Error:", res.error);
2077
- process.exit(1);
2078
- }
2079
- if (opts.json) {
2080
- console.log(JSON.stringify(res.data, null, 2));
2081
- return;
2082
- }
2083
- console.log(`Group created (groupId: ${res.data?.groupId})`);
2084
- });
2085
- groups.command("send").description("Send message to group").argument("<group-id>", "Group ID").argument("<message>", "Message content").option("--json", "JSON output").action(async (groupId, message, opts) => {
2086
- const client = getIMClient();
2087
- const res = await client.im.groups.send(groupId, message);
2088
- if (!res.ok) {
2089
- console.error("Error:", res.error);
2090
- process.exit(1);
2091
- }
2092
- if (opts.json) {
2093
- console.log(JSON.stringify(res.data, null, 2));
2094
- return;
2095
- }
2096
- console.log("Message sent to group.");
2097
- });
2098
- groups.command("messages").description("View group message history").argument("<group-id>", "Group ID").option("-n, --limit <n>", "Max messages", "20").option("--json", "JSON output").action(async (groupId, opts) => {
2099
- const client = getIMClient();
2100
- const res = await client.im.groups.getMessages(groupId, { limit: parseInt(opts.limit) });
2101
- if (!res.ok) {
2102
- console.error("Error:", res.error);
2103
- process.exit(1);
2104
- }
2105
- const msgs = res.data || [];
2106
- if (opts.json) {
2107
- console.log(JSON.stringify(msgs, null, 2));
2108
- return;
2109
- }
2110
- if (msgs.length === 0) {
2111
- console.log("No messages.");
2112
- return;
2113
- }
2114
- for (const m of msgs) {
2115
- const ts = m.createdAt ? new Date(m.createdAt).toLocaleString() : "";
2116
- console.log(`[${ts}] ${m.senderId || "?"}: ${m.content}`);
2117
- }
2118
- });
2119
- var convos = im.command("conversations").description("Conversation management");
2120
- convos.command("list").description("List conversations").option("--unread", "Show unread only").option("--json", "JSON output").action(async (opts) => {
2121
- const client = getIMClient();
2122
- const listOpts = {};
2123
- if (opts.unread) {
2124
- listOpts.withUnread = true;
2125
- listOpts.unreadOnly = true;
2126
- }
2127
- const res = await client.im.conversations.list(listOpts);
2128
- if (!res.ok) {
2129
- console.error("Error:", res.error);
2130
- process.exit(1);
2131
- }
2132
- const list = res.data || [];
2133
- if (opts.json) {
2134
- console.log(JSON.stringify(list, null, 2));
2135
- return;
2136
- }
2137
- if (list.length === 0) {
2138
- console.log("No conversations.");
2139
- return;
2140
- }
2141
- for (const c of list) {
2142
- const unread = c.unreadCount ? ` (${c.unreadCount} unread)` : "";
2143
- console.log(`${c.id || ""} ${c.type || ""} ${c.title || ""}${unread}`);
2144
- }
2145
- });
2146
- convos.command("read").description("Mark conversation as read").argument("<conversation-id>", "Conversation ID").action(async (convId) => {
2147
- const client = getIMClient();
2148
- const res = await client.im.conversations.markAsRead(convId);
2149
- if (!res.ok) {
2150
- console.error("Error:", res.error);
2151
- process.exit(1);
2152
- }
2153
- console.log("Marked as read.");
2154
- });
2155
- var files = im.command("files").description("File upload management");
2156
- files.command("upload").description("Upload a file").argument("<path>", "File path to upload").option("--mime <type>", "Override MIME type").option("--json", "JSON output").action(async (filePath, opts) => {
2157
- const client = getIMClient();
2158
- try {
2159
- const result = await client.im.files.upload(filePath, { mimeType: opts.mime });
2160
- if (opts.json) {
2161
- console.log(JSON.stringify(result, null, 2));
2162
- return;
2163
- }
2164
- console.log(`Upload ID: ${result.uploadId}`);
2165
- console.log(`CDN URL: ${result.cdnUrl}`);
2166
- console.log(`File: ${result.fileName} (${result.fileSize} bytes)`);
2167
- console.log(`MIME: ${result.mimeType}`);
2168
- } catch (err) {
2169
- console.error("Upload failed:", err instanceof Error ? err.message : err);
2170
- process.exit(1);
2171
- }
2172
- });
2173
- files.command("send").description("Upload file and send as message").argument("<conversation-id>", "Conversation ID").argument("<path>", "File path to upload").option("--content <text>", "Message text").option("--mime <type>", "Override MIME type").option("--json", "JSON output").action(async (conversationId, filePath, opts) => {
2174
- const client = getIMClient();
2175
- try {
2176
- const result = await client.im.files.sendFile(conversationId, filePath, { content: opts.content, mimeType: opts.mime });
2177
- if (opts.json) {
2178
- console.log(JSON.stringify(result, null, 2));
2179
- return;
2180
- }
2181
- console.log(`Upload ID: ${result.upload.uploadId}`);
2182
- console.log(`CDN URL: ${result.upload.cdnUrl}`);
2183
- console.log(`File: ${result.upload.fileName}`);
2184
- console.log(`Message: sent`);
2185
- } catch (err) {
2186
- console.error("Send file failed:", err instanceof Error ? err.message : err);
2187
- process.exit(1);
2188
- }
2189
- });
2190
- files.command("quota").description("Show storage quota").option("--json", "JSON output").action(async (opts) => {
5319
+ var tokenCmd = program.command("token").description("Token management");
5320
+ tokenCmd.command("refresh").description("Refresh IM JWT token").option("--json", "JSON output").action(async (opts) => {
2191
5321
  const client = getIMClient();
2192
- const res = await client.im.files.quota();
2193
- if (!res.ok) {
2194
- console.error("Error:", res.error);
2195
- process.exit(1);
2196
- }
5322
+ const res = await client.im.account.refreshToken();
2197
5323
  if (opts.json) {
2198
- console.log(JSON.stringify(res.data, null, 2));
5324
+ console.log(JSON.stringify(res, null, 2));
2199
5325
  return;
2200
5326
  }
2201
- const q = res.data;
2202
- console.log(`Used: ${q?.used ?? "-"} bytes`);
2203
- console.log(`Limit: ${q?.limit ?? "-"} bytes`);
2204
- console.log(`File Count: ${q?.fileCount ?? "-"}`);
2205
- console.log(`Tier: ${q?.tier ?? "-"}`);
2206
- });
2207
- files.command("delete").description("Delete an uploaded file").argument("<upload-id>", "Upload ID").action(async (uploadId) => {
2208
- const client = getIMClient();
2209
- const res = await client.im.files.delete(uploadId);
2210
- if (!res.ok) {
2211
- console.error("Error:", res.error);
2212
- process.exit(1);
2213
- }
2214
- console.log(`Deleted upload ${uploadId}.`);
2215
- });
2216
- files.command("types").description("List allowed MIME types").option("--json", "JSON output").action(async (opts) => {
2217
- const client = getIMClient();
2218
- const res = await client.im.files.types();
2219
5327
  if (!res.ok) {
2220
5328
  console.error("Error:", res.error);
2221
5329
  process.exit(1);
2222
5330
  }
2223
- if (opts.json) {
2224
- console.log(JSON.stringify(res.data, null, 2));
2225
- return;
2226
- }
2227
- const types = res.data?.allowedMimeTypes || [];
2228
- console.log(`Allowed MIME types (${types.length}):`);
2229
- for (const t of types) {
2230
- console.log(` ${t}`);
5331
+ const data = res.data;
5332
+ const config = readConfig();
5333
+ if (!config.auth) config.auth = {};
5334
+ if (data?.token) {
5335
+ config.auth.im_token = data.token;
5336
+ if (data.expiresIn) config.auth.im_token_expires = data.expiresIn;
5337
+ writeConfig(config);
5338
+ console.log("Token refreshed and saved.");
5339
+ } else {
5340
+ console.log("Token refreshed (no new token in response).");
2231
5341
  }
2232
5342
  });
2233
- im.command("credits").description("Show credits balance").option("--json", "JSON output").action(async (opts) => {
5343
+ register(program, getIMClient, getAPIClient);
5344
+ register2(program, getIMClient, getAPIClient);
5345
+ register3(program, getIMClient, getAPIClient);
5346
+ register4(program, getIMClient, getAPIClient);
5347
+ register5(program, getIMClient, getAPIClient);
5348
+ register6(program, getIMClient, getAPIClient);
5349
+ register7(program, getIMClient, getAPIClient);
5350
+ register8(program, getIMClient, getAPIClient);
5351
+ register9(program, getIMClient, getAPIClient);
5352
+ program.command("send").description("Send a direct message (shortcut for: im send)").argument("<user-id>", "Target user/agent ID").argument("<message>", "Message content").option("-t, --type <type>", "Message type: text, markdown, code, etc.", "text").option("--reply-to <id>", "Reply to a message ID").option("--json", "JSON output").action(async (userId, message, opts) => {
2234
5353
  const client = getIMClient();
2235
- const res = await client.im.credits.get();
2236
- if (!res.ok) {
2237
- console.error("Error:", res.error);
2238
- process.exit(1);
2239
- }
5354
+ const sendOpts = {};
5355
+ if (opts.type && opts.type !== "text") sendOpts.type = opts.type;
5356
+ if (opts.replyTo) sendOpts.parentId = opts.replyTo;
5357
+ const res = await client.im.direct.send(userId, message, sendOpts);
2240
5358
  if (opts.json) {
2241
- console.log(JSON.stringify(res.data, null, 2));
5359
+ console.log(JSON.stringify(res, null, 2));
2242
5360
  return;
2243
5361
  }
2244
- console.log(`Balance: ${res.data?.balance ?? "-"}`);
2245
- });
2246
- im.command("transactions").description("Transaction history").option("-n, --limit <n>", "Max transactions", "20").option("--json", "JSON output").action(async (opts) => {
2247
- const client = getIMClient();
2248
- const res = await client.im.credits.transactions({ limit: parseInt(opts.limit) });
2249
5362
  if (!res.ok) {
2250
5363
  console.error("Error:", res.error);
2251
5364
  process.exit(1);
2252
5365
  }
2253
- const txns = res.data || [];
2254
- if (opts.json) {
2255
- console.log(JSON.stringify(txns, null, 2));
2256
- return;
2257
- }
2258
- if (txns.length === 0) {
2259
- console.log("No transactions.");
2260
- return;
2261
- }
2262
- for (const t of txns) {
2263
- console.log(`${t.createdAt || ""} ${t.type || ""} ${t.amount ?? ""} ${t.description || ""}`);
2264
- }
5366
+ console.log(`Message sent (conversation: ${res.data?.conversationId})`);
2265
5367
  });
2266
- var ctx = program.command("context").description("Context API commands");
2267
- ctx.command("load").description("Load URL content").argument("<url>", "URL to load").option("-f, --format <fmt>", "Return format: hqcc, raw, both", "hqcc").option("--json", "JSON output").action(async (url, opts) => {
5368
+ program.command("load").description("Load URL(s) \u2192 compressed HQCC (shortcut for: context load)").argument("<urls...>", "One or more URLs").option("-f, --format <fmt>", "Return format: hqcc, raw, both", "hqcc").option("--json", "JSON output").action(async (urls, opts) => {
2268
5369
  const client = getAPIClient();
5370
+ const input = urls.length === 1 ? urls[0] : urls;
2269
5371
  const loadOpts = {};
2270
5372
  if (opts.format) loadOpts.return = { format: opts.format };
2271
- const res = await client.load(url, loadOpts);
5373
+ const res = await client.load(input, loadOpts);
2272
5374
  if (opts.json) {
2273
5375
  console.log(JSON.stringify(res, null, 2));
2274
5376
  return;
@@ -2277,23 +5379,22 @@ ctx.command("load").description("Load URL content").argument("<url>", "URL to lo
2277
5379
  console.error("Error:", res.error?.message || "Load failed");
2278
5380
  process.exit(1);
2279
5381
  }
2280
- const r = res.result;
2281
- console.log(`URL: ${r?.url || url}`);
2282
- console.log(`Status: ${r?.cached ? "cached" : "loaded"}`);
2283
- if (r?.hqcc) {
2284
- console.log(`
5382
+ const results = res.results || (res.result ? [res.result] : []);
5383
+ for (const r of results) {
5384
+ console.log(`URL: ${r.url || "?"}`);
5385
+ console.log(`Status: ${r.cached ? "cached" : "loaded"}`);
5386
+ if (r.hqcc) console.log(`
2285
5387
  --- HQCC ---
2286
5388
  ${r.hqcc.substring(0, 2e3)}`);
2287
- }
2288
- if (r?.raw) {
2289
- console.log(`
5389
+ if (r.raw) console.log(`
2290
5390
  --- Raw ---
2291
5391
  ${r.raw.substring(0, 2e3)}`);
5392
+ console.log("");
2292
5393
  }
2293
5394
  });
2294
- ctx.command("search").description("Search cached content").argument("<query>", "Search query").option("-k, --top-k <n>", "Number of results", "5").option("--json", "JSON output").action(async (query, opts) => {
5395
+ program.command("search").description("Search web content (shortcut for: context search)").argument("<query>", "Search query").option("-k, --top-k <n>", "Number of results", "5").option("--json", "JSON output").action(async (query, opts) => {
2295
5396
  const client = getAPIClient();
2296
- const res = await client.search(query, { topK: parseInt(opts.topK) });
5397
+ const res = await client.search(query, { topK: parseInt(opts.topK || "5") });
2297
5398
  if (opts.json) {
2298
5399
  console.log(JSON.stringify(res, null, 2));
2299
5400
  return;
@@ -2313,21 +5414,7 @@ ctx.command("search").description("Search cached content").argument("<query>", "
2313
5414
  if (r.hqcc) console.log(` ${r.hqcc.substring(0, 200)}`);
2314
5415
  }
2315
5416
  });
2316
- ctx.command("save").description("Save content to cache").argument("<url>", "URL key").argument("<hqcc>", "HQCC content").option("--json", "JSON output").action(async (url, hqcc, opts) => {
2317
- const client = getAPIClient();
2318
- const res = await client.save({ url, hqcc });
2319
- if (opts.json) {
2320
- console.log(JSON.stringify(res, null, 2));
2321
- return;
2322
- }
2323
- if (!res.success) {
2324
- console.error("Error:", res.error?.message || "Save failed");
2325
- process.exit(1);
2326
- }
2327
- console.log("Content saved.");
2328
- });
2329
- var parse2 = program.command("parse").description("Document parsing commands");
2330
- parse2.command("run").description("Parse a document").argument("<url>", "Document URL").option("-m, --mode <mode>", "Parse mode: fast, hires, auto", "fast").option("--json", "JSON output").action(async (url, opts) => {
5417
+ program.command("parse").description("Parse a document via OCR (shortcut for: parse run)").argument("<url>", "Document URL").option("-m, --mode <mode>", "Parse mode: fast, hires, auto", "fast").option("--async", "Async mode (returns task ID)").option("--json", "JSON output").action(async (url, opts) => {
2331
5418
  const client = getAPIClient();
2332
5419
  const res = await client.parsePdf(url, opts.mode);
2333
5420
  if (opts.json) {
@@ -2342,14 +5429,17 @@ parse2.command("run").description("Parse a document").argument("<url>", "Documen
2342
5429
  console.log(`Task ID: ${res.taskId}`);
2343
5430
  console.log(`Status: ${res.status || "processing"}`);
2344
5431
  console.log(`
2345
- Check progress: prismer parse status ${res.taskId}`);
5432
+ Check: prismer parse status ${res.taskId}`);
2346
5433
  } else if (res.document) {
2347
- console.log(`Status: complete`);
5434
+ console.log("Status: complete");
2348
5435
  const content = res.document.markdown || res.document.text || JSON.stringify(res.document, null, 2);
2349
5436
  console.log(content.substring(0, 5e3));
2350
5437
  }
2351
5438
  });
2352
- parse2.command("status").description("Check parse task status").argument("<task-id>", "Task ID").option("--json", "JSON output").action(async (taskId, opts) => {
5439
+ var parseCmd = program.commands.find((c) => c.name() === "parse");
5440
+ if (parseCmd) {
5441
+ }
5442
+ program.command("parse-status").description("Check parse task status").argument("<task-id>", "Task ID").option("--json", "JSON output").action(async (taskId, opts) => {
2353
5443
  const client = getAPIClient();
2354
5444
  const res = await client.parseStatus(taskId);
2355
5445
  if (opts.json) {
@@ -2359,7 +5449,7 @@ parse2.command("status").description("Check parse task status").argument("<task-
2359
5449
  console.log(`Task: ${taskId}`);
2360
5450
  console.log(`Status: ${res.status || (res.success ? "complete" : "unknown")}`);
2361
5451
  });
2362
- parse2.command("result").description("Get parse result").argument("<task-id>", "Task ID").option("--json", "JSON output").action(async (taskId, opts) => {
5452
+ program.command("parse-result").description("Get parse result").argument("<task-id>", "Task ID").option("--json", "JSON output").action(async (taskId, opts) => {
2363
5453
  const client = getAPIClient();
2364
5454
  const res = await client.parseResult(taskId);
2365
5455
  if (opts.json) {
@@ -2373,4 +5463,57 @@ parse2.command("result").description("Get parse result").argument("<task-id>", "
2373
5463
  const content = res.document?.markdown || res.document?.text || JSON.stringify(res.document, null, 2);
2374
5464
  console.log(content);
2375
5465
  });
5466
+ program.command("recall").description("Search across memory, cache, and evolution (shortcut for: memory recall)").argument("<query>", "Search query").option("--scope <scope>", "Scope: all, memory, cache, evolution", "all").option("-n, --limit <n>", "Max results", "10").option("--json", "JSON output").action(async (query, opts) => {
5467
+ const client = getIMClient();
5468
+ const params = { q: query };
5469
+ if (opts.scope) params.scope = opts.scope;
5470
+ if (opts.limit) params.limit = opts.limit;
5471
+ const res = await client.im.memory._r("GET", "/api/im/recall", void 0, params);
5472
+ if (opts.json) {
5473
+ console.log(JSON.stringify(res, null, 2));
5474
+ return;
5475
+ }
5476
+ if (!res.ok) {
5477
+ console.error("Error:", res.error);
5478
+ process.exit(1);
5479
+ }
5480
+ const data = res.data || [];
5481
+ if (data.length === 0) {
5482
+ console.log(`No results for "${query}".`);
5483
+ return;
5484
+ }
5485
+ for (const item of data) {
5486
+ console.log(`[${(item.source || "").toUpperCase()}] ${item.title || "?"} (score: ${(item.score || 0).toFixed(2)})`);
5487
+ if (item.snippet) console.log(` ${item.snippet.substring(0, 200)}`);
5488
+ }
5489
+ });
5490
+ program.command("discover").description("Discover available agents (shortcut for: im discover)").option("--type <type>", "Filter by agent type").option("--capability <cap>", "Filter by capability").option("--json", "JSON output").action(async (opts) => {
5491
+ const client = getIMClient();
5492
+ const discoverOpts = {};
5493
+ if (opts.type) discoverOpts.type = opts.type;
5494
+ if (opts.capability) discoverOpts.capability = opts.capability;
5495
+ const res = await client.im.contacts.discover(discoverOpts);
5496
+ if (opts.json) {
5497
+ console.log(JSON.stringify(res, null, 2));
5498
+ return;
5499
+ }
5500
+ if (!res.ok) {
5501
+ console.error("Error:", res.error);
5502
+ process.exit(1);
5503
+ }
5504
+ const agents = res.data || [];
5505
+ if (agents.length === 0) {
5506
+ console.log("No agents found.");
5507
+ return;
5508
+ }
5509
+ console.log("Username".padEnd(20) + "Type".padEnd(14) + "Status".padEnd(10) + "Display Name");
5510
+ for (const a of agents) {
5511
+ console.log(`${(a.username || "").padEnd(20)}${(a.agentType || "").padEnd(14)}${(a.status || "").padEnd(10)}${a.displayName || ""}`);
5512
+ }
5513
+ });
2376
5514
  program.parse(process.argv);
5515
+ // Annotate the CommonJS export names for ESM import in node:
5516
+ 0 && (module.exports = {
5517
+ getAPIClient,
5518
+ getIMClient
5519
+ });