@roj-ai/cli 0.0.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.
Files changed (49) hide show
  1. package/dist/client.d.ts +8 -0
  2. package/dist/client.d.ts.map +1 -0
  3. package/dist/client.js +28 -0
  4. package/dist/commands/answer.d.ts +3 -0
  5. package/dist/commands/answer.d.ts.map +1 -0
  6. package/dist/commands/answer.js +15 -0
  7. package/dist/commands/debug-format.d.ts +12 -0
  8. package/dist/commands/debug-format.d.ts.map +1 -0
  9. package/dist/commands/debug-format.js +262 -0
  10. package/dist/commands/debug.d.ts +14 -0
  11. package/dist/commands/debug.d.ts.map +1 -0
  12. package/dist/commands/debug.js +187 -0
  13. package/dist/commands/messages.d.ts +4 -0
  14. package/dist/commands/messages.d.ts.map +1 -0
  15. package/dist/commands/messages.js +77 -0
  16. package/dist/commands/presets.d.ts +3 -0
  17. package/dist/commands/presets.d.ts.map +1 -0
  18. package/dist/commands/presets.js +14 -0
  19. package/dist/commands/sessions.d.ts +6 -0
  20. package/dist/commands/sessions.d.ts.map +1 -0
  21. package/dist/commands/sessions.js +50 -0
  22. package/dist/main.d.ts +2 -0
  23. package/dist/main.d.ts.map +1 -0
  24. package/dist/main.js +277 -0
  25. package/dist/repl/formatter.d.ts +16 -0
  26. package/dist/repl/formatter.d.ts.map +1 -0
  27. package/dist/repl/formatter.js +72 -0
  28. package/dist/repl/repl.d.ts +3 -0
  29. package/dist/repl/repl.d.ts.map +1 -0
  30. package/dist/repl/repl.js +212 -0
  31. package/dist/repl/session-picker.d.ts +6 -0
  32. package/dist/repl/session-picker.d.ts.map +1 -0
  33. package/dist/repl/session-picker.js +60 -0
  34. package/dist/unwrap.d.ts +4 -0
  35. package/dist/unwrap.d.ts.map +1 -0
  36. package/dist/unwrap.js +6 -0
  37. package/package.json +27 -0
  38. package/src/client.ts +41 -0
  39. package/src/commands/answer.ts +27 -0
  40. package/src/commands/debug-format.ts +299 -0
  41. package/src/commands/debug.ts +347 -0
  42. package/src/commands/messages.ts +92 -0
  43. package/src/commands/presets.ts +22 -0
  44. package/src/commands/sessions.ts +73 -0
  45. package/src/main.ts +319 -0
  46. package/src/repl/formatter.ts +84 -0
  47. package/src/repl/repl.ts +246 -0
  48. package/src/repl/session-picker.ts +81 -0
  49. package/src/unwrap.ts +8 -0
