@aomi-labs/client 0.1.1 → 0.1.2

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
@@ -19,6 +19,444 @@ var __spreadValues = (a, b) => {
19
19
  };
20
20
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
21
21
 
22
+ // src/cli/args.ts
23
+ function parseArgs(argv) {
24
+ const raw = argv.slice(2);
25
+ const command = raw[0] && !raw[0].startsWith("--") ? raw[0] : void 0;
26
+ const rest = command ? raw.slice(1) : raw;
27
+ const positional = [];
28
+ const flags = {};
29
+ for (let i = 0; i < rest.length; i++) {
30
+ const arg = rest[i];
31
+ if (arg.startsWith("--") && arg.includes("=")) {
32
+ const [key, ...val] = arg.slice(2).split("=");
33
+ flags[key] = val.join("=");
34
+ } else if (arg.startsWith("--")) {
35
+ const key = arg.slice(2);
36
+ const next = rest[i + 1];
37
+ if (next && !next.startsWith("-")) {
38
+ flags[key] = next;
39
+ i++;
40
+ } else {
41
+ flags[key] = "true";
42
+ }
43
+ } else if (arg.startsWith("-") && arg.length === 2) {
44
+ flags[arg.slice(1)] = "true";
45
+ } else {
46
+ positional.push(arg);
47
+ }
48
+ }
49
+ return { command, positional, flags };
50
+ }
51
+ function getConfig(parsed) {
52
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i;
53
+ return {
54
+ baseUrl: (_b = (_a3 = parsed.flags["backend-url"]) != null ? _a3 : process.env.AOMI_BASE_URL) != null ? _b : "https://api.aomi.dev",
55
+ apiKey: (_c = parsed.flags["api-key"]) != null ? _c : process.env.AOMI_API_KEY,
56
+ namespace: (_e = (_d = parsed.flags["namespace"]) != null ? _d : process.env.AOMI_NAMESPACE) != null ? _e : "default",
57
+ model: (_f = parsed.flags["model"]) != null ? _f : process.env.AOMI_MODEL,
58
+ publicKey: (_g = parsed.flags["public-key"]) != null ? _g : process.env.AOMI_PUBLIC_KEY,
59
+ privateKey: (_h = parsed.flags["private-key"]) != null ? _h : process.env.PRIVATE_KEY,
60
+ chainRpcUrl: (_i = parsed.flags["rpc-url"]) != null ? _i : process.env.CHAIN_RPC_URL
61
+ };
62
+ }
63
+ function createRuntime(argv) {
64
+ const parsed = parseArgs(argv);
65
+ return {
66
+ parsed,
67
+ config: getConfig(parsed)
68
+ };
69
+ }
70
+
71
+ // src/cli/state.ts
72
+ import {
73
+ existsSync,
74
+ mkdirSync,
75
+ readFileSync,
76
+ readdirSync,
77
+ rmSync,
78
+ writeFileSync
79
+ } from "fs";
80
+ import { basename, join } from "path";
81
+ import { homedir, tmpdir } from "os";
82
+ var SESSION_FILE_PREFIX = "session-";
83
+ var SESSION_FILE_SUFFIX = ".json";
84
+ var _a;
85
+ var LEGACY_STATE_FILE = join(
86
+ (_a = process.env.XDG_RUNTIME_DIR) != null ? _a : tmpdir(),
87
+ "aomi-session.json"
88
+ );
89
+ var _a2;
90
+ var STATE_ROOT_DIR = (_a2 = process.env.AOMI_STATE_DIR) != null ? _a2 : join(homedir(), ".aomi");
91
+ var SESSIONS_DIR = join(STATE_ROOT_DIR, "sessions");
92
+ var ACTIVE_SESSION_FILE = join(STATE_ROOT_DIR, "active-session.txt");
93
+ function ensureStorageDirs() {
94
+ mkdirSync(SESSIONS_DIR, { recursive: true });
95
+ }
96
+ function parseSessionFileLocalId(filename) {
97
+ const match = filename.match(/^session-(\d+)\.json$/);
98
+ if (!match) return null;
99
+ const localId = parseInt(match[1], 10);
100
+ return Number.isNaN(localId) ? null : localId;
101
+ }
102
+ function toSessionFilePath(localId) {
103
+ return join(SESSIONS_DIR, `${SESSION_FILE_PREFIX}${localId}${SESSION_FILE_SUFFIX}`);
104
+ }
105
+ function toCliSessionState(stored) {
106
+ return {
107
+ sessionId: stored.sessionId,
108
+ baseUrl: stored.baseUrl,
109
+ namespace: stored.namespace,
110
+ model: stored.model,
111
+ apiKey: stored.apiKey,
112
+ publicKey: stored.publicKey,
113
+ pendingTxs: stored.pendingTxs,
114
+ signedTxs: stored.signedTxs
115
+ };
116
+ }
117
+ function readStoredSession(path) {
118
+ var _a3;
119
+ try {
120
+ const raw = readFileSync(path, "utf-8");
121
+ const parsed = JSON.parse(raw);
122
+ if (typeof parsed.sessionId !== "string" || typeof parsed.baseUrl !== "string") {
123
+ return null;
124
+ }
125
+ const fallbackLocalId = (_a3 = parseSessionFileLocalId(basename(path))) != null ? _a3 : 0;
126
+ return {
127
+ sessionId: parsed.sessionId,
128
+ baseUrl: parsed.baseUrl,
129
+ namespace: parsed.namespace,
130
+ model: parsed.model,
131
+ apiKey: parsed.apiKey,
132
+ publicKey: parsed.publicKey,
133
+ pendingTxs: parsed.pendingTxs,
134
+ signedTxs: parsed.signedTxs,
135
+ localId: typeof parsed.localId === "number" && parsed.localId > 0 ? parsed.localId : fallbackLocalId,
136
+ createdAt: typeof parsed.createdAt === "number" && parsed.createdAt > 0 ? parsed.createdAt : Date.now(),
137
+ updatedAt: typeof parsed.updatedAt === "number" && parsed.updatedAt > 0 ? parsed.updatedAt : Date.now()
138
+ };
139
+ } catch (e) {
140
+ return null;
141
+ }
142
+ }
143
+ function readActiveLocalId() {
144
+ try {
145
+ if (!existsSync(ACTIVE_SESSION_FILE)) return null;
146
+ const raw = readFileSync(ACTIVE_SESSION_FILE, "utf-8").trim();
147
+ if (!raw) return null;
148
+ const parsed = parseInt(raw, 10);
149
+ return Number.isNaN(parsed) ? null : parsed;
150
+ } catch (e) {
151
+ return null;
152
+ }
153
+ }
154
+ function writeActiveLocalId(localId) {
155
+ try {
156
+ if (localId === null) {
157
+ if (existsSync(ACTIVE_SESSION_FILE)) {
158
+ rmSync(ACTIVE_SESSION_FILE);
159
+ }
160
+ return;
161
+ }
162
+ ensureStorageDirs();
163
+ writeFileSync(ACTIVE_SESSION_FILE, String(localId));
164
+ } catch (e) {
165
+ }
166
+ }
167
+ function readAllStoredSessions() {
168
+ try {
169
+ ensureStorageDirs();
170
+ const filenames = readdirSync(SESSIONS_DIR).map((name) => ({ name, localId: parseSessionFileLocalId(name) })).filter(
171
+ (entry) => entry.localId !== null
172
+ ).sort((a, b) => a.localId - b.localId);
173
+ const sessions = [];
174
+ for (const entry of filenames) {
175
+ const path = join(SESSIONS_DIR, entry.name);
176
+ const stored = readStoredSession(path);
177
+ if (stored) {
178
+ sessions.push(stored);
179
+ }
180
+ }
181
+ return sessions;
182
+ } catch (e) {
183
+ return [];
184
+ }
185
+ }
186
+ function getNextLocalId(sessions) {
187
+ const maxLocalId = sessions.reduce((max, session) => {
188
+ return session.localId > max ? session.localId : max;
189
+ }, 0);
190
+ return maxLocalId + 1;
191
+ }
192
+ var _migrationDone = false;
193
+ function migrateLegacyStateIfNeeded() {
194
+ if (_migrationDone) return;
195
+ _migrationDone = true;
196
+ if (!existsSync(LEGACY_STATE_FILE)) return;
197
+ const existing = readAllStoredSessions();
198
+ if (existing.length > 0) {
199
+ return;
200
+ }
201
+ try {
202
+ const raw = readFileSync(LEGACY_STATE_FILE, "utf-8");
203
+ const legacy = JSON.parse(raw);
204
+ if (!legacy.sessionId || !legacy.baseUrl) {
205
+ return;
206
+ }
207
+ const now = Date.now();
208
+ const migrated = __spreadProps(__spreadValues({}, legacy), {
209
+ localId: 1,
210
+ createdAt: now,
211
+ updatedAt: now
212
+ });
213
+ ensureStorageDirs();
214
+ writeFileSync(toSessionFilePath(1), JSON.stringify(migrated, null, 2));
215
+ writeActiveLocalId(1);
216
+ rmSync(LEGACY_STATE_FILE);
217
+ } catch (e) {
218
+ }
219
+ }
220
+ function resolveStoredSession(selector, sessions) {
221
+ var _a3, _b;
222
+ const trimmed = selector.trim();
223
+ if (!trimmed) return null;
224
+ const localMatch = trimmed.match(/^(?:session-)?(\d+)$/);
225
+ if (localMatch) {
226
+ const localId = parseInt(localMatch[1], 10);
227
+ if (!Number.isNaN(localId)) {
228
+ return (_a3 = sessions.find((session) => session.localId === localId)) != null ? _a3 : null;
229
+ }
230
+ }
231
+ return (_b = sessions.find((session) => session.sessionId === trimmed)) != null ? _b : null;
232
+ }
233
+ function toStoredSessionRecord(stored) {
234
+ return {
235
+ localId: stored.localId,
236
+ sessionId: stored.sessionId,
237
+ path: toSessionFilePath(stored.localId),
238
+ createdAt: stored.createdAt,
239
+ updatedAt: stored.updatedAt,
240
+ state: toCliSessionState(stored)
241
+ };
242
+ }
243
+ function getActiveStateFilePath() {
244
+ migrateLegacyStateIfNeeded();
245
+ const sessions = readAllStoredSessions();
246
+ const activeLocalId = readActiveLocalId();
247
+ if (activeLocalId === null) return null;
248
+ const active = sessions.find((session) => session.localId === activeLocalId);
249
+ return active ? toSessionFilePath(active.localId) : null;
250
+ }
251
+ function listStoredSessions() {
252
+ migrateLegacyStateIfNeeded();
253
+ return readAllStoredSessions().map(toStoredSessionRecord);
254
+ }
255
+ function setActiveSession(selector) {
256
+ migrateLegacyStateIfNeeded();
257
+ const sessions = readAllStoredSessions();
258
+ const target = resolveStoredSession(selector, sessions);
259
+ if (!target) return null;
260
+ writeActiveLocalId(target.localId);
261
+ return toStoredSessionRecord(target);
262
+ }
263
+ function deleteStoredSession(selector) {
264
+ var _a3, _b;
265
+ migrateLegacyStateIfNeeded();
266
+ const sessions = readAllStoredSessions();
267
+ const target = resolveStoredSession(selector, sessions);
268
+ if (!target) return null;
269
+ const targetPath = toSessionFilePath(target.localId);
270
+ try {
271
+ if (existsSync(targetPath)) {
272
+ rmSync(targetPath);
273
+ }
274
+ } catch (e) {
275
+ return null;
276
+ }
277
+ const activeLocalId = readActiveLocalId();
278
+ if (activeLocalId === target.localId) {
279
+ const remaining = readAllStoredSessions().sort((a, b) => b.updatedAt - a.updatedAt);
280
+ writeActiveLocalId((_b = (_a3 = remaining[0]) == null ? void 0 : _a3.localId) != null ? _b : null);
281
+ }
282
+ return toStoredSessionRecord(target);
283
+ }
284
+ function readState() {
285
+ var _a3;
286
+ migrateLegacyStateIfNeeded();
287
+ const sessions = readAllStoredSessions();
288
+ if (sessions.length === 0) return null;
289
+ const activeLocalId = readActiveLocalId();
290
+ if (activeLocalId === null) {
291
+ return null;
292
+ }
293
+ const active = (_a3 = sessions.find((session) => session.localId === activeLocalId)) != null ? _a3 : null;
294
+ if (!active) {
295
+ writeActiveLocalId(null);
296
+ return null;
297
+ }
298
+ return toCliSessionState(active);
299
+ }
300
+ function writeState(state) {
301
+ var _a3, _b;
302
+ migrateLegacyStateIfNeeded();
303
+ ensureStorageDirs();
304
+ const sessions = readAllStoredSessions();
305
+ const activeLocalId = readActiveLocalId();
306
+ const existingBySessionId = sessions.find(
307
+ (session) => session.sessionId === state.sessionId
308
+ );
309
+ const existingByActive = activeLocalId !== null ? sessions.find((session) => session.localId === activeLocalId) : void 0;
310
+ const existing = existingBySessionId != null ? existingBySessionId : existingByActive;
311
+ const now = Date.now();
312
+ const localId = (_a3 = existing == null ? void 0 : existing.localId) != null ? _a3 : getNextLocalId(sessions);
313
+ const createdAt = (_b = existing == null ? void 0 : existing.createdAt) != null ? _b : now;
314
+ const payload = __spreadProps(__spreadValues({}, state), {
315
+ localId,
316
+ createdAt,
317
+ updatedAt: now
318
+ });
319
+ writeFileSync(toSessionFilePath(localId), JSON.stringify(payload, null, 2));
320
+ writeActiveLocalId(localId);
321
+ }
322
+ function clearState() {
323
+ migrateLegacyStateIfNeeded();
324
+ writeActiveLocalId(null);
325
+ }
326
+ function getNextTxId(state) {
327
+ var _a3, _b;
328
+ const allIds = [...(_a3 = state.pendingTxs) != null ? _a3 : [], ...(_b = state.signedTxs) != null ? _b : []].map((tx) => {
329
+ const match = tx.id.match(/^tx-(\d+)$/);
330
+ return match ? parseInt(match[1], 10) : 0;
331
+ });
332
+ const max = allIds.length > 0 ? Math.max(...allIds) : 0;
333
+ return `tx-${max + 1}`;
334
+ }
335
+ function addPendingTx(state, tx) {
336
+ if (!state.pendingTxs) state.pendingTxs = [];
337
+ const pending = __spreadProps(__spreadValues({}, tx), {
338
+ id: getNextTxId(state)
339
+ });
340
+ state.pendingTxs.push(pending);
341
+ writeState(state);
342
+ return pending;
343
+ }
344
+ function removePendingTx(state, id) {
345
+ if (!state.pendingTxs) return null;
346
+ const idx = state.pendingTxs.findIndex((tx) => tx.id === id);
347
+ if (idx === -1) return null;
348
+ const [removed] = state.pendingTxs.splice(idx, 1);
349
+ writeState(state);
350
+ return removed;
351
+ }
352
+ function addSignedTx(state, tx) {
353
+ if (!state.signedTxs) state.signedTxs = [];
354
+ state.signedTxs.push(tx);
355
+ writeState(state);
356
+ }
357
+
358
+ // src/cli/output.ts
359
+ var DIM = "\x1B[2m";
360
+ var CYAN = "\x1B[36m";
361
+ var YELLOW = "\x1B[33m";
362
+ var GREEN = "\x1B[32m";
363
+ var RESET = "\x1B[0m";
364
+ function printDataFileLocation() {
365
+ const activeFile = getActiveStateFilePath();
366
+ if (activeFile) {
367
+ console.log(`Data stored at ${activeFile} \u{1F4DD}`);
368
+ return;
369
+ }
370
+ console.log(`Data stored under ${STATE_ROOT_DIR} \u{1F4DD}`);
371
+ }
372
+ function printToolUpdate(event) {
373
+ var _a3;
374
+ const name = getToolNameFromEvent(event);
375
+ const status = (_a3 = event.status) != null ? _a3 : "running";
376
+ console.log(`${DIM}\u{1F527} [tool] ${name}: ${status}${RESET}`);
377
+ }
378
+ function printToolComplete(event) {
379
+ const name = getToolNameFromEvent(event);
380
+ const result = getToolResultFromEvent(event);
381
+ const line = formatToolResultLine(name, result);
382
+ console.log(line);
383
+ }
384
+ function printToolResultLine(name, result) {
385
+ console.log(formatToolResultLine(name, result));
386
+ }
387
+ function getToolNameFromEvent(event) {
388
+ var _a3, _b;
389
+ return (_b = (_a3 = event.tool_name) != null ? _a3 : event.name) != null ? _b : "unknown";
390
+ }
391
+ function getToolResultFromEvent(event) {
392
+ var _a3;
393
+ return (_a3 = event.result) != null ? _a3 : event.output;
394
+ }
395
+ function toToolResultKey(name, result) {
396
+ return `${name}
397
+ ${result != null ? result : ""}`;
398
+ }
399
+ function getMessageToolResults(messages, startAt = 0) {
400
+ const results = [];
401
+ for (let i = startAt; i < messages.length; i++) {
402
+ const toolResult = messages[i].tool_result;
403
+ if (!toolResult) {
404
+ continue;
405
+ }
406
+ const [name, result] = toolResult;
407
+ if (!name || typeof result !== "string") {
408
+ continue;
409
+ }
410
+ results.push({ name, result });
411
+ }
412
+ return results;
413
+ }
414
+ function isAlwaysVisibleTool(name) {
415
+ const normalized = name.toLowerCase();
416
+ if (normalized.includes("encode_and_simulate") || normalized.includes("encode-and-simulate") || normalized.includes("encode_and_view") || normalized.includes("encode-and-view")) {
417
+ return true;
418
+ }
419
+ if (normalized.startsWith("simulate ")) {
420
+ return true;
421
+ }
422
+ return false;
423
+ }
424
+ function printNewAgentMessages(messages, lastPrintedCount) {
425
+ const agentMessages = messages.filter(
426
+ (message) => message.sender === "agent" || message.sender === "assistant"
427
+ );
428
+ let handled = lastPrintedCount;
429
+ for (let i = lastPrintedCount; i < agentMessages.length; i++) {
430
+ const message = agentMessages[i];
431
+ if (message.is_streaming) {
432
+ break;
433
+ }
434
+ if (message.content) {
435
+ console.log(`${CYAN}\u{1F916} ${message.content}${RESET}`);
436
+ }
437
+ handled = i + 1;
438
+ }
439
+ return handled;
440
+ }
441
+ function formatLogContent(content) {
442
+ if (!content) return null;
443
+ const trimmed = content.trim();
444
+ return trimmed.length > 0 ? trimmed : null;
445
+ }
446
+ function formatToolResultPreview(result, maxLength = 200) {
447
+ const normalized = result.replace(/\s+/g, " ").trim();
448
+ if (normalized.length <= maxLength) {
449
+ return normalized;
450
+ }
451
+ return `${normalized.slice(0, maxLength)}\u2026`;
452
+ }
453
+ function formatToolResultLine(name, result) {
454
+ if (!result) {
455
+ return `${GREEN}\u2714 [tool] ${name} done${RESET}`;
456
+ }
457
+ return `${GREEN}\u2714 [tool] ${name} \u2192 ${formatToolResultPreview(result, 120)}${RESET}`;
458
+ }
459
+
22
460
  // src/sse.ts
