@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.
- package/dist/client.d.ts +8 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +28 -0
- package/dist/commands/answer.d.ts +3 -0
- package/dist/commands/answer.d.ts.map +1 -0
- package/dist/commands/answer.js +15 -0
- package/dist/commands/debug-format.d.ts +12 -0
- package/dist/commands/debug-format.d.ts.map +1 -0
- package/dist/commands/debug-format.js +262 -0
- package/dist/commands/debug.d.ts +14 -0
- package/dist/commands/debug.d.ts.map +1 -0
- package/dist/commands/debug.js +187 -0
- package/dist/commands/messages.d.ts +4 -0
- package/dist/commands/messages.d.ts.map +1 -0
- package/dist/commands/messages.js +77 -0
- package/dist/commands/presets.d.ts +3 -0
- package/dist/commands/presets.d.ts.map +1 -0
- package/dist/commands/presets.js +14 -0
- package/dist/commands/sessions.d.ts +6 -0
- package/dist/commands/sessions.d.ts.map +1 -0
- package/dist/commands/sessions.js +50 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +277 -0
- package/dist/repl/formatter.d.ts +16 -0
- package/dist/repl/formatter.d.ts.map +1 -0
- package/dist/repl/formatter.js +72 -0
- package/dist/repl/repl.d.ts +3 -0
- package/dist/repl/repl.d.ts.map +1 -0
- package/dist/repl/repl.js +212 -0
- package/dist/repl/session-picker.d.ts +6 -0
- package/dist/repl/session-picker.d.ts.map +1 -0
- package/dist/repl/session-picker.js +60 -0
- package/dist/unwrap.d.ts +4 -0
- package/dist/unwrap.d.ts.map +1 -0
- package/dist/unwrap.js +6 -0
- package/package.json +27 -0
- package/src/client.ts +41 -0
- package/src/commands/answer.ts +27 -0
- package/src/commands/debug-format.ts +299 -0
- package/src/commands/debug.ts +347 -0
- package/src/commands/messages.ts +92 -0
- package/src/commands/presets.ts +22 -0
- package/src/commands/sessions.ts +73 -0
- package/src/main.ts +319 -0
- package/src/repl/formatter.ts +84 -0
- package/src/repl/repl.ts +246 -0
- package/src/repl/session-picker.ts +81 -0
- package/src/unwrap.ts +8 -0
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import type { DomainEvent, LLMCallLogEntry, SessionId } from '@roj-ai/sdk'
|
|
2
|
+
import type { GetAgentDetailResponse, ProjectionEvent } from '@roj-ai/shared'
|
|
3
|
+
import {
|
|
4
|
+
type AgentDetailProjectionState,
|
|
5
|
+
AgentId,
|
|
6
|
+
type AgentRegistryState,
|
|
7
|
+
type AgentTreeProjectionState,
|
|
8
|
+
applyEventToAgentDetail,
|
|
9
|
+
applyEventToAgentRegistry,
|
|
10
|
+
applyEventToAgentTree,
|
|
11
|
+
applyEventToMailbox,
|
|
12
|
+
applyEventToMetrics,
|
|
13
|
+
applyEventToTimeline,
|
|
14
|
+
buildAgentTreeFromProjection,
|
|
15
|
+
createAgentDetailProjectionState,
|
|
16
|
+
createAgentRegistryState,
|
|
17
|
+
createAgentTreeProjectionState,
|
|
18
|
+
createMailboxState,
|
|
19
|
+
createMetricsState,
|
|
20
|
+
createTimelineState,
|
|
21
|
+
getAgentDetail,
|
|
22
|
+
getMailboxMessages,
|
|
23
|
+
getTimelineItems,
|
|
24
|
+
isDomainEvent,
|
|
25
|
+
metricsStateToResponse,
|
|
26
|
+
} from '@roj-ai/shared'
|
|
27
|
+
import type { RpcClient, RpcOutput } from '@roj-ai/shared/rpc'
|
|
28
|
+
import { formatTable } from '../repl/formatter.js'
|
|
29
|
+
import { unwrap } from '../unwrap.js'
|
|
30
|
+
import {
|
|
31
|
+
formatAgentDetail,
|
|
32
|
+
formatAgentTree,
|
|
33
|
+
formatEventRow,
|
|
34
|
+
formatLLMCallDetail,
|
|
35
|
+
formatMailboxMessage,
|
|
36
|
+
formatMetrics,
|
|
37
|
+
formatTimelineItem,
|
|
38
|
+
truncate,
|
|
39
|
+
} from './debug-format.js'
|
|
40
|
+
|
|
41
|
+
// ============================================================================
|
|
42
|
+
// Helpers
|
|
43
|
+
// ============================================================================
|
|
44
|
+
|
|
45
|
+
function isLLMCallLogEntry(data: unknown): data is LLMCallLogEntry {
|
|
46
|
+
return typeof data === 'object' && data !== null && 'id' in data && 'status' in data && 'request' in data
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface LoadedProjections {
|
|
50
|
+
registry: AgentRegistryState
|
|
51
|
+
agentTree: AgentTreeProjectionState
|
|
52
|
+
agentDetail: AgentDetailProjectionState
|
|
53
|
+
events: DomainEvent[]
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function loadProjections(client: RpcClient, sessionId: string): Promise<LoadedProjections> {
|
|
57
|
+
const { events: rawEvents } = unwrap(await client.call('sessions.getEvents', { sessionId, limit: 10000 }))
|
|
58
|
+
const events = rawEvents.filter(isDomainEvent)
|
|
59
|
+
|
|
60
|
+
let registry = createAgentRegistryState()
|
|
61
|
+
let agentTree = createAgentTreeProjectionState()
|
|
62
|
+
let agentDetail = createAgentDetailProjectionState()
|
|
63
|
+
|
|
64
|
+
for (const event of events) {
|
|
65
|
+
const e = event as ProjectionEvent
|
|
66
|
+
registry = applyEventToAgentRegistry(registry, e)
|
|
67
|
+
agentTree = applyEventToAgentTree(agentTree, e)
|
|
68
|
+
agentDetail = applyEventToAgentDetail(agentDetail, e)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return { registry, agentTree, agentDetail, events }
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ============================================================================
|
|
75
|
+
// Direct RPC Commands
|
|
76
|
+
// ============================================================================
|
|
77
|
+
|
|
78
|
+
export async function eventsCommand(
|
|
79
|
+
client: RpcClient,
|
|
80
|
+
sessionId: string,
|
|
81
|
+
flags: Record<string, string | true>,
|
|
82
|
+
json: boolean,
|
|
83
|
+
): Promise<void> {
|
|
84
|
+
const limit = typeof flags.limit === 'string' ? parseInt(flags.limit, 10) : undefined
|
|
85
|
+
const type = typeof flags.type === 'string' ? flags.type : undefined
|
|
86
|
+
const agentId = typeof flags.agent === 'string' ? flags.agent : undefined
|
|
87
|
+
|
|
88
|
+
const { events: rawEvents, total } = unwrap(await client.call('sessions.getEvents', { sessionId, limit, type, agentId }))
|
|
89
|
+
const events = rawEvents.filter(isDomainEvent)
|
|
90
|
+
|
|
91
|
+
if (json) {
|
|
92
|
+
console.log(JSON.stringify({ events, total }, null, 2))
|
|
93
|
+
return
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (events.length === 0) {
|
|
97
|
+
console.log('No events found.')
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
console.log(formatTable(
|
|
102
|
+
['#', 'Type', 'Agent', 'Time'],
|
|
103
|
+
events.map((e, i) => formatEventRow(e, i)),
|
|
104
|
+
))
|
|
105
|
+
console.log(`\nTotal: ${total} events`)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export async function llmCallsCommand(
|
|
109
|
+
client: RpcClient,
|
|
110
|
+
sessionId: string,
|
|
111
|
+
flags: Record<string, string | true>,
|
|
112
|
+
json: boolean,
|
|
113
|
+
): Promise<void> {
|
|
114
|
+
const limit = typeof flags.limit === 'string' ? parseInt(flags.limit, 10) : undefined
|
|
115
|
+
|
|
116
|
+
const { calls, total } = unwrap(await client.call('llm.getCalls', { sessionId, limit }))
|
|
117
|
+
|
|
118
|
+
if (json) {
|
|
119
|
+
console.log(JSON.stringify({ calls, total }, null, 2))
|
|
120
|
+
return
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (calls.length === 0) {
|
|
124
|
+
console.log('No LLM calls found.')
|
|
125
|
+
return
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const typedCalls = calls.filter(isLLMCallLogEntry)
|
|
129
|
+
console.log(formatTable(
|
|
130
|
+
['Time', 'Status', 'Model', 'Duration', 'Tokens', 'Cost', 'Agent'],
|
|
131
|
+
typedCalls.map((c) => {
|
|
132
|
+
const time = new Date(c.createdAt).toLocaleTimeString()
|
|
133
|
+
const duration = c.durationMs !== undefined ? `${(c.durationMs / 1000).toFixed(1)}s` : '-'
|
|
134
|
+
const tokens = c.metrics ? `${c.metrics.promptTokens}/${c.metrics.completionTokens}` : '-'
|
|
135
|
+
const cost = c.metrics?.cost !== undefined ? `$${c.metrics.cost.toFixed(4)}` : '-'
|
|
136
|
+
return [time, c.status, c.request.model, duration, tokens, cost, String(c.agentId)]
|
|
137
|
+
}),
|
|
138
|
+
))
|
|
139
|
+
console.log(`\nTotal: ${total} calls`)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export async function llmCallCommand(
|
|
143
|
+
client: RpcClient,
|
|
144
|
+
sessionId: string,
|
|
145
|
+
callId: string,
|
|
146
|
+
json: boolean,
|
|
147
|
+
): Promise<void> {
|
|
148
|
+
const callData = unwrap(await client.call('llm.getCall', { sessionId, callId }))
|
|
149
|
+
|
|
150
|
+
if (json) {
|
|
151
|
+
console.log(JSON.stringify(callData, null, 2))
|
|
152
|
+
return
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (!isLLMCallLogEntry(callData)) {
|
|
156
|
+
console.error('Invalid LLM call data.')
|
|
157
|
+
return
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
console.log(formatLLMCallDetail(callData))
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export async function presetAgentsCommand(
|
|
164
|
+
client: RpcClient,
|
|
165
|
+
sessionId: SessionId,
|
|
166
|
+
json: boolean,
|
|
167
|
+
): Promise<void> {
|
|
168
|
+
const result = unwrap(await client.call('presets.getAgents', { sessionId }))
|
|
169
|
+
const agents = result.agents
|
|
170
|
+
|
|
171
|
+
if (json) {
|
|
172
|
+
console.log(JSON.stringify(agents, null, 2))
|
|
173
|
+
return
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (agents.length === 0) {
|
|
177
|
+
console.log('No agent definitions found.')
|
|
178
|
+
return
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
type PresetAgent = RpcOutput<'presets.getAgents'>['agents'][number]
|
|
182
|
+
console.log(formatTable(
|
|
183
|
+
['Name', 'Spawnable By', 'Has Input Schema'],
|
|
184
|
+
agents.map((a: PresetAgent) => [a.name, a.spawnableBy.join(', '), a.hasInputSchema ? 'yes' : 'no']),
|
|
185
|
+
))
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export async function debugSendCommand(
|
|
189
|
+
client: RpcClient,
|
|
190
|
+
sessionId: string,
|
|
191
|
+
agentId: string,
|
|
192
|
+
content: string,
|
|
193
|
+
flags: Record<string, string | true>,
|
|
194
|
+
json: boolean,
|
|
195
|
+
): Promise<void> {
|
|
196
|
+
const { messageId } = unwrap(await client.call('user-chat.sendMessage', { sessionId, agentId: AgentId(agentId), content }))
|
|
197
|
+
|
|
198
|
+
if (json) {
|
|
199
|
+
console.log(JSON.stringify({ messageId }))
|
|
200
|
+
return
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
console.log(`Message sent: ${messageId}`)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export async function spawnAgentCommand(
|
|
207
|
+
client: RpcClient,
|
|
208
|
+
sessionId: string,
|
|
209
|
+
definitionName: string,
|
|
210
|
+
parentId: string,
|
|
211
|
+
flags: Record<string, string | true>,
|
|
212
|
+
json: boolean,
|
|
213
|
+
): Promise<void> {
|
|
214
|
+
const message = typeof flags.message === 'string' ? flags.message : undefined
|
|
215
|
+
const { agentId } = unwrap(await client.call('agents.spawn', { sessionId, definitionName, parentId: AgentId(parentId), message }))
|
|
216
|
+
|
|
217
|
+
if (json) {
|
|
218
|
+
console.log(JSON.stringify({ agentId }))
|
|
219
|
+
return
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
console.log(`Agent spawned: ${agentId}`)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// ============================================================================
|
|
226
|
+
// Event-sourced Projection Commands
|
|
227
|
+
// ============================================================================
|
|
228
|
+
|
|
229
|
+
export async function agentsCommand(
|
|
230
|
+
client: RpcClient,
|
|
231
|
+
sessionId: string,
|
|
232
|
+
json: boolean,
|
|
233
|
+
): Promise<void> {
|
|
234
|
+
const { agentTree: agentTreeState } = await loadProjections(client, sessionId)
|
|
235
|
+
const tree = buildAgentTreeFromProjection(agentTreeState)
|
|
236
|
+
|
|
237
|
+
if (json) {
|
|
238
|
+
console.log(JSON.stringify(tree, null, 2))
|
|
239
|
+
return
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (tree.length === 0) {
|
|
243
|
+
console.log('No agents.')
|
|
244
|
+
return
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
console.log(formatAgentTree(tree))
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export async function agentCommand(
|
|
251
|
+
client: RpcClient,
|
|
252
|
+
sessionId: string,
|
|
253
|
+
agentId: string,
|
|
254
|
+
json: boolean,
|
|
255
|
+
): Promise<void> {
|
|
256
|
+
const { agentDetail: agentDetailState } = await loadProjections(client, sessionId)
|
|
257
|
+
const detail = getAgentDetail(agentDetailState, AgentId(agentId))
|
|
258
|
+
|
|
259
|
+
if (!detail) {
|
|
260
|
+
console.error(`Agent not found: ${agentId}`)
|
|
261
|
+
process.exit(1)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (json) {
|
|
265
|
+
console.log(JSON.stringify(detail, null, 2))
|
|
266
|
+
return
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
console.log(formatAgentDetail(detail))
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export async function mailboxCommand(
|
|
273
|
+
client: RpcClient,
|
|
274
|
+
sessionId: string,
|
|
275
|
+
json: boolean,
|
|
276
|
+
): Promise<void> {
|
|
277
|
+
const { registry, events } = await loadProjections(client, sessionId)
|
|
278
|
+
|
|
279
|
+
let mailboxState = createMailboxState()
|
|
280
|
+
for (const event of events) {
|
|
281
|
+
mailboxState = applyEventToMailbox(mailboxState, event as ProjectionEvent, registry)
|
|
282
|
+
}
|
|
283
|
+
const messages = getMailboxMessages(mailboxState)
|
|
284
|
+
|
|
285
|
+
if (json) {
|
|
286
|
+
console.log(JSON.stringify(messages, null, 2))
|
|
287
|
+
return
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (messages.length === 0) {
|
|
291
|
+
console.log('No mailbox messages.')
|
|
292
|
+
return
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
for (const msg of messages) {
|
|
296
|
+
console.log(formatMailboxMessage(msg))
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
export async function timelineCommand(
|
|
301
|
+
client: RpcClient,
|
|
302
|
+
sessionId: string,
|
|
303
|
+
json: boolean,
|
|
304
|
+
): Promise<void> {
|
|
305
|
+
const { registry, events } = await loadProjections(client, sessionId)
|
|
306
|
+
|
|
307
|
+
let timelineState = createTimelineState()
|
|
308
|
+
for (const event of events) {
|
|
309
|
+
timelineState = applyEventToTimeline(timelineState, event as ProjectionEvent, registry)
|
|
310
|
+
}
|
|
311
|
+
const items = getTimelineItems(timelineState, registry)
|
|
312
|
+
|
|
313
|
+
if (json) {
|
|
314
|
+
console.log(JSON.stringify(items, null, 2))
|
|
315
|
+
return
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (items.length === 0) {
|
|
319
|
+
console.log('No timeline items.')
|
|
320
|
+
return
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
for (const item of items) {
|
|
324
|
+
console.log(formatTimelineItem(item))
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export async function metricsCommand(
|
|
329
|
+
client: RpcClient,
|
|
330
|
+
sessionId: string,
|
|
331
|
+
json: boolean,
|
|
332
|
+
): Promise<void> {
|
|
333
|
+
const { registry, events } = await loadProjections(client, sessionId)
|
|
334
|
+
|
|
335
|
+
let metricsState = createMetricsState()
|
|
336
|
+
for (const event of events) {
|
|
337
|
+
metricsState = applyEventToMetrics(metricsState, event as ProjectionEvent)
|
|
338
|
+
}
|
|
339
|
+
const metrics = metricsStateToResponse(metricsState, registry.count)
|
|
340
|
+
|
|
341
|
+
if (json) {
|
|
342
|
+
console.log(JSON.stringify(metrics, null, 2))
|
|
343
|
+
return
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
console.log(formatMetrics(metrics))
|
|
347
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { ChatMessage } from '@roj-ai/sdk'
|
|
2
|
+
import { AgentId } from '@roj-ai/shared'
|
|
3
|
+
import type { RpcClient } from '@roj-ai/shared/rpc'
|
|
4
|
+
import { connectWebSocket } from '../client.js'
|
|
5
|
+
import { formatChatMessage } from '../repl/formatter.js'
|
|
6
|
+
import { unwrap } from '../unwrap.js'
|
|
7
|
+
|
|
8
|
+
function isChatMessage(msg: unknown): msg is ChatMessage {
|
|
9
|
+
return typeof msg === 'object' && msg !== null && 'type' in msg && 'timestamp' in msg
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function messagesCommand(client: RpcClient, sessionId: string, json: boolean): Promise<void> {
|
|
13
|
+
const { messages: rawMessages } = unwrap(await client.call('user-chat.getMessages', { sessionId }))
|
|
14
|
+
const messages = rawMessages.filter(isChatMessage)
|
|
15
|
+
|
|
16
|
+
if (json) {
|
|
17
|
+
console.log(JSON.stringify(messages, null, 2))
|
|
18
|
+
return
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (messages.length === 0) {
|
|
22
|
+
console.log('No messages.')
|
|
23
|
+
return
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
for (const msg of messages) {
|
|
27
|
+
console.log(formatChatMessage(msg))
|
|
28
|
+
console.log()
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function sendCommand(
|
|
33
|
+
client: RpcClient,
|
|
34
|
+
baseUrl: string,
|
|
35
|
+
sessionId: string,
|
|
36
|
+
content: string,
|
|
37
|
+
wait: boolean,
|
|
38
|
+
json: boolean,
|
|
39
|
+
): Promise<void> {
|
|
40
|
+
const session = unwrap(await client.call('sessions.get', { sessionId }))
|
|
41
|
+
if (!session.entryAgentId) {
|
|
42
|
+
console.error('No entry agent found for session.')
|
|
43
|
+
process.exit(1)
|
|
44
|
+
}
|
|
45
|
+
const { messageId } = unwrap(await client.call('user-chat.sendMessage', { sessionId, agentId: AgentId(session.entryAgentId), content }))
|
|
46
|
+
|
|
47
|
+
if (!wait) {
|
|
48
|
+
if (json) {
|
|
49
|
+
console.log(JSON.stringify({ messageId }))
|
|
50
|
+
} else {
|
|
51
|
+
console.log(`Message sent: ${messageId}`)
|
|
52
|
+
}
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Wait for agent response via WebSocket
|
|
57
|
+
const responsePromise = new Promise<string>((resolve, reject) => {
|
|
58
|
+
const timeout = setTimeout(() => {
|
|
59
|
+
connection.disconnect()
|
|
60
|
+
reject(new Error('Timeout waiting for agent response'))
|
|
61
|
+
}, 120_000)
|
|
62
|
+
|
|
63
|
+
const connection = connectWebSocket(baseUrl, sessionId, {
|
|
64
|
+
agentMessage: (payload) => {
|
|
65
|
+
if (typeof payload !== 'object' || payload === null) return
|
|
66
|
+
const input = payload as Record<string, unknown>
|
|
67
|
+
if (typeof input.content !== 'string') return
|
|
68
|
+
clearTimeout(timeout)
|
|
69
|
+
connection.disconnect()
|
|
70
|
+
resolve(input.content)
|
|
71
|
+
},
|
|
72
|
+
error: (payload) => {
|
|
73
|
+
if (typeof payload !== 'object' || payload === null) return
|
|
74
|
+
const input = payload as Record<string, unknown>
|
|
75
|
+
if (typeof input.message !== 'string') return
|
|
76
|
+
clearTimeout(timeout)
|
|
77
|
+
connection.disconnect()
|
|
78
|
+
reject(new Error(input.message))
|
|
79
|
+
},
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
connection.connect().catch(reject)
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
const response = await responsePromise
|
|
86
|
+
|
|
87
|
+
if (json) {
|
|
88
|
+
console.log(JSON.stringify({ messageId, response }))
|
|
89
|
+
} else {
|
|
90
|
+
console.log(response)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { RpcClient } from '@roj-ai/shared/rpc'
|
|
2
|
+
import { formatTable } from '../repl/formatter.js'
|
|
3
|
+
import { unwrap } from '../unwrap.js'
|
|
4
|
+
|
|
5
|
+
export async function presetsCommand(client: RpcClient, json: boolean): Promise<void> {
|
|
6
|
+
const { presets } = unwrap(await client.call('presets.list', {}))
|
|
7
|
+
|
|
8
|
+
if (json) {
|
|
9
|
+
console.log(JSON.stringify(presets, null, 2))
|
|
10
|
+
return
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (presets.length === 0) {
|
|
14
|
+
console.log('No presets available.')
|
|
15
|
+
return
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
console.log(formatTable(
|
|
19
|
+
['ID', 'Name', 'Description'],
|
|
20
|
+
presets.map(p => [p.id, p.name, p.description ?? '']),
|
|
21
|
+
))
|
|
22
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { SessionMetadata } from '@roj-ai/sdk'
|
|
2
|
+
import type { RpcClient } from '@roj-ai/shared/rpc'
|
|
3
|
+
import { formatSessionInfo, formatTable } from '../repl/formatter.js'
|
|
4
|
+
import { unwrap } from '../unwrap.js'
|
|
5
|
+
|
|
6
|
+
function isSessionMetadata(data: unknown): data is SessionMetadata {
|
|
7
|
+
return typeof data === 'object' && data !== null && 'sessionId' in data && 'presetId' in data
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export async function sessionsListCommand(
|
|
11
|
+
client: RpcClient,
|
|
12
|
+
status: 'active' | 'closed' | 'errored' | undefined,
|
|
13
|
+
json: boolean,
|
|
14
|
+
): Promise<void> {
|
|
15
|
+
const { sessions } = unwrap(await client.call('sessions.list', { status, limit: 50, order: 'desc' }))
|
|
16
|
+
|
|
17
|
+
if (json) {
|
|
18
|
+
console.log(JSON.stringify(sessions, null, 2))
|
|
19
|
+
return
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (sessions.length === 0) {
|
|
23
|
+
console.log('No sessions found.')
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
console.log(formatTable(
|
|
28
|
+
['Session ID', 'Preset', 'Status', 'Created'],
|
|
29
|
+
sessions.filter(isSessionMetadata).map(s => [
|
|
30
|
+
s.sessionId,
|
|
31
|
+
s.presetId,
|
|
32
|
+
s.status,
|
|
33
|
+
new Date(s.createdAt).toLocaleString(),
|
|
34
|
+
]),
|
|
35
|
+
))
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export async function sessionCreateCommand(client: RpcClient, presetId: string, json: boolean): Promise<void> {
|
|
39
|
+
const { sessionId } = unwrap(await client.call('sessions.create', { presetId }))
|
|
40
|
+
|
|
41
|
+
if (json) {
|
|
42
|
+
console.log(JSON.stringify({ sessionId }))
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
console.log(`Session created: ${sessionId}`)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function sessionGetCommand(client: RpcClient, sessionId: string, json: boolean): Promise<void> {
|
|
50
|
+
const session = unwrap(await client.call('sessions.get', { sessionId }))
|
|
51
|
+
|
|
52
|
+
if (json) {
|
|
53
|
+
console.log(JSON.stringify(session, null, 2))
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
console.log(formatSessionInfo(session))
|
|
58
|
+
console.log(` Agents: ${session.agentCount}`)
|
|
59
|
+
if (session.closedAt) {
|
|
60
|
+
console.log(` Closed: ${new Date(session.closedAt).toLocaleString()}`)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function sessionCloseCommand(client: RpcClient, sessionId: string, json: boolean): Promise<void> {
|
|
65
|
+
const result = unwrap(await client.call('sessions.close', { sessionId }))
|
|
66
|
+
|
|
67
|
+
if (json) {
|
|
68
|
+
console.log(JSON.stringify(result))
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
console.log('Session closed.')
|
|
73
|
+
}
|