@@ -0,0 +1,8 @@
1
+ import { RpcClient } from '@roj-ai/shared/rpc';
2
+ import type { ProtocolDef } from '@roj-ai/transport';
3
+ import { ClientConnection } from '@roj-ai/transport/client';
4
+ export declare function createCliClient(baseUrl: string): RpcClient;
5
+ export type WsConnection = ClientConnection<ProtocolDef, ProtocolDef>;
6
+ export type NotificationHandlers = Record<string, (payload: unknown) => void>;
7
+ export declare function connectWebSocket(baseUrl: string, sessionId: string, handlers: NotificationHandlers): WsConnection;
8
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAsB,MAAM,mBAAmB,CAAA;AAExE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAE3D,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAE1D;AAED,MAAM,MAAM,YAAY,GAAG,gBAAgB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAA;AAErE,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC,CAAA;AAE7E,wBAAgB,gBAAgB,CAC/B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,oBAAoB,GAC5B,YAAY,CAuBd"}
package/dist/client.js ADDED
@@ -0,0 +1,28 @@
1
+ import { RpcClient } from '@roj-ai/shared/rpc';
2
+ import { bunWebSocketFactory } from '@roj-ai/transport/bun';
3
+ import { ClientConnection } from '@roj-ai/transport/client';
4
+ export function createCliClient(baseUrl) {
5
+ return new RpcClient(baseUrl);
6
+ }
7
+ export function connectWebSocket(baseUrl, sessionId, handlers) {
8
+ const url = new URL('/ws/spa', baseUrl);
9
+ url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:';
10
+ url.searchParams.set('sessionId', sessionId);
11
+ const connection = new ClientConnection({
12
+ url: url.toString(),
13
+ wsFactory: bunWebSocketFactory,
14
+ reconnect: {
15
+ baseDelayMs: 1000,
16
+ maxDelayMs: 10000,
17
+ maxAttempts: 10,
18
+ },
19
+ });
20
+ const listener = (type, payload) => {
21
+ const handler = handlers[type];
22
+ if (handler) {
23
+ handler(payload);
24
+ }
25
+ };
26
+ connection.setRawMessageListener(listener);
27
+ return connection;
28
+ }
@@ -0,0 +1,3 @@
1
+ import type { RpcClient } from '@roj-ai/shared/rpc';
2
+ export declare function answerCommand(client: RpcClient, sessionId: string, questionId: string, answer: string, json: boolean): Promise<void>;
3
+ //# sourceMappingURL=answer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"answer.d.ts","sourceRoot":"","sources":["../../src/commands/answer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAGnD,wBAAsB,aAAa,CAClC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,OAAO,GACX,OAAO,CAAC,IAAI,CAAC,CAgBf"}
@@ -0,0 +1,15 @@
1
+ import { AgentId, ChatMessageId } from '@roj-ai/shared';
2
+ import { unwrap } from '../unwrap.js';
3
+ export async function answerCommand(client, sessionId, questionId, answer, json) {
4
+ const session = unwrap(await client.call('sessions.get', { sessionId }));
5
+ if (!session.entryAgentId) {
6
+ console.error('No entry agent found for session.');
7
+ process.exit(1);
8
+ }
9
+ const result = unwrap(await client.call('user-chat.answerQuestion', { sessionId, agentId: AgentId(session.entryAgentId), questionId: ChatMessageId(questionId), answer }));
10
+ if (json) {
11
+ console.log(JSON.stringify(result));
12
+ return;
13
+ }
14
+ console.log('Answer submitted.');
15
+ }
@@ -0,0 +1,12 @@
1
+ import type { LLMCallLogEntry } from '@roj-ai/sdk';
2
+ import type { DomainEvent } from '@roj-ai/sdk';
3
+ import type { AgentTreeNode, GetAgentDetailResponse, GetMetricsResponse, GlobalMailboxMessage, TimelineItem } from '@roj-ai/shared';
4
+ export declare function truncate(str: string, maxLen: number): string;
5
+ export declare function formatAgentTree(nodes: AgentTreeNode[]): string;
6
+ export declare function formatAgentDetail(detail: GetAgentDetailResponse): string;
7
+ export declare function formatTimelineItem(item: TimelineItem): string;
8
+ export declare function formatMailboxMessage(msg: GlobalMailboxMessage): string;
9
+ export declare function formatMetrics(metrics: GetMetricsResponse): string;
10
+ export declare function formatLLMCallDetail(call: LLMCallLogEntry): string;
11
+ export declare function formatEventRow(event: DomainEvent, index: number): string[];
12
+ //# sourceMappingURL=debug-format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug-format.d.ts","sourceRoot":"","sources":["../../src/commands/debug-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,KAAK,EACX,aAAa,EAEb,sBAAsB,EACtB,kBAAkB,EAClB,oBAAoB,EACpB,YAAY,EACZ,MAAM,gBAAgB,CAAA;AAYvB,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAG5D;AAgCD,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,MAAM,CAO9D;AAmCD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,sBAAsB,GAAG,MAAM,CA8CxE;AAwBD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAsB7D;AAMD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,oBAAoB,GAAG,MAAM,CAItE;AAMD,wBAAgB,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAcjE;AAMD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,CA0DjE;AAMD,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ1E"}
@@ -0,0 +1,262 @@
1
+ // ANSI color codes
2
+ const RESET = '\x1b[0m';
3
+ const BOLD = '\x1b[1m';
4
+ const DIM = '\x1b[2m';
5
+ const CYAN = '\x1b[36m';
6
+ const GREEN = '\x1b[32m';
7
+ const YELLOW = '\x1b[33m';
8
+ const RED = '\x1b[31m';
9
+ const MAGENTA = '\x1b[35m';
10
+ export function truncate(str, maxLen) {
11
+ if (str.length <= maxLen)
12
+ return str;
13
+ return str.slice(0, maxLen - 1) + '\u2026';
14
+ }
15
+ function formatDuration(ms) {
16
+ if (ms === undefined)
17
+ return '-';
18
+ if (ms < 1000)
19
+ return `${ms}ms`;
20
+ return `${(ms / 1000).toFixed(1)}s`;
21
+ }
22
+ function formatTimestamp(ts) {
23
+ return new Date(ts).toLocaleTimeString();
24
+ }
25
+ function statusColor(status) {
26
+ switch (status) {
27
+ case 'idle':
28
+ case 'success':
29
+ return GREEN;
30
+ case 'thinking':
31
+ case 'responding':
32
+ case 'running':
33
+ return YELLOW;
34
+ case 'error':
35
+ return RED;
36
+ default:
37
+ return '';
38
+ }
39
+ }
40
+ // ============================================================================
41
+ // Agent Tree
42
+ // ============================================================================
43
+ export function formatAgentTree(nodes) {
44
+ const lines = [];
45
+ for (let i = 0; i < nodes.length; i++) {
46
+ const isLast = i === nodes.length - 1;
47
+ formatTreeNode(lines, nodes[i], '', isLast);
48
+ }
49
+ return lines.join('\n');
50
+ }
51
+ function formatCost(cost) {
52
+ if (cost >= 1)
53
+ return `$${cost.toFixed(2)}`;
54
+ return `$${cost.toFixed(4)}`;
55
+ }
56
+ function formatTreeNode(lines, node, prefix, isLast) {
57
+ const connector = isLast ? '\u2514\u2500\u2500 ' : '\u251c\u2500\u2500 ';
58
+ const childPrefix = prefix + (isLast ? ' ' : '\u2502 ');
59
+ const color = statusColor(node.status);
60
+ // Line 1: name + status
61
+ lines.push(`${prefix}${connector}${BOLD}${node.definitionName}${RESET} ${color}[${node.status}]${RESET}`);
62
+ // Line 2: cost + badges + id
63
+ const details = [];
64
+ if (node.cost > 0)
65
+ details.push(`${GREEN}${formatCost(node.cost)}${RESET}`);
66
+ if (node.isExecuting)
67
+ details.push(`${YELLOW}executing${RESET}`);
68
+ if (node.mailboxCount > 0)
69
+ details.push(`${CYAN}${node.mailboxCount} msgs${RESET}`);
70
+ if (node.pendingToolCalls > 0)
71
+ details.push(`${MAGENTA}${node.pendingToolCalls} tools${RESET}`);
72
+ const detailStr = details.length > 0 ? details.join(` ${DIM}\u00b7${RESET} `) + ' ' : '';
73
+ lines.push(`${childPrefix}${detailStr}${DIM}${node.id}${RESET}`);
74
+ // Children
75
+ for (let i = 0; i < node.children.length; i++) {
76
+ const childIsLast = i === node.children.length - 1;
77
+ formatTreeNode(lines, node.children[i], childPrefix, childIsLast);
78
+ }
79
+ }
80
+ // ============================================================================
81
+ // Agent Detail
82
+ // ============================================================================
83
+ export function formatAgentDetail(detail) {
84
+ const lines = [];
85
+ const color = statusColor(detail.status);
86
+ // Header
87
+ lines.push(`${BOLD}Agent: ${detail.definitionName}${RESET}`);
88
+ lines.push(` ID: ${detail.id}`);
89
+ lines.push(` Status: ${color}${detail.status}${RESET}`);
90
+ lines.push(` Parent: ${detail.parentId ?? 'none'}`);
91
+ // Mailbox
92
+ lines.push('');
93
+ lines.push(`${BOLD}Mailbox${RESET} (${detail.mailbox.length} messages)`);
94
+ if (detail.mailbox.length === 0) {
95
+ lines.push(` ${DIM}(empty)${RESET}`);
96
+ }
97
+ else {
98
+ for (const msg of detail.mailbox) {
99
+ const consumed = msg.consumed ? `${DIM}[consumed]${RESET}` : `${YELLOW}[pending]${RESET}`;
100
+ lines.push(` ${msg.from} ${consumed}: ${truncate(msg.content, 80)}`);
101
+ }
102
+ }
103
+ // Conversation
104
+ lines.push('');
105
+ lines.push(`${BOLD}Conversation${RESET} (${detail.conversationHistory.length} messages)`);
106
+ if (detail.conversationHistory.length === 0) {
107
+ lines.push(` ${DIM}(empty)${RESET}`);
108
+ }
109
+ else {
110
+ for (const msg of detail.conversationHistory) {
111
+ lines.push(formatConversationMessage(msg));
112
+ }
113
+ }
114
+ // Pending Tool Calls
115
+ if (detail.pendingToolCalls.length > 0) {
116
+ lines.push('');
117
+ lines.push(`${BOLD}Pending Tool Calls${RESET} (${detail.pendingToolCalls.length})`);
118
+ for (const tc of detail.pendingToolCalls) {
119
+ lines.push(` ${MAGENTA}${tc.name}${RESET} [${tc.status}] ${DIM}${tc.id}${RESET}`);
120
+ if (tc.input) {
121
+ lines.push(` Input: ${truncate(JSON.stringify(tc.input), 100)}`);
122
+ }
123
+ }
124
+ }
125
+ return lines.join('\n');
126
+ }
127
+ function formatConversationMessage(msg) {
128
+ switch (msg.role) {
129
+ case 'user':
130
+ return ` ${GREEN}user:${RESET} ${truncate(typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content), 100)}`;
131
+ case 'assistant': {
132
+ const content = msg.content ? truncate(msg.content, 100) : '';
133
+ const toolsInfo = msg.toolCalls?.length ? ` ${DIM}[${msg.toolCalls.length} tool calls]${RESET}` : '';
134
+ return ` ${CYAN}assistant:${RESET} ${content}${toolsInfo}`;
135
+ }
136
+ case 'tool': {
137
+ const errTag = msg.isError ? `${RED}[error]${RESET} ` : '';
138
+ return ` ${MAGENTA}tool(${msg.toolCallId}):${RESET} ${errTag}${truncate(msg.content, 100)}`;
139
+ }
140
+ case 'system':
141
+ return ` ${DIM}system: ${truncate(msg.content, 100)}${RESET}`;
142
+ }
143
+ }
144
+ // ============================================================================
145
+ // Timeline
146
+ // ============================================================================
147
+ export function formatTimelineItem(item) {
148
+ const status = `${statusColor(item.status)}${item.status}${RESET}`;
149
+ const duration = formatDuration(item.durationMs);
150
+ const time = formatTimestamp(item.startedAt);
151
+ switch (item.type) {
152
+ case 'llm': {
153
+ const model = item.model ?? '-';
154
+ const tokens = item.promptTokens !== undefined ? `${item.promptTokens}/${item.completionTokens}` : '-';
155
+ return `${time} ${CYAN}llm${RESET} ${item.agentName.padEnd(20)} ${status.padEnd(20)} ${duration.padStart(8)} ${model} ${tokens}`;
156
+ }
157
+ case 'tool': {
158
+ const toolName = item.toolName ?? '-';
159
+ return `${time} ${MAGENTA}tool${RESET} ${item.agentName.padEnd(20)} ${status.padEnd(20)} ${duration.padStart(8)} ${toolName}`;
160
+ }
161
+ case 'compaction': {
162
+ const info = item.originalTokens !== undefined
163
+ ? `${item.originalTokens} -> ${item.compactedTokens} tokens, ${item.messagesRemoved} msgs removed`
164
+ : '';
165
+ return `${time} ${YELLOW}compact${RESET} ${item.agentName.padEnd(20)} ${status.padEnd(20)} ${DIM}${info}${RESET}`;
166
+ }
167
+ }
168
+ }
169
+ // ============================================================================
170
+ // Mailbox
171
+ // ============================================================================
172
+ export function formatMailboxMessage(msg) {
173
+ const status = msg.consumed ? `${DIM}[consumed]${RESET}` : `${YELLOW}[pending]${RESET}`;
174
+ const time = formatTimestamp(msg.timestamp);
175
+ return `${time} ${msg.fromAgentName} -> ${msg.toAgentName} ${status} ${truncate(msg.content, 60)}`;
176
+ }
177
+ // ============================================================================
178
+ // Metrics
179
+ // ============================================================================
180
+ export function formatMetrics(metrics) {
181
+ const lines = [];
182
+ lines.push(`${BOLD}Session Metrics${RESET}`);
183
+ lines.push(` Total tokens: ${metrics.totalTokens.toLocaleString()}`);
184
+ lines.push(` Prompt tokens: ${metrics.promptTokens.toLocaleString()}`);
185
+ lines.push(` Completion tokens: ${metrics.completionTokens.toLocaleString()}`);
186
+ if (metrics.totalCost !== undefined) {
187
+ lines.push(` Cost: $${metrics.totalCost.toFixed(4)}`);
188
+ }
189
+ lines.push(` LLM calls: ${metrics.llmCalls}`);
190
+ lines.push(` Tool calls: ${metrics.toolCalls}`);
191
+ lines.push(` Agent count: ${metrics.agentCount}`);
192
+ lines.push(` Duration: ${formatDuration(metrics.durationMs)}`);
193
+ return lines.join('\n');
194
+ }
195
+ // ============================================================================
196
+ // LLM Call Detail
197
+ // ============================================================================
198
+ export function formatLLMCallDetail(call) {
199
+ const lines = [];
200
+ lines.push(`${BOLD}LLM Call: ${call.id}${RESET}`);
201
+ lines.push(` Agent: ${call.agentId}`);
202
+ lines.push(` Status: ${statusColor(call.status)}${call.status}${RESET}`);
203
+ lines.push(` Created: ${new Date(call.createdAt).toLocaleString()}`);
204
+ if (call.durationMs !== undefined) {
205
+ lines.push(` Duration: ${formatDuration(call.durationMs)}`);
206
+ }
207
+ // Request
208
+ lines.push('');
209
+ lines.push(`${BOLD}Request${RESET}`);
210
+ lines.push(` Model: ${call.request.model}`);
211
+ lines.push(` Messages: ${call.request.messages.length}`);
212
+ lines.push(` Tools: ${call.request.toolsCount}`);
213
+ if (call.request.systemPrompt) {
214
+ lines.push(` System: ${truncate(call.request.systemPrompt, 100)}`);
215
+ }
216
+ // Response
217
+ if (call.response) {
218
+ lines.push('');
219
+ lines.push(`${BOLD}Response${RESET}`);
220
+ lines.push(` Finish: ${call.response.finishReason}`);
221
+ if (call.response.content) {
222
+ lines.push(` Content: ${truncate(call.response.content, 200)}`);
223
+ }
224
+ if (call.response.toolCalls.length > 0) {
225
+ lines.push(` Tool calls: ${call.response.toolCalls.length}`);
226
+ for (const tc of call.response.toolCalls) {
227
+ lines.push(` ${MAGENTA}${tc.name}${RESET} ${DIM}${tc.id}${RESET}`);
228
+ }
229
+ }
230
+ }
231
+ // Metrics
232
+ if (call.metrics) {
233
+ lines.push('');
234
+ lines.push(`${BOLD}Metrics${RESET}`);
235
+ lines.push(` Prompt: ${call.metrics.promptTokens.toLocaleString()} tokens`);
236
+ lines.push(` Completion: ${call.metrics.completionTokens.toLocaleString()} tokens`);
237
+ lines.push(` Total: ${call.metrics.totalTokens.toLocaleString()} tokens`);
238
+ if (call.metrics.cost !== undefined) {
239
+ lines.push(` Cost: $${call.metrics.cost.toFixed(4)}`);
240
+ }
241
+ lines.push(` Latency: ${formatDuration(call.metrics.latencyMs)}`);
242
+ }
243
+ // Error
244
+ if (call.error) {
245
+ lines.push('');
246
+ lines.push(`${RED}${BOLD}Error${RESET}`);
247
+ lines.push(` ${RED}${call.error.type}: ${call.error.message}${RESET}`);
248
+ }
249
+ return lines.join('\n');
250
+ }
251
+ // ============================================================================
252
+ // Event Row
253
+ // ============================================================================
254
+ export function formatEventRow(event, index) {
255
+ const agentId = 'agentId' in event ? String(event.agentId) : '-';
256
+ return [
257
+ String(index),
258
+ event.type,
259
+ truncate(agentId, 24),
260
+ formatTimestamp(event.timestamp),
261
+ ];
262
+ }
@@ -0,0 +1,14 @@
1
+ import type { SessionId } from '@roj-ai/sdk';
2
+ import type { RpcClient } from '@roj-ai/shared/rpc';
3
+ export declare function eventsCommand(client: RpcClient, sessionId: string, flags: Record<string, string | true>, json: boolean): Promise<void>;
4
+ export declare function llmCallsCommand(client: RpcClient, sessionId: string, flags: Record<string, string | true>, json: boolean): Promise<void>;
5
+ export declare function llmCallCommand(client: RpcClient, sessionId: string, callId: string, json: boolean): Promise<void>;
6
+ export declare function presetAgentsCommand(client: RpcClient, sessionId: SessionId, json: boolean): Promise<void>;
7
+ export declare function debugSendCommand(client: RpcClient, sessionId: string, agentId: string, content: string, flags: Record<string, string | true>, json: boolean): Promise<void>;
8
+ export declare function spawnAgentCommand(client: RpcClient, sessionId: string, definitionName: string, parentId: string, flags: Record<string, string | true>, json: boolean): Promise<void>;
9
+ export declare function agentsCommand(client: RpcClient, sessionId: string, json: boolean): Promise<void>;
10
+ export declare function agentCommand(client: RpcClient, sessionId: string, agentId: string, json: boolean): Promise<void>;
11
+ export declare function mailboxCommand(client: RpcClient, sessionId: string, json: boolean): Promise<void>;
12
+ export declare function timelineCommand(client: RpcClient, sessionId: string, json: boolean): Promise<void>;
13
+ export declare function metricsCommand(client: RpcClient, sessionId: string, json: boolean): Promise<void>;
14
+ //# sourceMappingURL=debug.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../../src/commands/debug.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgC,SAAS,EAAE,MAAM,aAAa,CAAA;AA0B1E,OAAO,KAAK,EAAE,SAAS,EAAa,MAAM,oBAAoB,CAAA;AAmD9D,wBAAsB,aAAa,CAClC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,EACpC,IAAI,EAAE,OAAO,GACX,OAAO,CAAC,IAAI,CAAC,CAuBf;AAED,wBAAsB,eAAe,CACpC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,EACpC,IAAI,EAAE,OAAO,GACX,OAAO,CAAC,IAAI,CAAC,CA2Bf;AAED,wBAAsB,cAAc,CACnC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,OAAO,GACX,OAAO,CAAC,IAAI,CAAC,CAcf;AAED,wBAAsB,mBAAmB,CACxC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,OAAO,GACX,OAAO,CAAC,IAAI,CAAC,CAmBf;AAED,wBAAsB,gBAAgB,CACrC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,EACpC,IAAI,EAAE,OAAO,GACX,OAAO,CAAC,IAAI,CAAC,CASf;AAED,wBAAsB,iBAAiB,CACtC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,EACpC,IAAI,EAAE,OAAO,GACX,OAAO,CAAC,IAAI,CAAC,CAUf;AAMD,wBAAsB,aAAa,CAClC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,OAAO,GACX,OAAO,CAAC,IAAI,CAAC,CAef;AAED,wBAAsB,YAAY,CACjC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,OAAO,GACX,OAAO,CAAC,IAAI,CAAC,CAef;AAED,wBAAsB,cAAc,CACnC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,OAAO,GACX,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED,wBAAsB,eAAe,CACpC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,OAAO,GACX,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED,wBAAsB,cAAc,CACnC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,OAAO,GACX,OAAO,CAAC,IAAI,CAAC,CAef"}
@@ -0,0 +1,187 @@
1
+ import { AgentId, applyEventToAgentDetail, applyEventToAgentRegistry, applyEventToAgentTree, applyEventToMailbox, applyEventToMetrics, applyEventToTimeline, buildAgentTreeFromProjection, createAgentDetailProjectionState, createAgentRegistryState, createAgentTreeProjectionState, createMailboxState, createMetricsState, createTimelineState, getAgentDetail, getMailboxMessages, getTimelineItems, isDomainEvent, metricsStateToResponse, } from '@roj-ai/shared';
2
+ import { formatTable } from '../repl/formatter.js';
3
+ import { unwrap } from '../unwrap.js';
4
+ import { formatAgentDetail, formatAgentTree, formatEventRow, formatLLMCallDetail, formatMailboxMessage, formatMetrics, formatTimelineItem, } from './debug-format.js';
5
+ // ============================================================================
6
+ // Helpers
7
+ // ============================================================================
8
+ function isLLMCallLogEntry(data) {
9
+ return typeof data === 'object' && data !== null && 'id' in data && 'status' in data && 'request' in data;
10
+ }
11
+ async function loadProjections(client, sessionId) {
12
+ const { events: rawEvents } = unwrap(await client.call('sessions.getEvents', { sessionId, limit: 10000 }));
13
+ const events = rawEvents.filter(isDomainEvent);
14
+ let registry = createAgentRegistryState();
15
+ let agentTree = createAgentTreeProjectionState();
16
+ let agentDetail = createAgentDetailProjectionState();
17
+ for (const event of events) {
18
+ const e = event;
19
+ registry = applyEventToAgentRegistry(registry, e);
20
+ agentTree = applyEventToAgentTree(agentTree, e);
21
+ agentDetail = applyEventToAgentDetail(agentDetail, e);
22
+ }
23
+ return { registry, agentTree, agentDetail, events };
24
+ }
25
+ // ============================================================================
26
+ // Direct RPC Commands
27
+ // ============================================================================
28
+ export async function eventsCommand(client, sessionId, flags, json) {
29
+ const limit = typeof flags.limit === 'string' ? parseInt(flags.limit, 10) : undefined;
30
+ const type = typeof flags.type === 'string' ? flags.type : undefined;
31
+ const agentId = typeof flags.agent === 'string' ? flags.agent : undefined;
32
+ const { events: rawEvents, total } = unwrap(await client.call('sessions.getEvents', { sessionId, limit, type, agentId }));
33
+ const events = rawEvents.filter(isDomainEvent);
34
+ if (json) {
35
+ console.log(JSON.stringify({ events, total }, null, 2));
36
+ return;
37
+ }
38
+ if (events.length === 0) {
39
+ console.log('No events found.');
40
+ return;
41
+ }
42
+ console.log(formatTable(['#', 'Type', 'Agent', 'Time'], events.map((e, i) => formatEventRow(e, i))));
43
+ console.log(`\nTotal: ${total} events`);
44
+ }
45
+ export async function llmCallsCommand(client, sessionId, flags, json) {
46
+ const limit = typeof flags.limit === 'string' ? parseInt(flags.limit, 10) : undefined;
47
+ const { calls, total } = unwrap(await client.call('llm.getCalls', { sessionId, limit }));
48
+ if (json) {
49
+ console.log(JSON.stringify({ calls, total }, null, 2));
50
+ return;
51
+ }
52
+ if (calls.length === 0) {
53
+ console.log('No LLM calls found.');
54
+ return;
55
+ }
56
+ const typedCalls = calls.filter(isLLMCallLogEntry);
57
+ console.log(formatTable(['Time', 'Status', 'Model', 'Duration', 'Tokens', 'Cost', 'Agent'], typedCalls.map((c) => {
58
+ const time = new Date(c.createdAt).toLocaleTimeString();
59
+ const duration = c.durationMs !== undefined ? `${(c.durationMs / 1000).toFixed(1)}s` : '-';
60
+ const tokens = c.metrics ? `${c.metrics.promptTokens}/${c.metrics.completionTokens}` : '-';
61
+ const cost = c.metrics?.cost !== undefined ? `$${c.metrics.cost.toFixed(4)}` : '-';
62
+ return [time, c.status, c.request.model, duration, tokens, cost, String(c.agentId)];
63
+ })));
64
+ console.log(`\nTotal: ${total} calls`);
65
+ }
66
+ export async function llmCallCommand(client, sessionId, callId, json) {
67
+ const callData = unwrap(await client.call('llm.getCall', { sessionId, callId }));
68
+ if (json) {
69
+ console.log(JSON.stringify(callData, null, 2));
70
+ return;
71
+ }
72
+ if (!isLLMCallLogEntry(callData)) {
73
+ console.error('Invalid LLM call data.');
74
+ return;
75
+ }
76
+ console.log(formatLLMCallDetail(callData));
77
+ }
78
+ export async function presetAgentsCommand(client, sessionId, json) {
79
+ const result = unwrap(await client.call('presets.getAgents', { sessionId }));
80
+ const agents = result.agents;
81
+ if (json) {
82
+ console.log(JSON.stringify(agents, null, 2));
83
+ return;
84
+ }
85
+ if (agents.length === 0) {
86
+ console.log('No agent definitions found.');
87
+ return;
88
+ }
89
+ console.log(formatTable(['Name', 'Spawnable By', 'Has Input Schema'], agents.map((a) => [a.name, a.spawnableBy.join(', '), a.hasInputSchema ? 'yes' : 'no'])));
90
+ }
91
+ export async function debugSendCommand(client, sessionId, agentId, content, flags, json) {
92
+ const { messageId } = unwrap(await client.call('user-chat.sendMessage', { sessionId, agentId: AgentId(agentId), content }));
93
+ if (json) {
94
+ console.log(JSON.stringify({ messageId }));
95
+ return;
96
+ }
97
+ console.log(`Message sent: ${messageId}`);
98
+ }
99
+ export async function spawnAgentCommand(client, sessionId, definitionName, parentId, flags, json) {
100
+ const message = typeof flags.message === 'string' ? flags.message : undefined;
101
+ const { agentId } = unwrap(await client.call('agents.spawn', { sessionId, definitionName, parentId: AgentId(parentId), message }));
102
+ if (json) {
103
+ console.log(JSON.stringify({ agentId }));
104
+ return;
105
+ }
106
+ console.log(`Agent spawned: ${agentId}`);
107
+ }
108
+ // ============================================================================
109
+ // Event-sourced Projection Commands
110
+ // ============================================================================
111
+ export async function agentsCommand(client, sessionId, json) {
112
+ const { agentTree: agentTreeState } = await loadProjections(client, sessionId);
113
+ const tree = buildAgentTreeFromProjection(agentTreeState);
114
+ if (json) {
115
+ console.log(JSON.stringify(tree, null, 2));
116
+ return;
117
+ }
118
+ if (tree.length === 0) {
119
+ console.log('No agents.');
120
+ return;
121
+ }
122
+ console.log(formatAgentTree(tree));
123
+ }
124
+ export async function agentCommand(client, sessionId, agentId, json) {
125
+ const { agentDetail: agentDetailState } = await loadProjections(client, sessionId);
126
+ const detail = getAgentDetail(agentDetailState, AgentId(agentId));
127
+ if (!detail) {
128
+ console.error(`Agent not found: ${agentId}`);
129
+ process.exit(1);
130
+ }
131
+ if (json) {
132
+ console.log(JSON.stringify(detail, null, 2));
133
+ return;
134
+ }
135
+ console.log(formatAgentDetail(detail));
136
+ }
137
+ export async function mailboxCommand(client, sessionId, json) {
138
+ const { registry, events } = await loadProjections(client, sessionId);
139
+ let mailboxState = createMailboxState();
140
+ for (const event of events) {
141
+ mailboxState = applyEventToMailbox(mailboxState, event, registry);
142
+ }
143
+ const messages = getMailboxMessages(mailboxState);
144
+ if (json) {
145
+ console.log(JSON.stringify(messages, null, 2));
146
+ return;
147
+ }
148
+ if (messages.length === 0) {
149
+ console.log('No mailbox messages.');
150
+ return;
151
+ }
152
+ for (const msg of messages) {
153
+ console.log(formatMailboxMessage(msg));
154
+ }
155
+ }
156
+ export async function timelineCommand(client, sessionId, json) {
157
+ const { registry, events } = await loadProjections(client, sessionId);
158
+ let timelineState = createTimelineState();
159
+ for (const event of events) {
160
+ timelineState = applyEventToTimeline(timelineState, event, registry);
161
+ }
162
+ const items = getTimelineItems(timelineState, registry);
163
+ if (json) {
164
+ console.log(JSON.stringify(items, null, 2));
165
+ return;
166
+ }
167
+ if (items.length === 0) {
168
+ console.log('No timeline items.');
169
+ return;
170
+ }
171
+ for (const item of items) {
172
+ console.log(formatTimelineItem(item));
173
+ }
174
+ }
175
+ export async function metricsCommand(client, sessionId, json) {
176
+ const { registry, events } = await loadProjections(client, sessionId);
177
+ let metricsState = createMetricsState();
178
+ for (const event of events) {
179
+ metricsState = applyEventToMetrics(metricsState, event);
180
+ }
181
+ const metrics = metricsStateToResponse(metricsState, registry.count);
182
+ if (json) {
183
+ console.log(JSON.stringify(metrics, null, 2));
184
+ return;
185
+ }
186
+ console.log(formatMetrics(metrics));
187
+ }
@@ -0,0 +1,4 @@
1
+ import type { RpcClient } from '@roj-ai/shared/rpc';
2
+ export declare function messagesCommand(client: RpcClient, sessionId: string, json: boolean): Promise<void>;
3
+ export declare function sendCommand(client: RpcClient, baseUrl: string, sessionId: string, content: string, wait: boolean, json: boolean): Promise<void>;
4
+ //# sourceMappingURL=messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/commands/messages.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AASnD,wBAAsB,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBxG;AAED,wBAAsB,WAAW,CAChC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,OAAO,GACX,OAAO,CAAC,IAAI,CAAC,CAqDf"}
@@ -0,0 +1,77 @@
1
+ import { AgentId } from '@roj-ai/shared';
2
+ import { connectWebSocket } from '../client.js';
3
+ import { formatChatMessage } from '../repl/formatter.js';
4
+ import { unwrap } from '../unwrap.js';
5
+ function isChatMessage(msg) {
6
+ return typeof msg === 'object' && msg !== null && 'type' in msg && 'timestamp' in msg;
7
+ }
8
+ export async function messagesCommand(client, sessionId, json) {
9
+ const { messages: rawMessages } = unwrap(await client.call('user-chat.getMessages', { sessionId }));
10
+ const messages = rawMessages.filter(isChatMessage);
11
+ if (json) {
12
+ console.log(JSON.stringify(messages, null, 2));
13
+ return;
14
+ }
15
+ if (messages.length === 0) {
16
+ console.log('No messages.');
17
+ return;
18
+ }
19
+ for (const msg of messages) {
20
+ console.log(formatChatMessage(msg));
21
+ console.log();
22
+ }
23
+ }
24
+ export async function sendCommand(client, baseUrl, sessionId, content, wait, json) {
25
+ const session = unwrap(await client.call('sessions.get', { sessionId }));
26
+ if (!session.entryAgentId) {
27
+ console.error('No entry agent found for session.');
28
+ process.exit(1);
29
+ }
30
+ const { messageId } = unwrap(await client.call('user-chat.sendMessage', { sessionId, agentId: AgentId(session.entryAgentId), content }));
31
+ if (!wait) {
32
+ if (json) {
33
+ console.log(JSON.stringify({ messageId }));
34
+ }
35
+ else {
36
+ console.log(`Message sent: ${messageId}`);
37
+ }
38
+ return;
39
+ }
40
+ // Wait for agent response via WebSocket
41
+ const responsePromise = new Promise((resolve, reject) => {
42
+ const timeout = setTimeout(() => {
43
+ connection.disconnect();
44
+ reject(new Error('Timeout waiting for agent response'));
45
+ }, 120_000);
46
+ const connection = connectWebSocket(baseUrl, sessionId, {
47
+ agentMessage: (payload) => {
48
+ if (typeof payload !== 'object' || payload === null)
49
+ return;
50
+ const input = payload;
51
+ if (typeof input.content !== 'string')
52
+ return;
53
+ clearTimeout(timeout);
54
+ connection.disconnect();
55
+ resolve(input.content);
56
+ },
57
+ error: (payload) => {
58
+ if (typeof payload !== 'object' || payload === null)
59
+ return;
60
+ const input = payload;
61
+ if (typeof input.message !== 'string')
62
+ return;
63
+ clearTimeout(timeout);
64
+ connection.disconnect();
65
+ reject(new Error(input.message));
66
+ },
67
+ });
68
+ connection.connect().catch(reject);
69
+ });
70
+ const response = await responsePromise;
71
+ if (json) {
72
+ console.log(JSON.stringify({ messageId, response }));
73
+ }
74
+ else {
75
+ console.log(response);
76
+ }
77
+ }
@@ -0,0 +1,3 @@
1
+ import type { RpcClient } from '@roj-ai/shared/rpc';
2
+ export declare function presetsCommand(client: RpcClient, json: boolean): Promise<void>;
3
+ //# sourceMappingURL=presets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../src/commands/presets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAInD,wBAAsB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBpF"}