23
461
  function extractSseData(rawEvent) {
24
462
  const dataLines = rawEvent.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart());
@@ -86,13 +524,13 @@ function createSseSubscriber({
86
524
  stopped: false,
87
525
  listeners: /* @__PURE__ */ new Set([listener]),
88
526
  stop: (reason) => {
89
- var _a2;
527
+ var _a3;
90
528
  subscription.stopped = true;
91
529
  if (subscription.retryTimer) {
92
530
  clearTimeout(subscription.retryTimer);
93
531
  subscription.retryTimer = null;
94
532
  }
95
- (_a2 = subscription.abortController) == null ? void 0 : _a2.abort();
533
+ (_a3 = subscription.abortController) == null ? void 0 : _a3.abort();
96
534
  subscription.abortController = null;
97
535
  logger == null ? void 0 : logger.debug("[aomi][sse] stop", {
98
536
  sessionId,
@@ -115,7 +553,7 @@ function createSseSubscriber({
115
553
  }, delayMs);
116
554
  };
117
555
  const open = async () => {
118
- var _a2;
556
+ var _a3;
119
557
  if (subscription.stopped) return;
120
558
  if (subscription.retryTimer) {
121
559
  clearTimeout(subscription.retryTimer);
@@ -139,19 +577,19 @@ function createSseSubscriber({
139
577
  }
140
578
  subscription.retries = 0;
141
579
  await readSseStream(response.body, controller.signal, (data) => {
142
- var _a3, _b;
143
- let parsed2;
580
+ var _a4, _b;
581
+ let parsed;
144
582
  try {
145
- parsed2 = JSON.parse(data);
583
+ parsed = JSON.parse(data);
146
584
  } catch (error) {
147
585
  for (const item of subscription.listeners) {
148
- (_a3 = item.onError) == null ? void 0 : _a3.call(item, error);
586
+ (_a4 = item.onError) == null ? void 0 : _a4.call(item, error);
149
587
  }
150
588
  return;
151
589
  }
152
590
  for (const item of subscription.listeners) {
153
591
  try {
154
- item.onUpdate(parsed2);
592
+ item.onUpdate(parsed);
155
593
  } catch (error) {
156
594
  (_b = item.onError) == null ? void 0 : _b.call(item, error);
157
595
  }
@@ -166,7 +604,7 @@ function createSseSubscriber({
166
604
  } catch (error) {
167
605
  if (!controller.signal.aborted && !subscription.stopped) {
168
606
  for (const item of subscription.listeners) {
169
- (_a2 = item.onError) == null ? void 0 : _a2.call(item, error);
607
+ (_a3 = item.onError) == null ? void 0 : _a3.call(item, error);
170
608
  }
171
609
  }
172
610
  }
@@ -260,8 +698,8 @@ var AomiClient = class {
260
698
  * Send a chat message and return updated session state.
261
699
  */
262
700
  async sendMessage(sessionId, message, options) {
263
- var _a2, _b;
264
- const namespace = (_a2 = options == null ? void 0 : options.namespace) != null ? _a2 : "default";
701
+ var _a3, _b;
702
+ const namespace = (_a3 = options == null ? void 0 : options.namespace) != null ? _a3 : "default";
265
703
  const apiKey = (_b = options == null ? void 0 : options.apiKey) != null ? _b : this.apiKey;
266
704
  const payload = { message, namespace };
267
705
  if (options == null ? void 0 : options.publicKey) {
@@ -439,12 +877,12 @@ var AomiClient = class {
439
877
  * Get available namespaces.
440
878
  */
441
879
  async getNamespaces(sessionId, options) {
442
- var _a2;
880
+ var _a3;
443
881
  const url = new URL("/api/control/namespaces", this.baseUrl);
444
882
  if (options == null ? void 0 : options.publicKey) {
445
883
  url.searchParams.set("public_key", options.publicKey);
446
884
  }
447
- const apiKey = (_a2 = options == null ? void 0 : options.apiKey) != null ? _a2 : this.apiKey;
885
+ const apiKey = (_a3 = options == null ? void 0 : options.apiKey) != null ? _a3 : this.apiKey;
448
886
  const headers = new Headers(withSessionHeader(sessionId));
449
887
  if (apiKey) {
450
888
  headers.set(API_KEY_HEADER, apiKey);
@@ -458,10 +896,16 @@ var AomiClient = class {
458
896
  /**
459
897
  * Get available models.
460
898
  */
461
- async getModels(sessionId) {
899
+ async getModels(sessionId, options) {
900
+ var _a3;
462
901
  const url = new URL("/api/control/models", this.baseUrl);
902
+ const apiKey = (_a3 = options == null ? void 0 : options.apiKey) != null ? _a3 : this.apiKey;
903
+ const headers = new Headers(withSessionHeader(sessionId));
904
+ if (apiKey) {
905
+ headers.set(API_KEY_HEADER, apiKey);
906
+ }
463
907
  const response = await fetch(url.toString(), {
464
- headers: withSessionHeader(sessionId)
908
+ headers
465
909
  });
466
910
  if (!response.ok) {
467
911
  throw new Error(`Failed to get models: HTTP ${response.status}`);
@@ -472,8 +916,8 @@ var AomiClient = class {
472
916
  * Set the model for a session.
473
917
  */
474
918
  async setModel(sessionId, rig, options) {
475
- var _a2;
476
- const apiKey = (_a2 = options == null ? void 0 : options.apiKey) != null ? _a2 : this.apiKey;
919
+ var _a3;
920
+ const apiKey = (_a3 = options == null ? void 0 : options.apiKey) != null ? _a3 : this.apiKey;
477
921
  const payload = { rig };
478
922
  if (options == null ? void 0 : options.namespace) {
479
923
  payload.namespace = options.namespace;
@@ -570,11 +1014,11 @@ function isAsyncCallback(event) {
570
1014
 
571
1015
  // src/event-unwrap.ts
572
1016
  function unwrapSystemEvent(event) {
573
- var _a2;
1017
+ var _a3;
574
1018
  if (isInlineCall(event)) {
575
1019
  return {
576
1020
  type: event.InlineCall.type,
577
- payload: (_a2 = event.InlineCall.payload) != null ? _a2 : event.InlineCall
1021
+ payload: (_a3 = event.InlineCall.payload) != null ? _a3 : event.InlineCall
578
1022
  };
579
1023
  }
580
1024
  if (isSystemNotice(event)) {
@@ -605,10 +1049,10 @@ function asRecord(value) {
605
1049
  return value;
606
1050
  }
607
1051
  function getToolArgs(payload) {
608
- var _a2;
1052
+ var _a3;
609
1053
  const root = asRecord(payload);
610
1054
  const nestedArgs = asRecord(root == null ? void 0 : root.args);
611
- return (_a2 = nestedArgs != null ? nestedArgs : root) != null ? _a2 : {};
1055
+ return (_a3 = nestedArgs != null ? nestedArgs : root) != null ? _a3 : {};
612
1056
  }
613
1057
  function parseChainId(value) {
614
1058
  if (typeof value === "number" && Number.isFinite(value)) return value;
@@ -619,11 +1063,11 @@ function parseChainId(value) {
619
1063
  const parsedHex = Number.parseInt(trimmed.slice(2), 16);
620
1064
  return Number.isFinite(parsedHex) ? parsedHex : void 0;
621
1065
  }
622
- const parsed2 = Number.parseInt(trimmed, 10);
623
- return Number.isFinite(parsed2) ? parsed2 : void 0;
1066
+ const parsed = Number.parseInt(trimmed, 10);
1067
+ return Number.isFinite(parsed) ? parsed : void 0;
624
1068
  }
625
1069
  function normalizeTxPayload(payload) {
626
- var _a2, _b, _c;
1070
+ var _a3, _b, _c;
627
1071
  const root = asRecord(payload);
628
1072
  const args = getToolArgs(payload);
629
1073
  const ctx = asRecord(root == null ? void 0 : root.ctx);
@@ -632,19 +1076,19 @@ function normalizeTxPayload(payload) {
632
1076
  const valueRaw = args.value;
633
1077
  const value = typeof valueRaw === "string" ? valueRaw : typeof valueRaw === "number" && Number.isFinite(valueRaw) ? String(Math.trunc(valueRaw)) : void 0;
634
1078
  const data = typeof args.data === "string" ? args.data : void 0;
635
- const chainId = (_c = (_b = (_a2 = parseChainId(args.chainId)) != null ? _a2 : parseChainId(args.chain_id)) != null ? _b : parseChainId(ctx == null ? void 0 : ctx.user_chain_id)) != null ? _c : parseChainId(ctx == null ? void 0 : ctx.userChainId);
1079
+ const chainId = (_c = (_b = (_a3 = parseChainId(args.chainId)) != null ? _a3 : parseChainId(args.chain_id)) != null ? _b : parseChainId(ctx == null ? void 0 : ctx.user_chain_id)) != null ? _c : parseChainId(ctx == null ? void 0 : ctx.userChainId);
636
1080
  return { to, value, data, chainId };
637
1081
  }
638
1082
  function normalizeEip712Payload(payload) {
639
- var _a2;
1083
+ var _a3;
640
1084
  const args = getToolArgs(payload);
641
- const typedDataRaw = (_a2 = args.typed_data) != null ? _a2 : args.typedData;
1085
+ const typedDataRaw = (_a3 = args.typed_data) != null ? _a3 : args.typedData;
642
1086
  let typedData;
643
1087
  if (typeof typedDataRaw === "string") {
644
1088
  try {
645
- const parsed2 = JSON.parse(typedDataRaw);
646
- if (parsed2 && typeof parsed2 === "object" && !Array.isArray(parsed2)) {
647
- typedData = parsed2;
1089
+ const parsed = JSON.parse(typedDataRaw);
1090
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
1091
+ typedData = parsed;
648
1092
  }
649
1093
  } catch (e) {
650
1094
  typedData = void 0;
@@ -659,7 +1103,7 @@ function normalizeEip712Payload(payload) {
659
1103
  // src/session.ts
660
1104
  var Session = class extends TypedEventEmitter {
661
1105
  constructor(clientOrOptions, sessionOptions) {
662
- var _a2, _b, _c;
1106
+ var _a3, _b, _c;
663
1107
  super();
664
1108
  // Internal state
665
1109
  this.pollTimer = null;
@@ -672,7 +1116,7 @@ var Session = class extends TypedEventEmitter {
672
1116
  // For send() blocking behavior
673
1117
  this.pendingResolve = null;
674
1118
  this.client = clientOrOptions instanceof AomiClient ? clientOrOptions : new AomiClient(clientOrOptions);
675
- this.sessionId = (_a2 = sessionOptions == null ? void 0 : sessionOptions.sessionId) != null ? _a2 : crypto.randomUUID();
1119
+ this.sessionId = (_a3 = sessionOptions == null ? void 0 : sessionOptions.sessionId) != null ? _a3 : crypto.randomUUID();
676
1120
  this.namespace = (_b = sessionOptions == null ? void 0 : sessionOptions.namespace) != null ? _b : "default";
677
1121
  this.publicKey = sessionOptions == null ? void 0 : sessionOptions.publicKey;
678
1122
  this.apiKey = sessionOptions == null ? void 0 : sessionOptions.apiKey;
@@ -743,14 +1187,14 @@ var Session = class extends TypedEventEmitter {
743
1187
  * Sends the result to the backend and resumes polling.
744
1188
  */
745
1189
  async resolve(requestId, result) {
746
- var _a2;
1190
+ var _a3;
747
1191
  const req = this.removeWalletRequest(requestId);
748
1192
  if (!req) {
749
1193
  throw new Error(`No pending wallet request with id "${requestId}"`);
750
1194
  }
751
1195
  if (req.kind === "transaction") {
752
1196
  await this.sendSystemEvent("wallet:tx_complete", {
753
- txHash: (_a2 = result.txHash) != null ? _a2 : "",
1197
+ txHash: (_a3 = result.txHash) != null ? _a3 : "",
754
1198
  status: "success",
755
1199
  amount: result.amount
756
1200
  });
@@ -811,11 +1255,11 @@ var Session = class extends TypedEventEmitter {
811
1255
  * The session cannot be used after closing.
812
1256
  */
813
1257
  close() {
814
- var _a2;
1258
+ var _a3;
815
1259
  if (this.closed) return;
816
1260
  this.closed = true;
817
1261
  this.stopPolling();
818
- (_a2 = this.unsubscribeSSE) == null ? void 0 : _a2.call(this);
1262
+ (_a3 = this.unsubscribeSSE) == null ? void 0 : _a3.call(this);
819
1263
  this.unsubscribeSSE = null;
820
1264
  this.resolvePending();
821
1265
  this.removeAllListeners();
@@ -843,23 +1287,23 @@ var Session = class extends TypedEventEmitter {
843
1287
  // Internal — Polling (ported from PollingController)
844
1288
  // ===========================================================================
845
1289
  startPolling() {
846
- var _a2;
1290
+ var _a3;
847
1291
  if (this.pollTimer || this.closed) return;
848
- (_a2 = this.logger) == null ? void 0 : _a2.debug("[session] polling started", this.sessionId);
1292
+ (_a3 = this.logger) == null ? void 0 : _a3.debug("[session] polling started", this.sessionId);
849
1293
  this.pollTimer = setInterval(() => {
850
1294
  void this.pollTick();
851
1295
  }, this.pollIntervalMs);
852
1296
  }
853
1297
  stopPolling() {
854
- var _a2;
1298
+ var _a3;
855
1299
  if (this.pollTimer) {
856
1300
  clearInterval(this.pollTimer);
857
1301
  this.pollTimer = null;
858
- (_a2 = this.logger) == null ? void 0 : _a2.debug("[session] polling stopped", this.sessionId);
1302
+ (_a3 = this.logger) == null ? void 0 : _a3.debug("[session] polling stopped", this.sessionId);
859
1303
  }
860
1304
  }
861
1305
  async pollTick() {
862
- var _a2;
1306
+ var _a3;
863
1307
  if (!this.pollTimer) return;
864
1308
  try {
865
1309
  const state = await this.client.fetchState(
@@ -875,7 +1319,7 @@ var Session = class extends TypedEventEmitter {
875
1319
  this.resolvePending();
876
1320
  }
877
1321
  } catch (error) {
878
- (_a2 = this.logger) == null ? void 0 : _a2.debug("[session] poll error", error);
1322
+ (_a3 = this.logger) == null ? void 0 : _a3.debug("[session] poll error", error);
879
1323
  this.emit("error", { error });
880
1324
  }
881
1325
  }
@@ -883,7 +1327,7 @@ var Session = class extends TypedEventEmitter {
883
1327
  // Internal — State Application
884
1328
  // ===========================================================================
885
1329
  applyState(state) {
886
- var _a2;
1330
+ var _a3;
887
1331
  if (state.messages) {
888
1332
  this._messages = state.messages;
889
1333
  this.emit("messages", this._messages);
@@ -891,12 +1335,12 @@ var Session = class extends TypedEventEmitter {
891
1335
  if (state.title) {
892
1336
  this._title = state.title;
893
1337
  }
894
- if ((_a2 = state.system_events) == null ? void 0 : _a2.length) {
1338
+ if ((_a3 = state.system_events) == null ? void 0 : _a3.length) {
895
1339
  this.dispatchSystemEvents(state.system_events);
896
1340
  }
897
1341
  }
898
1342
  dispatchSystemEvents(events) {
899
- var _a2;
1343
+ var _a3;
900
1344
  for (const event of events) {
901
1345
  const unwrapped = unwrapSystemEvent(event);
902
1346
  if (!unwrapped) continue;
@@ -907,7 +1351,7 @@ var Session = class extends TypedEventEmitter {
907
1351
  this.emit("wallet_tx_request", req);
908
1352
  }
909
1353
  } else if (unwrapped.type === "wallet_eip712_request") {
910
- const payload = normalizeEip712Payload((_a2 = unwrapped.payload) != null ? _a2 : {});
1354
+ const payload = normalizeEip712Payload((_a3 = unwrapped.payload) != null ? _a3 : {});
911
1355
  const req = this.enqueueWalletRequest("eip712_sign", payload);
912
1356
  this.emit("wallet_eip712_request", req);
913
1357
  } else if (unwrapped.type === "system_notice" || unwrapped.type === "system_error" || unwrapped.type === "async_callback") {
@@ -970,69 +1414,78 @@ var Session = class extends TypedEventEmitter {
970
1414
  }
971
1415
  };
972
1416
 
973
- // src/cli-state.ts
974
- import { readFileSync, writeFileSync, unlinkSync, existsSync } from "fs";
975
- import { join } from "path";
976
- import { tmpdir } from "os";
977
- var _a;
978
- var STATE_FILE = join(
979
- (_a = process.env.XDG_RUNTIME_DIR) != null ? _a : tmpdir(),
980
- "aomi-session.json"
981
- );
982
- function readState() {
983
- try {
984
- if (!existsSync(STATE_FILE)) return null;
985
- const raw = readFileSync(STATE_FILE, "utf-8");
986
- return JSON.parse(raw);
987
- } catch (e) {
988
- return null;
989
- }
990
- }
991
- function writeState(state) {
992
- writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
993
- }
994
- function clearState() {
995
- try {
996
- if (existsSync(STATE_FILE)) unlinkSync(STATE_FILE);
997
- } catch (e) {
1417
+ // src/cli/context.ts
1418
+ function getOrCreateSession(runtime) {
1419
+ const { config } = runtime;
1420
+ let state = readState();
1421
+ if (!state) {
1422
+ state = {
1423
+ sessionId: crypto.randomUUID(),
1424
+ baseUrl: config.baseUrl,
1425
+ namespace: config.namespace,
1426
+ apiKey: config.apiKey,
1427
+ publicKey: config.publicKey
1428
+ };
1429
+ writeState(state);
1430
+ } else {
1431
+ let changed = false;
1432
+ if (config.baseUrl !== state.baseUrl) {
1433
+ state.baseUrl = config.baseUrl;
1434
+ changed = true;
1435
+ }
1436
+ if (config.namespace !== state.namespace) {
1437
+ state.namespace = config.namespace;
1438
+ changed = true;
1439
+ }
1440
+ if (config.apiKey !== void 0 && config.apiKey !== state.apiKey) {
1441
+ state.apiKey = config.apiKey;
1442
+ changed = true;
1443
+ }
1444
+ if (config.publicKey !== void 0 && config.publicKey !== state.publicKey) {
1445
+ state.publicKey = config.publicKey;
1446
+ changed = true;
1447
+ }
1448
+ if (changed) writeState(state);
998
1449
  }
1450
+ const session = new Session(
1451
+ { baseUrl: state.baseUrl, apiKey: state.apiKey },
1452
+ {
1453
+ sessionId: state.sessionId,
1454
+ namespace: state.namespace,
1455
+ apiKey: state.apiKey,
1456
+ publicKey: state.publicKey,
1457
+ userState: state.publicKey ? {
1458
+ address: state.publicKey,
1459
+ chainId: 1,
1460
+ isConnected: true
1461
+ } : void 0
1462
+ }
1463
+ );
1464
+ return { session, state };
999
1465
  }
1000
- function getNextTxId(state) {
1001
- var _a2, _b;
1002
- const allIds = [
1003
- ...(_a2 = state.pendingTxs) != null ? _a2 : [],
1004
- ...(_b = state.signedTxs) != null ? _b : []
1005
- ].map((t) => {
1006
- const m = t.id.match(/^tx-(\d+)$/);
1007
- return m ? parseInt(m[1], 10) : 0;
1466
+ function createControlClient(runtime) {
1467
+ return new AomiClient({
1468
+ baseUrl: runtime.config.baseUrl,
1469
+ apiKey: runtime.config.apiKey
1008
1470
  });
1009
- const max = allIds.length > 0 ? Math.max(...allIds) : 0;
1010
- return `tx-${max + 1}`;
1011
1471
  }
1012
- function addPendingTx(state, tx) {
1013
- if (!state.pendingTxs) state.pendingTxs = [];
1014
- const pending = __spreadProps(__spreadValues({}, tx), {
1015
- id: getNextTxId(state)
1472
+ async function applyModelSelection(session, state, model) {
1473
+ await session.client.setModel(state.sessionId, model, {
1474
+ namespace: state.namespace,
1475
+ apiKey: state.apiKey
1016
1476
  });
1017
- state.pendingTxs.push(pending);
1477
+ state.model = model;
1018
1478
  writeState(state);
1019
- return pending;
1020
1479
  }
1021
- function removePendingTx(state, id) {
1022
- if (!state.pendingTxs) return null;
1023
- const idx = state.pendingTxs.findIndex((t) => t.id === id);
1024
- if (idx === -1) return null;
1025
- const [removed] = state.pendingTxs.splice(idx, 1);
1026
- writeState(state);
1027
- return removed;
1028
- }
1029
- function addSignedTx(state, tx) {
1030
- if (!state.signedTxs) state.signedTxs = [];
1031
- state.signedTxs.push(tx);
1032
- writeState(state);
1480
+ async function applyRequestedModelIfPresent(runtime, session, state) {
1481
+ const requestedModel = runtime.config.model;
1482
+ if (!requestedModel || requestedModel === state.model) {
1483
+ return;
1484
+ }
1485
+ await applyModelSelection(session, state, requestedModel);
1033
1486
  }
1034
1487
 
1035
- // src/cli.ts
1488
+ // src/cli/errors.ts
1036
1489
  var CliExit = class extends Error {
1037
1490
  constructor(code) {
1038
1491
  super();
@@ -1040,217 +1493,108 @@ var CliExit = class extends Error {
1040
1493
  }
1041
1494
  };
1042
1495
  function fatal(message) {
1043
- console.error(message);
1044
- throw new CliExit(1);
1045
- }
1046
- function printDataFileLocation() {
1047
- console.log(`Data stored at ${STATE_FILE} \u{1F4DD}`);
1048
- }
1049
- function parseArgs(argv) {
1050
- const raw = argv.slice(2);
1051
- const command = raw[0] && !raw[0].startsWith("--") ? raw[0] : void 0;
1052
- const rest = command ? raw.slice(1) : raw;
1053
- const positional = [];
1054
- const flags = {};
1055
- for (let i = 0; i < rest.length; i++) {
1056
- const arg = rest[i];
1057
- if (arg.startsWith("--") && arg.includes("=")) {
1058
- const [key, ...val] = arg.slice(2).split("=");
1059
- flags[key] = val.join("=");
1060
- } else if (arg.startsWith("--")) {
1061
- const key = arg.slice(2);
1062
- const next = rest[i + 1];
1063
- if (next && !next.startsWith("-")) {
1064
- flags[key] = next;
1065
- i++;
1066
- } else {
1067
- flags[key] = "true";
1068
- }
1069
- } else if (arg.startsWith("-") && arg.length === 2) {
1070
- flags[arg.slice(1)] = "true";
1071
- } else {
1072
- positional.push(arg);
1073
- }
1496
+ const RED = "\x1B[31m";
1497
+ const DIM3 = "\x1B[2m";
1498
+ const RESET3 = "\x1B[0m";
1499
+ const lines = message.split("\n");
1500
+ const [headline, ...details] = lines;
1501
+ console.error(`${RED}\u274C ${headline}${RESET3}`);
1502
+ for (const detail of details) {
1503
+ if (!detail.trim()) {
1504
+ console.error("");
1505
+ continue;
1506
+ }
1507
+ console.error(`${DIM3}${detail}${RESET3}`);
1074
1508
  }
1075
- return { command, positional, flags };
1076
- }
1077
- var parsed = parseArgs(process.argv);
1078
- function getConfig() {
1079
- var _a2, _b, _c, _d, _e, _f, _g, _h;
1080
- return {
1081
- baseUrl: (_b = (_a2 = parsed.flags["backend-url"]) != null ? _a2 : process.env.AOMI_BASE_URL) != null ? _b : "https://api.aomi.dev",
1082
- apiKey: (_c = parsed.flags["api-key"]) != null ? _c : process.env.AOMI_API_KEY,
1083
- namespace: (_e = (_d = parsed.flags["namespace"]) != null ? _d : process.env.AOMI_NAMESPACE) != null ? _e : "default",
1084
- publicKey: (_f = parsed.flags["public-key"]) != null ? _f : process.env.AOMI_PUBLIC_KEY,
1085
- privateKey: (_g = parsed.flags["private-key"]) != null ? _g : process.env.PRIVATE_KEY,
1086
- chainRpcUrl: (_h = parsed.flags["rpc-url"]) != null ? _h : process.env.CHAIN_RPC_URL
1087
- };
1088
- }
1089
- function getOrCreateSession() {
1090
- const config = getConfig();
1091
- let state = readState();
1092
- if (!state) {
1093
- state = {
1094
- sessionId: crypto.randomUUID(),
1095
- baseUrl: config.baseUrl,
1096
- namespace: config.namespace,
1097
- apiKey: config.apiKey,
1098
- publicKey: config.publicKey
1099
- };
1100
- writeState(state);
1101
- } else {
1102
- let changed = false;
1103
- if (config.baseUrl && config.baseUrl !== state.baseUrl) {
1104
- state.baseUrl = config.baseUrl;
1105
- changed = true;
1106
- }
1107
- if (config.namespace && config.namespace !== state.namespace) {
1108
- state.namespace = config.namespace;
1109
- changed = true;
1110
- }
1111
- if (config.apiKey !== void 0 && config.apiKey !== state.apiKey) {
1112
- state.apiKey = config.apiKey;
1113
- changed = true;
1114
- }
1115
- if (config.publicKey !== void 0 && config.publicKey !== state.publicKey) {
1116
- state.publicKey = config.publicKey;
1117
- changed = true;
1118
- }
1119
- if (changed) writeState(state);
1120
- }
1121
- const session = new Session(
1122
- { baseUrl: state.baseUrl, apiKey: state.apiKey },
1123
- {
1124
- sessionId: state.sessionId,
1125
- namespace: state.namespace,
1126
- apiKey: state.apiKey,
1127
- publicKey: state.publicKey,
1128
- userState: state.publicKey ? {
1129
- address: state.publicKey,
1130
- chainId: 1,
1131
- isConnected: true
1132
- } : void 0
1133
- }
1134
- );
1135
- return { session, state };
1509
+ throw new CliExit(1);
1136
1510
  }
1137
- function walletRequestToPendingTx(req) {
1138
- if (req.kind === "transaction") {
1139
- const p2 = req.payload;
1511
+
1512
+ // src/cli/transactions.ts
1513
+ function walletRequestToPendingTx(request) {
1514
+ if (request.kind === "transaction") {
1515
+ const payload2 = request.payload;
1140
1516
  return {
1141
1517
  kind: "transaction",
1142
- to: p2.to,
1143
- value: p2.value,
1144
- data: p2.data,
1145
- chainId: p2.chainId,
1146
- timestamp: req.timestamp,
1147
- payload: req.payload
1518
+ to: payload2.to,
1519
+ value: payload2.value,
1520
+ data: payload2.data,
1521
+ chainId: payload2.chainId,
1522
+ timestamp: request.timestamp,
1523
+ payload: request.payload
1148
1524
  };
1149
1525
  }
1150
- const p = req.payload;
1526
+ const payload = request.payload;
1151
1527
  return {
1152
1528
  kind: "eip712_sign",
1153
- description: p.description,
1154
- timestamp: req.timestamp,
1155
- payload: req.payload
1529
+ description: payload.description,
1530
+ timestamp: request.timestamp,
1531
+ payload: request.payload
1156
1532
  };
1157
1533
  }
1158
1534
  function formatTxLine(tx, prefix) {
1159
- var _a2;
1535
+ var _a3;
1160
1536
  const parts = [`${prefix} ${tx.id}`];
1161
1537
  if (tx.kind === "transaction") {
1162
- parts.push(`to: ${(_a2 = tx.to) != null ? _a2 : "?"}`);
1538
+ parts.push(`to: ${(_a3 = tx.to) != null ? _a3 : "?"}`);
1163
1539
  if (tx.value) parts.push(`value: ${tx.value}`);
1164
1540
  if (tx.chainId) parts.push(`chain: ${tx.chainId}`);
1165
1541
  if (tx.data) parts.push(`data: ${tx.data.slice(0, 20)}...`);
1166
1542
  } else {
1167
- parts.push(`eip712`);
1543
+ parts.push("eip712");
1168
1544
  if (tx.description) parts.push(tx.description);
1169
1545
  }
1170
1546
  parts.push(`(${new Date(tx.timestamp).toLocaleTimeString()})`);
1171
1547
  return parts.join(" ");
1172
1548
  }
1173
- var DIM = "\x1B[2m";
1174
- var CYAN = "\x1B[36m";
1175
- var YELLOW = "\x1B[33m";
1176
- var GREEN = "\x1B[32m";
1177
- var RESET = "\x1B[0m";
1178
- function printToolUpdate(event) {
1179
- var _a2, _b, _c;
1180
- const name = (_b = (_a2 = event.tool_name) != null ? _a2 : event.name) != null ? _b : "unknown";
1181
- const status = (_c = event.status) != null ? _c : "running";
1182
- console.log(`${DIM}\u{1F527} [tool] ${name}: ${status}${RESET}`);
1183
- }
1184
- function printToolComplete(event) {
1185
- var _a2, _b, _c;
1186
- const name = (_b = (_a2 = event.tool_name) != null ? _a2 : event.name) != null ? _b : "unknown";
1187
- const result = (_c = event.result) != null ? _c : event.output;
1188
- const line = result ? `${GREEN}\u2714 [tool] ${name} \u2192 ${result.slice(0, 120)}${result.length > 120 ? "\u2026" : ""}${RESET}` : `${GREEN}\u2714 [tool] ${name} done${RESET}`;
1189
- console.log(line);
1190
- }
1191
- function printNewAgentMessages(messages, lastPrintedCount) {
1192
- const agentMessages = messages.filter(
1193
- (m) => m.sender === "agent" || m.sender === "assistant"
1194
- );
1195
- let handled = lastPrintedCount;
1196
- for (let i = lastPrintedCount; i < agentMessages.length; i++) {
1197
- const msg = agentMessages[i];
1198
- if (msg.is_streaming) {
1199
- break;
1200
- }
1201
- if (msg.content) {
1202
- console.log(`${CYAN}\u{1F916} ${msg.content}${RESET}`);
1203
- }
1204
- handled = i + 1;
1205
- }
1206
- return handled;
1207
- }
1208
- async function chatCommand() {
1209
- const message = parsed.positional.join(" ");
1549
+
1550
+ // src/cli/commands/chat.ts
1551
+ async function chatCommand(runtime) {
1552
+ const message = runtime.parsed.positional.join(" ");
1210
1553
  if (!message) {
1211
1554
  fatal("Usage: aomi chat <message>");
1212
1555
  }
1213
- const verbose = parsed.flags["verbose"] === "true" || parsed.flags["v"] === "true";
1214
- const { session, state } = getOrCreateSession();
1215
- if (state.publicKey) {
1216
- await session.client.sendSystemMessage(
1217
- session.sessionId,
1218
- JSON.stringify({
1219
- type: "wallet:state_changed",
1220
- payload: {
1221
- address: state.publicKey,
1222
- chainId: 1,
1223
- isConnected: true
1224
- }
1225
- })
1226
- );
1227
- }
1228
- const capturedRequests = [];
1229
- let printedAgentCount = 0;
1230
- session.on("wallet_tx_request", (req) => capturedRequests.push(req));
1231
- session.on("wallet_eip712_request", (req) => capturedRequests.push(req));
1556
+ const verbose = runtime.parsed.flags["verbose"] === "true" || runtime.parsed.flags["v"] === "true";
1557
+ const { session, state } = getOrCreateSession(runtime);
1232
1558
  try {
1233
- await session.sendAsync(message);
1234
- const allMsgs = session.getMessages();
1235
- let seedIdx = allMsgs.length;
1236
- for (let i = allMsgs.length - 1; i >= 0; i--) {
1237
- if (allMsgs[i].sender === "user") {
1238
- seedIdx = i;
1239
- break;
1240
- }
1559
+ await applyRequestedModelIfPresent(runtime, session, state);
1560
+ if (state.publicKey) {
1561
+ await session.client.sendSystemMessage(
1562
+ session.sessionId,
1563
+ JSON.stringify({
1564
+ type: "wallet:state_changed",
1565
+ payload: {
1566
+ address: state.publicKey,
1567
+ chainId: 1,
1568
+ isConnected: true
1569
+ }
1570
+ })
1571
+ );
1241
1572
  }
1242
- printedAgentCount = allMsgs.slice(0, seedIdx).filter(
1243
- (m) => m.sender === "agent" || m.sender === "assistant"
1244
- ).length;
1573
+ const capturedRequests = [];
1574
+ let printedAgentCount = 0;
1575
+ const seenToolResults = /* @__PURE__ */ new Set();
1576
+ session.on("wallet_tx_request", (request) => capturedRequests.push(request));
1577
+ session.on(
1578
+ "wallet_eip712_request",
1579
+ (request) => capturedRequests.push(request)
1580
+ );
1581
+ session.on("tool_complete", (event) => {
1582
+ const name = getToolNameFromEvent(event);
1583
+ const result = getToolResultFromEvent(event);
1584
+ const key = toToolResultKey(name, result);
1585
+ seenToolResults.add(key);
1586
+ if (verbose || isAlwaysVisibleTool(name)) {
1587
+ printToolComplete(event);
1588
+ }
1589
+ });
1590
+ session.on("tool_update", (event) => {
1591
+ if (verbose) {
1592
+ printToolUpdate(event);
1593
+ }
1594
+ });
1245
1595
  if (verbose) {
1246
- if (session.getIsProcessing()) {
1596
+ session.on("processing_start", () => {
1247
1597
  console.log(`${DIM}\u23F3 Processing\u2026${RESET}`);
1248
- }
1249
- printedAgentCount = printNewAgentMessages(allMsgs, printedAgentCount);
1250
- session.on("tool_update", (event) => printToolUpdate(event));
1251
- session.on("tool_complete", (event) => printToolComplete(event));
1252
- session.on("messages", (msgs) => {
1253
- printedAgentCount = printNewAgentMessages(msgs, printedAgentCount);
1254
1598
  });
1255
1599
  session.on("system_notice", ({ message: msg }) => {
1256
1600
  console.log(`${YELLOW}\u{1F4E2} ${msg}${RESET}`);
@@ -1259,6 +1603,27 @@ async function chatCommand() {
1259
1603
  console.log(`\x1B[31m\u274C ${msg}${RESET}`);
1260
1604
  });
1261
1605
  }
1606
+ await session.sendAsync(message);
1607
+ const allMessages = session.getMessages();
1608
+ let seedIdx = allMessages.length;
1609
+ for (let i = allMessages.length - 1; i >= 0; i--) {
1610
+ if (allMessages[i].sender === "user") {
1611
+ seedIdx = i;
1612
+ break;
1613
+ }
1614
+ }
1615
+ printedAgentCount = allMessages.slice(0, seedIdx).filter(
1616
+ (entry) => entry.sender === "agent" || entry.sender === "assistant"
1617
+ ).length;
1618
+ if (verbose) {
1619
+ printedAgentCount = printNewAgentMessages(
1620
+ allMessages,
1621
+ printedAgentCount
1622
+ );
1623
+ session.on("messages", (messages) => {
1624
+ printedAgentCount = printNewAgentMessages(messages, printedAgentCount);
1625
+ });
1626
+ }
1262
1627
  if (session.getIsProcessing()) {
1263
1628
  await new Promise((resolve) => {
1264
1629
  const checkWallet = () => {
@@ -1269,27 +1634,54 @@ async function chatCommand() {
1269
1634
  session.on("processing_end", () => resolve());
1270
1635
  });
1271
1636
  }
1637
+ const messageToolResults = getMessageToolResults(
1638
+ session.getMessages(),
1639
+ seedIdx + 1
1640
+ );
1272
1641
  if (verbose) {
1273
- printNewAgentMessages(session.getMessages(), printedAgentCount);
1642
+ for (const tool of messageToolResults) {
1643
+ const key = toToolResultKey(tool.name, tool.result);
1644
+ if (seenToolResults.has(key)) {
1645
+ continue;
1646
+ }
1647
+ printToolResultLine(tool.name, tool.result);
1648
+ }
1649
+ } else {
1650
+ for (const tool of messageToolResults) {
1651
+ const key = toToolResultKey(tool.name, tool.result);
1652
+ if (seenToolResults.has(key)) {
1653
+ continue;
1654
+ }
1655
+ if (isAlwaysVisibleTool(tool.name)) {
1656
+ printToolResultLine(tool.name, tool.result);
1657
+ }
1658
+ }
1659
+ }
1660
+ if (verbose) {
1661
+ printedAgentCount = printNewAgentMessages(
1662
+ session.getMessages(),
1663
+ printedAgentCount
1664
+ );
1274
1665
  console.log(`${DIM}\u2705 Done${RESET}`);
1275
1666
  }
1276
- for (const req of capturedRequests) {
1277
- const pending = addPendingTx(state, walletRequestToPendingTx(req));
1667
+ for (const request of capturedRequests) {
1668
+ const pending = addPendingTx(state, walletRequestToPendingTx(request));
1278
1669
  console.log(`\u26A1 Wallet request queued: ${pending.id}`);
1279
- if (req.kind === "transaction") {
1280
- const p = req.payload;
1281
- console.log(` to: ${p.to}`);
1282
- if (p.value) console.log(` value: ${p.value}`);
1283
- if (p.chainId) console.log(` chain: ${p.chainId}`);
1670
+ if (request.kind === "transaction") {
1671
+ const payload = request.payload;
1672
+ console.log(` to: ${payload.to}`);
1673
+ if (payload.value) console.log(` value: ${payload.value}`);
1674
+ if (payload.chainId) console.log(` chain: ${payload.chainId}`);
1284
1675
  } else {
1285
- const p = req.payload;
1286
- if (p.description) console.log(` desc: ${p.description}`);
1676
+ const payload = request.payload;
1677
+ if (payload.description) {
1678
+ console.log(` desc: ${payload.description}`);
1679
+ }
1287
1680
  }
1288
1681
  }
1289
1682
  if (!verbose) {
1290
- const messages = session.getMessages();
1291
- const agentMessages = messages.filter(
1292
- (m) => m.sender === "agent" || m.sender === "assistant"
1683
+ const agentMessages = session.getMessages().filter(
1684
+ (entry) => entry.sender === "agent" || entry.sender === "assistant"
1293
1685
  );
1294
1686
  const last = agentMessages[agentMessages.length - 1];
1295
1687
  if (last == null ? void 0 : last.content) {
@@ -1299,22 +1691,24 @@ async function chatCommand() {
1299
1691
  }
1300
1692
  }
1301
1693
  if (capturedRequests.length > 0) {
1302
- console.log(`
1303
- Run \`aomi tx\` to see pending transactions, \`aomi sign <id>\` to sign.`);
1694
+ console.log(
1695
+ "\nRun `aomi tx` to see pending transactions, `aomi sign <id>` to sign."
1696
+ );
1304
1697
  }
1305
1698
  } finally {
1306
1699
  session.close();
1307
1700
  }
1308
1701
  }
1309
- async function statusCommand() {
1310
- var _a2, _b, _c, _d, _e, _f, _g, _h;
1311
- const state = readState();
1312
- if (!state) {
1702
+
1703
+ // src/cli/commands/control.ts
1704
+ async function statusCommand(runtime) {
1705
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i;
1706
+ if (!readState()) {
1313
1707
  console.log("No active session");
1314
1708
  printDataFileLocation();
1315
1709
  return;
1316
1710
  }
1317
- const { session } = getOrCreateSession();
1711
+ const { session, state } = getOrCreateSession(runtime);
1318
1712
  try {
1319
1713
  const apiState = await session.client.fetchState(state.sessionId);
1320
1714
  console.log(
@@ -1323,11 +1717,12 @@ async function statusCommand() {
1323
1717
  sessionId: state.sessionId,
1324
1718
  baseUrl: state.baseUrl,
1325
1719
  namespace: state.namespace,
1326
- isProcessing: (_a2 = apiState.is_processing) != null ? _a2 : false,
1327
- messageCount: (_c = (_b = apiState.messages) == null ? void 0 : _b.length) != null ? _c : 0,
1328
- title: (_d = apiState.title) != null ? _d : null,
1329
- pendingTxs: (_f = (_e = state.pendingTxs) == null ? void 0 : _e.length) != null ? _f : 0,
1330
- signedTxs: (_h = (_g = state.signedTxs) == null ? void 0 : _g.length) != null ? _h : 0
1720
+ model: (_a3 = state.model) != null ? _a3 : null,
1721
+ isProcessing: (_b = apiState.is_processing) != null ? _b : false,
1722
+ messageCount: (_d = (_c = apiState.messages) == null ? void 0 : _c.length) != null ? _d : 0,
1723
+ title: (_e = apiState.title) != null ? _e : null,
1724
+ pendingTxs: (_g = (_f = state.pendingTxs) == null ? void 0 : _f.length) != null ? _g : 0,
1725
+ signedTxs: (_i = (_h = state.signedTxs) == null ? void 0 : _h.length) != null ? _i : 0
1331
1726
  },
1332
1727
  null,
1333
1728
  2
@@ -1338,13 +1733,12 @@ async function statusCommand() {
1338
1733
  session.close();
1339
1734
  }
1340
1735
  }
1341
- async function eventsCommand() {
1342
- const state = readState();
1343
- if (!state) {
1736
+ async function eventsCommand(runtime) {
1737
+ if (!readState()) {
1344
1738
  console.log("No active session");
1345
1739
  return;
1346
1740
  }
1347
- const { session } = getOrCreateSession();
1741
+ const { session, state } = getOrCreateSession(runtime);
1348
1742
  try {
1349
1743
  const events = await session.client.getSystemEvents(state.sessionId);
1350
1744
  console.log(JSON.stringify(events, null, 2));
@@ -1352,15 +1746,372 @@ async function eventsCommand() {
1352
1746
  session.close();
1353
1747
  }
1354
1748
  }
1749
+ async function modelsCommand(runtime) {
1750
+ var _a3, _b;
1751
+ const client = createControlClient(runtime);
1752
+ const state = readState();
1753
+ const sessionId = (_a3 = state == null ? void 0 : state.sessionId) != null ? _a3 : crypto.randomUUID();
1754
+ const models = await client.getModels(sessionId, {
1755
+ apiKey: (_b = runtime.config.apiKey) != null ? _b : state == null ? void 0 : state.apiKey
1756
+ });
1757
+ if (models.length === 0) {
1758
+ console.log("No models available.");
1759
+ return;
1760
+ }
1761
+ for (const model of models) {
1762
+ const marker = (state == null ? void 0 : state.model) === model ? " (current)" : "";
1763
+ console.log(`${model}${marker}`);
1764
+ }
1765
+ }
1766
+ async function modelCommand(runtime) {
1767
+ var _a3;
1768
+ const subcommand = runtime.parsed.positional[0];
1769
+ if (!subcommand || subcommand === "current") {
1770
+ const state2 = readState();
1771
+ if (!state2) {
1772
+ console.log("No active session");
1773
+ printDataFileLocation();
1774
+ return;
1775
+ }
1776
+ console.log((_a3 = state2.model) != null ? _a3 : "(default backend model)");
1777
+ printDataFileLocation();
1778
+ return;
1779
+ }
1780
+ if (subcommand !== "set") {
1781
+ fatal("Usage: aomi model set <rig>\n aomi model current");
1782
+ }
1783
+ const model = runtime.parsed.positional.slice(1).join(" ").trim();
1784
+ if (!model) {
1785
+ fatal("Usage: aomi model set <rig>");
1786
+ }
1787
+ const { session, state } = getOrCreateSession(runtime);
1788
+ try {
1789
+ await applyModelSelection(session, state, model);
1790
+ console.log(`Model set to ${model}`);
1791
+ printDataFileLocation();
1792
+ } finally {
1793
+ session.close();
1794
+ }
1795
+ }
1796
+
1797
+ // src/cli/tables.ts
1798
+ var MAX_TABLE_VALUE_WIDTH = 72;
1799
+ var MAX_TX_JSON_WIDTH = 96;
1800
+ var MAX_TX_ROWS = 8;
1801
+ function truncateCell(value, maxWidth) {
1802
+ if (value.length <= maxWidth) return value;
1803
+ return `${value.slice(0, maxWidth - 1)}\u2026`;
1804
+ }
1805
+ function padRight(value, width) {
1806
+ return value.padEnd(width, " ");
1807
+ }
1808
+ function estimateTokenCount(messages) {
1809
+ var _a3;
1810
+ let totalChars = 0;
1811
+ for (const message of messages) {
1812
+ const content = formatLogContent(message.content);
1813
+ if (content) {
1814
+ totalChars += content.length + 1;
1815
+ }
1816
+ if ((_a3 = message.tool_result) == null ? void 0 : _a3[1]) {
1817
+ totalChars += message.tool_result[1].length;
1818
+ }
1819
+ }
1820
+ return Math.round(totalChars / 4);
1821
+ }
1822
+ function toPendingTxMetadata(tx) {
1823
+ var _a3, _b, _c, _d;
1824
+ return {
1825
+ id: tx.id,
1826
+ kind: tx.kind,
1827
+ to: (_a3 = tx.to) != null ? _a3 : null,
1828
+ value: (_b = tx.value) != null ? _b : null,
1829
+ chainId: (_c = tx.chainId) != null ? _c : null,
1830
+ description: (_d = tx.description) != null ? _d : null,
1831
+ timestamp: new Date(tx.timestamp).toISOString()
1832
+ };
1833
+ }
1834
+ function toSignedTxMetadata(tx) {
1835
+ var _a3, _b, _c, _d, _e, _f, _g;
1836
+ return {
1837
+ id: tx.id,
1838
+ kind: tx.kind,
1839
+ txHash: (_a3 = tx.txHash) != null ? _a3 : null,
1840
+ signature: (_b = tx.signature) != null ? _b : null,
1841
+ from: (_c = tx.from) != null ? _c : null,
1842
+ to: (_d = tx.to) != null ? _d : null,
1843
+ value: (_e = tx.value) != null ? _e : null,
1844
+ chainId: (_f = tx.chainId) != null ? _f : null,
1845
+ description: (_g = tx.description) != null ? _g : null,
1846
+ timestamp: new Date(tx.timestamp).toISOString()
1847
+ };
1848
+ }
1849
+ function printKeyValueTable(rows, color = CYAN) {
1850
+ const labels = rows.map(([label]) => label);
1851
+ const values = rows.map(
1852
+ ([, value]) => truncateCell(value, MAX_TABLE_VALUE_WIDTH)
1853
+ );
1854
+ const keyWidth = Math.max("field".length, ...labels.map((label) => label.length));
1855
+ const valueWidth = Math.max("value".length, ...values.map((value) => value.length));
1856
+ const border = `+${"-".repeat(keyWidth + 2)}+${"-".repeat(valueWidth + 2)}+`;
1857
+ console.log(`${color}${border}${RESET}`);
1858
+ console.log(
1859
+ `${color}| ${padRight("field", keyWidth)} | ${padRight("value", valueWidth)} |${RESET}`
1860
+ );
1861
+ console.log(`${color}${border}${RESET}`);
1862
+ for (let i = 0; i < rows.length; i++) {
1863
+ console.log(
1864
+ `${color}| ${padRight(labels[i], keyWidth)} | ${padRight(values[i], valueWidth)} |${RESET}`
1865
+ );
1866
+ console.log(`${color}${border}${RESET}`);
1867
+ }
1868
+ }
1869
+ function printTransactionTable(pendingTxs, signedTxs, color = GREEN) {
1870
+ const rows = [
1871
+ ...pendingTxs.map((tx) => ({
1872
+ status: "pending",
1873
+ metadata: toPendingTxMetadata(tx)
1874
+ })),
1875
+ ...signedTxs.map((tx) => ({
1876
+ status: "signed",
1877
+ metadata: toSignedTxMetadata(tx)
1878
+ }))
1879
+ ];
1880
+ if (rows.length === 0) {
1881
+ console.log(`${YELLOW}No transactions in local CLI state.${RESET}`);
1882
+ return;
1883
+ }
1884
+ const visibleRows = rows.slice(0, MAX_TX_ROWS);
1885
+ const statusWidth = Math.max(
1886
+ "status".length,
1887
+ ...visibleRows.map((row) => row.status.length)
1888
+ );
1889
+ const jsonCells = visibleRows.map(
1890
+ (row) => truncateCell(JSON.stringify(row.metadata), MAX_TX_JSON_WIDTH)
1891
+ );
1892
+ const jsonWidth = Math.max("metadata_json".length, ...jsonCells.map((v) => v.length));
1893
+ const border = `+${"-".repeat(statusWidth + 2)}+${"-".repeat(jsonWidth + 2)}+`;
1894
+ console.log(`${color}${border}${RESET}`);
1895
+ console.log(
1896
+ `${color}| ${padRight("status", statusWidth)} | ${padRight("metadata_json", jsonWidth)} |${RESET}`
1897
+ );
1898
+ console.log(`${color}${border}${RESET}`);
1899
+ for (let i = 0; i < visibleRows.length; i++) {
1900
+ console.log(
1901
+ `${color}| ${padRight(visibleRows[i].status, statusWidth)} | ${padRight(jsonCells[i], jsonWidth)} |${RESET}`
1902
+ );
1903
+ console.log(`${color}${border}${RESET}`);
1904
+ }
1905
+ if (rows.length > MAX_TX_ROWS) {
1906
+ const omitted = rows.length - MAX_TX_ROWS;
1907
+ console.log(`${DIM}${omitted} transaction rows omitted${RESET}`);
1908
+ }
1909
+ }
1910
+
1911
+ // src/cli/commands/history.ts
1912
+ async function logCommand(runtime) {
1913
+ var _a3, _b, _c, _d, _e;
1914
+ if (!readState()) {
1915
+ console.log("No active session");
1916
+ printDataFileLocation();
1917
+ return;
1918
+ }
1919
+ const { session, state } = getOrCreateSession(runtime);
1920
+ try {
1921
+ const apiState = await session.client.fetchState(state.sessionId);
1922
+ const messages = (_a3 = apiState.messages) != null ? _a3 : [];
1923
+ const pendingTxs = (_b = state.pendingTxs) != null ? _b : [];
1924
+ const signedTxs = (_c = state.signedTxs) != null ? _c : [];
1925
+ const toolCalls = messages.filter((msg) => Boolean(msg.tool_result)).length;
1926
+ const tokenCountEstimate = estimateTokenCount(messages);
1927
+ const topic = (_d = apiState.title) != null ? _d : "Untitled Session";
1928
+ if (messages.length === 0) {
1929
+ console.log("No messages in this session.");
1930
+ printDataFileLocation();
1931
+ return;
1932
+ }
1933
+ console.log(`------ Session id: ${state.sessionId} ------`);
1934
+ printKeyValueTable([
1935
+ ["topic", topic],
1936
+ ["msg count", String(messages.length)],
1937
+ ["token count", `${tokenCountEstimate} (estimated)`],
1938
+ ["tool calls", String(toolCalls)],
1939
+ [
1940
+ "transactions",
1941
+ `${pendingTxs.length + signedTxs.length} (${pendingTxs.length} pending, ${signedTxs.length} signed)`
1942
+ ]
1943
+ ]);
1944
+ console.log("Transactions metadata (JSON):");
1945
+ printTransactionTable(pendingTxs, signedTxs);
1946
+ console.log("-------------------- Messages --------------------");
1947
+ for (const msg of messages) {
1948
+ const content = formatLogContent(msg.content);
1949
+ let time = "";
1950
+ if (msg.timestamp) {
1951
+ const raw = msg.timestamp;
1952
+ const numeric = /^\d+$/.test(raw) ? parseInt(raw, 10) : NaN;
1953
+ const date = !Number.isNaN(numeric) ? new Date(numeric < 1e12 ? numeric * 1e3 : numeric) : new Date(raw);
1954
+ time = Number.isNaN(date.getTime()) ? "" : `${DIM}${date.toLocaleTimeString()}${RESET} `;
1955
+ }
1956
+ const sender = (_e = msg.sender) != null ? _e : "unknown";
1957
+ if (sender === "user") {
1958
+ if (content) {
1959
+ console.log(`${time}${CYAN}\u{1F464} You:${RESET} ${content}`);
1960
+ }
1961
+ } else if (sender === "agent" || sender === "assistant") {
1962
+ if (msg.tool_result) {
1963
+ const [toolName, result] = msg.tool_result;
1964
+ console.log(
1965
+ `${time}${GREEN}\u{1F527} [${toolName}]${RESET} ${formatToolResultPreview(result)}`
1966
+ );
1967
+ }
1968
+ if (content) {
1969
+ console.log(`${time}${CYAN}\u{1F916} Agent:${RESET} ${content}`);
1970
+ }
1971
+ } else if (sender === "system") {
1972
+ if (content && !content.startsWith("Response of system endpoint:")) {
1973
+ console.log(`${time}${YELLOW}\u2699\uFE0F System:${RESET} ${content}`);
1974
+ }
1975
+ } else {
1976
+ if (content) {
1977
+ console.log(`${time}${DIM}[${sender}]${RESET} ${content}`);
1978
+ }
1979
+ }
1980
+ }
1981
+ console.log(`
1982
+ ${DIM}\u2014 ${messages.length} messages \u2014${RESET}`);
1983
+ printDataFileLocation();
1984
+ } finally {
1985
+ session.close();
1986
+ }
1987
+ }
1988
+ function closeCommand(runtime) {
1989
+ if (readState()) {
1990
+ const { session } = getOrCreateSession(runtime);
1991
+ session.close();
1992
+ }
1993
+ clearState();
1994
+ console.log("Session closed");
1995
+ }
1996
+
1997
+ // src/cli/commands/sessions.ts
1998
+ async function fetchRemoteSessionStats(record) {
1999
+ var _a3, _b;
2000
+ const client = new AomiClient({
2001
+ baseUrl: record.state.baseUrl,
2002
+ apiKey: record.state.apiKey
2003
+ });
2004
+ try {
2005
+ const apiState = await client.fetchState(record.sessionId);
2006
+ const messages = (_a3 = apiState.messages) != null ? _a3 : [];
2007
+ return {
2008
+ topic: (_b = apiState.title) != null ? _b : "Untitled Session",
2009
+ messageCount: messages.length,
2010
+ tokenCountEstimate: estimateTokenCount(messages),
2011
+ toolCalls: messages.filter((msg) => Boolean(msg.tool_result)).length
2012
+ };
2013
+ } catch (e) {
2014
+ return null;
2015
+ }
2016
+ }
2017
+ function printSessionSummary(record, stats, isActive) {
2018
+ var _a3, _b, _c;
2019
+ const pendingTxs = (_a3 = record.state.pendingTxs) != null ? _a3 : [];
2020
+ const signedTxs = (_b = record.state.signedTxs) != null ? _b : [];
2021
+ const header = isActive ? `\u{1F9F5} Session id: ${record.sessionId} (session-${record.localId}, active)` : `\u{1F9F5} Session id: ${record.sessionId} (session-${record.localId})`;
2022
+ console.log(`${YELLOW}------ ${header} ------${RESET}`);
2023
+ printKeyValueTable([
2024
+ ["\u{1F9E0} topic", (_c = stats == null ? void 0 : stats.topic) != null ? _c : "Unavailable (fetch failed)"],
2025
+ ["\u{1F4AC} msg count", stats ? String(stats.messageCount) : "n/a"],
2026
+ [
2027
+ "\u{1F9EE} token count",
2028
+ stats ? `${stats.tokenCountEstimate} (estimated)` : "n/a"
2029
+ ],
2030
+ ["\u{1F6E0} tool calls", stats ? String(stats.toolCalls) : "n/a"],
2031
+ [
2032
+ "\u{1F4B8} transactions",
2033
+ `${pendingTxs.length + signedTxs.length} (${pendingTxs.length} pending, ${signedTxs.length} signed)`
2034
+ ]
2035
+ ]);
2036
+ console.log();
2037
+ console.log(`${YELLOW}\u{1F4BE} Transactions metadata (JSON):${RESET}`);
2038
+ printTransactionTable(pendingTxs, signedTxs);
2039
+ }
2040
+ async function sessionsCommand(_runtime) {
2041
+ var _a3;
2042
+ const sessions = listStoredSessions().sort((a, b) => b.updatedAt - a.updatedAt);
2043
+ if (sessions.length === 0) {
2044
+ console.log("No local sessions.");
2045
+ printDataFileLocation();
2046
+ return;
2047
+ }
2048
+ const activeSessionId = (_a3 = readState()) == null ? void 0 : _a3.sessionId;
2049
+ const statsResults = await Promise.all(
2050
+ sessions.map((record) => fetchRemoteSessionStats(record))
2051
+ );
2052
+ for (let i = 0; i < sessions.length; i++) {
2053
+ printSessionSummary(
2054
+ sessions[i],
2055
+ statsResults[i],
2056
+ sessions[i].sessionId === activeSessionId
2057
+ );
2058
+ if (i < sessions.length - 1) {
2059
+ console.log();
2060
+ }
2061
+ }
2062
+ printDataFileLocation();
2063
+ }
2064
+ function sessionCommand(runtime) {
2065
+ const subcommand = runtime.parsed.positional[0];
2066
+ const selector = runtime.parsed.positional[1];
2067
+ if (subcommand === "resume") {
2068
+ if (!selector) {
2069
+ fatal("Usage: aomi session resume <session-id|session-N|N>");
2070
+ }
2071
+ const resumed = setActiveSession(selector);
2072
+ if (!resumed) {
2073
+ fatal(`No local session found for selector "${selector}".`);
2074
+ }
2075
+ console.log(`Active session set to ${resumed.sessionId} (session-${resumed.localId}).`);
2076
+ printDataFileLocation();
2077
+ return;
2078
+ }
2079
+ if (subcommand === "delete") {
2080
+ if (!selector) {
2081
+ fatal("Usage: aomi session delete <session-id|session-N|N>");
2082
+ }
2083
+ const deleted = deleteStoredSession(selector);
2084
+ if (!deleted) {
2085
+ fatal(`No local session found for selector "${selector}".`);
2086
+ }
2087
+ console.log(`Deleted local session ${deleted.sessionId} (session-${deleted.localId}).`);
2088
+ const active = readState();
2089
+ if (active) {
2090
+ console.log(`Active session: ${active.sessionId}`);
2091
+ } else {
2092
+ console.log("No active session");
2093
+ }
2094
+ printDataFileLocation();
2095
+ return;
2096
+ }
2097
+ fatal(
2098
+ "Usage: aomi session resume <session-id|session-N|N>\n aomi session delete <session-id|session-N|N>"
2099
+ );
2100
+ }
2101
+
2102
+ // src/cli/commands/wallet.ts
2103
+ import { createWalletClient, http } from "viem";
2104
+ import { privateKeyToAccount } from "viem/accounts";
2105
+ import * as viemChains from "viem/chains";
1355
2106
  function txCommand() {
1356
- var _a2, _b, _c;
2107
+ var _a3, _b, _c;
1357
2108
  const state = readState();
1358
2109
  if (!state) {
1359
2110
  console.log("No active session");
1360
2111
  printDataFileLocation();
1361
2112
  return;
1362
2113
  }
1363
- const pending = (_a2 = state.pendingTxs) != null ? _a2 : [];
2114
+ const pending = (_a3 = state.pendingTxs) != null ? _a3 : [];
1364
2115
  const signed = (_b = state.signedTxs) != null ? _b : [];
1365
2116
  if (pending.length === 0 && signed.length === 0) {
1366
2117
  console.log("No transactions.");
@@ -1392,48 +2143,62 @@ function txCommand() {
1392
2143
  }
1393
2144
  printDataFileLocation();
1394
2145
  }
1395
- async function signCommand() {
1396
- var _a2, _b, _c, _d;
1397
- const txId = parsed.positional[0];
2146
+ function requirePendingTx(state, txId) {
2147
+ var _a3;
2148
+ const pendingTx = ((_a3 = state.pendingTxs) != null ? _a3 : []).find((tx) => tx.id === txId);
2149
+ if (!pendingTx) {
2150
+ fatal(
2151
+ `No pending transaction with id "${txId}".
2152
+ Run \`aomi tx\` to see available IDs.`
2153
+ );
2154
+ }
2155
+ return pendingTx;
2156
+ }
2157
+ async function signCommand(runtime) {
2158
+ var _a3, _b, _c;
2159
+ const txId = runtime.parsed.positional[0];
1398
2160
  if (!txId) {
1399
- fatal("Usage: aomi sign <tx-id>\nRun `aomi tx` to see pending transaction IDs.");
2161
+ fatal(
2162
+ "Usage: aomi sign <tx-id>\nRun `aomi tx` to see pending transaction IDs."
2163
+ );
1400
2164
  }
1401
- const config = getConfig();
1402
- const privateKey = config.privateKey;
2165
+ const privateKey = runtime.config.privateKey;
1403
2166
  if (!privateKey) {
1404
- fatal("Private key required. Pass --private-key or set PRIVATE_KEY env var.");
2167
+ fatal(
2168
+ [
2169
+ "Private key required for `aomi sign`.",
2170
+ "Pass one of:",
2171
+ " --private-key <hex-key>",
2172
+ " PRIVATE_KEY=<hex-key> aomi sign <tx-id>"
2173
+ ].join("\n")
2174
+ );
1405
2175
  }
1406
2176
  const state = readState();
1407
2177
  if (!state) {
1408
2178
  fatal("No active session. Run `aomi chat` first.");
1409
2179
  }
1410
- const pendingTx = ((_a2 = state.pendingTxs) != null ? _a2 : []).find((t) => t.id === txId);
1411
- if (!pendingTx) {
1412
- fatal(`No pending transaction with id "${txId}".
1413
- Run \`aomi tx\` to see available IDs.`);
1414
- }
1415
- const { session } = getOrCreateSession();
2180
+ const pendingTx = requirePendingTx(state, txId);
2181
+ const { session } = getOrCreateSession(runtime);
1416
2182
  try {
1417
- let viem;
1418
- let viemAccounts;
1419
- let viemChains;
1420
- try {
1421
- viem = await import("viem");
1422
- viemAccounts = await import("viem/accounts");
1423
- viemChains = await import("viem/chains");
1424
- } catch (e) {
1425
- fatal(
1426
- "viem is required for `aomi sign`. Install it:\n npm install viem\n # or: pnpm add viem"
1427
- );
1428
- }
1429
- const { createWalletClient, http } = viem;
1430
- const { privateKeyToAccount } = viemAccounts;
1431
2183
  const account = privateKeyToAccount(privateKey);
1432
- const rpcUrl = config.chainRpcUrl;
1433
- const targetChainId = (_b = pendingTx.chainId) != null ? _b : 1;
1434
- const chain = (_c = Object.values(viemChains).find(
1435
- (c) => typeof c === "object" && c !== null && "id" in c && c.id === targetChainId
1436
- )) != null ? _c : { id: targetChainId, name: `Chain ${targetChainId}`, nativeCurrency: { name: "ETH", symbol: "ETH", decimals: 18 }, rpcUrls: { default: { http: [rpcUrl != null ? rpcUrl : ""] } } };
2184
+ const rpcUrl = runtime.config.chainRpcUrl;
2185
+ const targetChainId = (_a3 = pendingTx.chainId) != null ? _a3 : 1;
2186
+ const chain = (_b = Object.values(viemChains).find(
2187
+ (candidate) => typeof candidate === "object" && candidate !== null && "id" in candidate && candidate.id === targetChainId
2188
+ )) != null ? _b : {
2189
+ id: targetChainId,
2190
+ name: `Chain ${targetChainId}`,
2191
+ nativeCurrency: {
2192
+ name: "ETH",
2193
+ symbol: "ETH",
2194
+ decimals: 18
2195
+ },
2196
+ rpcUrls: {
2197
+ default: {
2198
+ http: [rpcUrl != null ? rpcUrl : ""]
2199
+ }
2200
+ }
2201
+ };
1437
2202
  const walletClient = createWalletClient({
1438
2203
  account,
1439
2204
  chain,
@@ -1446,12 +2211,14 @@ Run \`aomi tx\` to see available IDs.`);
1446
2211
  console.log(`To: ${pendingTx.to}`);
1447
2212
  if (pendingTx.value) console.log(`Value: ${pendingTx.value}`);
1448
2213
  if (pendingTx.chainId) console.log(`Chain: ${pendingTx.chainId}`);
1449
- if (pendingTx.data) console.log(`Data: ${pendingTx.data.slice(0, 40)}...`);
2214
+ if (pendingTx.data) {
2215
+ console.log(`Data: ${pendingTx.data.slice(0, 40)}...`);
2216
+ }
1450
2217
  console.log();
1451
2218
  const hash = await walletClient.sendTransaction({
1452
2219
  to: pendingTx.to,
1453
2220
  value: pendingTx.value ? BigInt(pendingTx.value) : /* @__PURE__ */ BigInt("0"),
1454
- data: (_d = pendingTx.data) != null ? _d : void 0
2221
+ data: (_c = pendingTx.data) != null ? _c : void 0
1455
2222
  });
1456
2223
  console.log(`\u2705 Sent! Hash: ${hash}`);
1457
2224
  removePendingTx(state, txId);
@@ -1478,8 +2245,12 @@ Run \`aomi tx\` to see available IDs.`);
1478
2245
  if (!typedData) {
1479
2246
  fatal("EIP-712 request is missing typed_data payload.");
1480
2247
  }
1481
- if (pendingTx.description) console.log(`Desc: ${pendingTx.description}`);
1482
- if (typedData.primaryType) console.log(`Type: ${typedData.primaryType}`);
2248
+ if (pendingTx.description) {
2249
+ console.log(`Desc: ${pendingTx.description}`);
2250
+ }
2251
+ if (typedData.primaryType) {
2252
+ console.log(`Type: ${typedData.primaryType}`);
2253
+ }
1483
2254
  console.log();
1484
2255
  const { domain, types, primaryType, message } = typedData;
1485
2256
  const sigTypes = __spreadValues({}, types);
@@ -1522,73 +2293,24 @@ Run \`aomi tx\` to see available IDs.`);
1522
2293
  session.close();
1523
2294
  }
1524
2295
  }
1525
- async function logCommand() {
1526
- var _a2, _b, _c, _d, _e;
1527
- const state = readState();
1528
- if (!state) {
1529
- console.log("No active session");
1530
- printDataFileLocation();
1531
- return;
1532
- }
1533
- const { session } = getOrCreateSession();
1534
- try {
1535
- const apiState = await session.client.fetchState(state.sessionId);
1536
- const messages = (_a2 = apiState.messages) != null ? _a2 : [];
1537
- if (messages.length === 0) {
1538
- console.log("No messages in this session.");
1539
- printDataFileLocation();
1540
- return;
1541
- }
1542
- for (const msg of messages) {
1543
- let time = "";
1544
- if (msg.timestamp) {
1545
- const raw = msg.timestamp;
1546
- const n = /^\d+$/.test(raw) ? parseInt(raw, 10) : NaN;
1547
- const date = !isNaN(n) ? new Date(n < 1e12 ? n * 1e3 : n) : new Date(raw);
1548
- time = isNaN(date.getTime()) ? "" : `${DIM}${date.toLocaleTimeString()}${RESET} `;
1549
- }
1550
- const sender = (_b = msg.sender) != null ? _b : "unknown";
1551
- if (sender === "user") {
1552
- console.log(`${time}${CYAN}\u{1F464} You:${RESET} ${(_c = msg.content) != null ? _c : ""}`);
1553
- } else if (sender === "agent" || sender === "assistant") {
1554
- if (msg.tool_result) {
1555
- const [toolName, result] = msg.tool_result;
1556
- console.log(
1557
- `${time}${GREEN}\u{1F527} [${toolName}]${RESET} ${result.slice(0, 200)}${result.length > 200 ? "\u2026" : ""}`
1558
- );
1559
- }
1560
- if (msg.content) {
1561
- console.log(`${time}${CYAN}\u{1F916} Agent:${RESET} ${msg.content}`);
1562
- }
1563
- } else if (sender === "system") {
1564
- console.log(`${time}${YELLOW}\u2699\uFE0F System:${RESET} ${(_d = msg.content) != null ? _d : ""}`);
1565
- } else {
1566
- console.log(`${time}${DIM}[${sender}]${RESET} ${(_e = msg.content) != null ? _e : ""}`);
1567
- }
1568
- }
1569
- console.log(`
1570
- ${DIM}\u2014 ${messages.length} messages \u2014${RESET}`);
1571
- printDataFileLocation();
1572
- } finally {
1573
- session.close();
1574
- }
1575
- }
1576
- function closeCommand() {
1577
- const state = readState();
1578
- if (state) {
1579
- const { session } = getOrCreateSession();
1580
- session.close();
1581
- }
1582
- clearState();
1583
- console.log("Session closed");
1584
- }
2296
+
2297
+ // src/cli/main.ts
1585
2298
  function printUsage() {
1586
2299
  console.log(`
1587
2300
  aomi \u2014 CLI client for Aomi on-chain agent
1588
2301
 
1589
2302
  Usage:
1590
2303
  aomi chat <message> Send a message and print the response
2304
+ aomi chat --model <rig>
2305
+ Set the session model before sending the message
1591
2306
  aomi chat --verbose Stream agent responses, tool calls, and events live
2307
+ aomi models List models available to the current backend
2308
+ aomi model set <rig> Set the active model for the current session
2309
+ aomi sessions List local sessions with metadata tables
2310
+ aomi session resume <id>
2311
+ Resume a local session (session-id or session-N)
2312
+ aomi session delete <id>
2313
+ Delete a local session file (session-id or session-N)
1592
2314
  aomi log Show full conversation history with tool results
1593
2315
  aomi tx List pending and signed transactions
1594
2316
  aomi sign <tx-id> Sign and submit a pending transaction
@@ -1600,6 +2322,7 @@ Options:
1600
2322
  --backend-url <url> Backend URL (default: https://api.aomi.dev)
1601
2323
  --api-key <key> API key for non-default namespaces
1602
2324
  --namespace <ns> Namespace (default: "default")
2325
+ --model <rig> Set the active model for this session
1603
2326
  --public-key <addr> Wallet address (so the agent knows your wallet)
1604
2327
  --private-key <key> Hex private key for signing
1605
2328
  --rpc-url <url> RPC URL for transaction submission
@@ -1609,49 +2332,85 @@ Environment (overridden by flags):
1609
2332
  AOMI_BASE_URL Backend URL
1610
2333
  AOMI_API_KEY API key
1611
2334
  AOMI_NAMESPACE Namespace
2335
+ AOMI_MODEL Model rig
1612
2336
  AOMI_PUBLIC_KEY Wallet address
1613
2337
  PRIVATE_KEY Hex private key for signing
1614
2338
  CHAIN_RPC_URL RPC URL for transaction submission
1615
2339
  `.trim());
1616
2340
  }
1617
- async function main() {
1618
- var _a2;
1619
- const cmd = (_a2 = parsed.command) != null ? _a2 : parsed.flags["help"] || parsed.flags["h"] ? "help" : void 0;
1620
- switch (cmd) {
2341
+ async function main(runtime) {
2342
+ var _a3;
2343
+ const command = (_a3 = runtime.parsed.command) != null ? _a3 : runtime.parsed.flags["help"] || runtime.parsed.flags["h"] ? "help" : void 0;
2344
+ switch (command) {
1621
2345
  case "chat":
1622
- await chatCommand();
2346
+ await chatCommand(runtime);
1623
2347
  break;
1624
2348
  case "log":
1625
- await logCommand();
2349
+ await logCommand(runtime);
2350
+ break;
2351
+ case "models":
2352
+ await modelsCommand(runtime);
2353
+ break;
2354
+ case "model":
2355
+ await modelCommand(runtime);
2356
+ break;
2357
+ case "sessions":
2358
+ await sessionsCommand(runtime);
2359
+ break;
2360
+ case "session":
2361
+ sessionCommand(runtime);
1626
2362
  break;
1627
2363
  case "tx":
1628
2364
  txCommand();
1629
2365
  break;
1630
2366
  case "sign":
1631
- await signCommand();
2367
+ await signCommand(runtime);
1632
2368
  break;
1633
2369
  case "status":
1634
- await statusCommand();
2370
+ await statusCommand(runtime);
1635
2371
  break;
1636
2372
  case "events":
1637
- await eventsCommand();
2373
+ await eventsCommand(runtime);
1638
2374
  break;
1639
2375
  case "close":
1640
- closeCommand();
2376
+ closeCommand(runtime);
1641
2377
  break;
1642
2378
  case "help":
1643
2379
  printUsage();
1644
2380
  break;
1645
2381
  default:
1646
2382
  printUsage();
1647
- if (cmd) throw new CliExit(1);
2383
+ if (command) {
2384
+ throw new CliExit(1);
2385
+ }
1648
2386
  }
1649
2387
  }
1650
- main().catch((err) => {
1651
- if (err instanceof CliExit) {
1652
- process.exit(err.code);
1653
- return;
2388
+ function isPnpmExecWrapper() {
2389
+ var _a3, _b;
2390
+ const npmCommand = (_a3 = process.env.npm_command) != null ? _a3 : "";
2391
+ const userAgent = (_b = process.env.npm_config_user_agent) != null ? _b : "";
2392
+ return npmCommand === "exec" && userAgent.includes("pnpm/");
2393
+ }
2394
+ async function runCli(argv = process.argv) {
2395
+ const runtime = createRuntime(argv);
2396
+ const RED = "\x1B[31m";
2397
+ const RESET3 = "\x1B[0m";
2398
+ const strictExit = process.env.AOMI_CLI_STRICT_EXIT === "1";
2399
+ try {
2400
+ await main(runtime);
2401
+ } catch (err) {
2402
+ if (err instanceof CliExit) {
2403
+ if (!strictExit && isPnpmExecWrapper()) {
2404
+ return;
2405
+ }
2406
+ process.exit(err.code);
2407
+ return;
2408
+ }
2409
+ const message = err instanceof Error ? err.message : String(err);
2410
+ console.error(`${RED}\u274C ${message}${RESET3}`);
2411
+ process.exit(1);
1654
2412
  }
1655
- console.error(err instanceof Error ? err.message : err);
1656
- process.exit(1);
1657
- });
2413
+ }
2414
+
2415
+ // src/cli.ts
2416
+ void runCli();