@astroanywhere/cli 0.1.1 → 0.2.1
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/{chunk-7H7WD7QX.js → chunk-SYY2HHOY.js} +217 -29
- package/dist/client.js +3 -1
- package/dist/index.js +313 -7
- package/dist/tui.js +2812 -0
- package/package.json +13 -4
|
@@ -168,6 +168,10 @@ var AstroClient = class {
|
|
|
168
168
|
async listFileChanges(executionId) {
|
|
169
169
|
return this.get("/api/data/file-changes", { executionId });
|
|
170
170
|
}
|
|
171
|
+
// ── Usage / Cost ────────────────────────────────────────────────────
|
|
172
|
+
async getUsageHistory(weeks = 1) {
|
|
173
|
+
return this.get("/api/data/usage/history", { weeks: String(weeks) });
|
|
174
|
+
}
|
|
171
175
|
// ── Activity ────────────────────────────────────────────────────────
|
|
172
176
|
async listActivities(params) {
|
|
173
177
|
return this.get("/api/data/activities", params);
|
|
@@ -286,12 +290,66 @@ var AstroClient = class {
|
|
|
286
290
|
}
|
|
287
291
|
return res;
|
|
288
292
|
}
|
|
293
|
+
// ── Chat (SSE streaming) ──────────────────────────────────────────
|
|
294
|
+
async projectChat(payload) {
|
|
295
|
+
const url = new URL("/api/agent/project-chat", this.baseUrl);
|
|
296
|
+
const res = await fetch(url.toString(), {
|
|
297
|
+
method: "POST",
|
|
298
|
+
headers: this.headers,
|
|
299
|
+
body: JSON.stringify(payload)
|
|
300
|
+
});
|
|
301
|
+
if (!res.ok) {
|
|
302
|
+
const text = await res.text();
|
|
303
|
+
throw new Error(`Project chat failed (${res.status}): ${text}`);
|
|
304
|
+
}
|
|
305
|
+
return res;
|
|
306
|
+
}
|
|
307
|
+
async taskChat(payload) {
|
|
308
|
+
const url = new URL("/api/agent/task-chat", this.baseUrl);
|
|
309
|
+
const res = await fetch(url.toString(), {
|
|
310
|
+
method: "POST",
|
|
311
|
+
headers: this.headers,
|
|
312
|
+
body: JSON.stringify(payload)
|
|
313
|
+
});
|
|
314
|
+
if (!res.ok) {
|
|
315
|
+
const text = await res.text();
|
|
316
|
+
throw new Error(`Task chat failed (${res.status}): ${text}`);
|
|
317
|
+
}
|
|
318
|
+
return res;
|
|
319
|
+
}
|
|
320
|
+
// ── Approval ───────────────────────────────────────────────────────
|
|
321
|
+
async sendApproval(payload) {
|
|
322
|
+
return this.post("/api/dispatch/approval", payload);
|
|
323
|
+
}
|
|
324
|
+
// ── Slurm Dispatch ────────────────────────────────────────────────
|
|
325
|
+
async dispatchSlurmTask(payload) {
|
|
326
|
+
const url = new URL("/api/relay/slurm/dispatch", this.baseUrl);
|
|
327
|
+
const res = await fetch(url.toString(), {
|
|
328
|
+
method: "POST",
|
|
329
|
+
headers: this.headers,
|
|
330
|
+
body: JSON.stringify(payload)
|
|
331
|
+
});
|
|
332
|
+
if (!res.ok) {
|
|
333
|
+
const text = await res.text();
|
|
334
|
+
throw new Error(`Slurm dispatch failed (${res.status}): ${text}`);
|
|
335
|
+
}
|
|
336
|
+
return res;
|
|
337
|
+
}
|
|
289
338
|
};
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
339
|
+
function parseSSELines(buffer, lines) {
|
|
340
|
+
const events = [];
|
|
341
|
+
for (const line of lines) {
|
|
342
|
+
if (line.startsWith("data: ")) {
|
|
343
|
+
try {
|
|
344
|
+
events.push(JSON.parse(line.slice(6)));
|
|
345
|
+
} catch {
|
|
346
|
+
}
|
|
347
|
+
}
|
|
294
348
|
}
|
|
349
|
+
return events;
|
|
350
|
+
}
|
|
351
|
+
async function readSSEStream(response, handler) {
|
|
352
|
+
if (!response.body) return;
|
|
295
353
|
const reader = response.body.getReader();
|
|
296
354
|
const decoder = new TextDecoder();
|
|
297
355
|
let buffer = "";
|
|
@@ -301,35 +359,164 @@ async function streamDispatchToStdout(response) {
|
|
|
301
359
|
buffer += decoder.decode(value, { stream: true });
|
|
302
360
|
const lines = buffer.split("\n");
|
|
303
361
|
buffer = lines.pop() ?? "";
|
|
304
|
-
for (const
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
362
|
+
for (const event of parseSSELines(buffer, lines)) {
|
|
363
|
+
await handler(event);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
async function streamDispatchToStdout(response, opts) {
|
|
368
|
+
const result = {};
|
|
369
|
+
if (!response.body) {
|
|
370
|
+
console.log("Task dispatched (no stream)");
|
|
371
|
+
return result;
|
|
372
|
+
}
|
|
373
|
+
await readSSEStream(response, async (event) => {
|
|
374
|
+
const type = event.type;
|
|
375
|
+
if (opts?.json) {
|
|
376
|
+
console.log(JSON.stringify(event));
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
switch (type) {
|
|
380
|
+
case "text":
|
|
381
|
+
process.stdout.write(event.content ?? "");
|
|
382
|
+
break;
|
|
383
|
+
case "tool_use":
|
|
384
|
+
process.stderr.write(`
|
|
385
|
+
[tool] ${event.name}
|
|
386
|
+
`);
|
|
387
|
+
break;
|
|
388
|
+
case "tool_result":
|
|
389
|
+
break;
|
|
390
|
+
case "session_init":
|
|
391
|
+
result.sessionId = event.sessionId;
|
|
392
|
+
break;
|
|
393
|
+
case "result":
|
|
394
|
+
console.log(`
|
|
318
395
|
--- Result: ${event.status} ---`);
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
396
|
+
if (event.summary) console.log(event.summary);
|
|
397
|
+
if (event.durationMs || event.inputTokens || event.outputTokens || event.totalCost) {
|
|
398
|
+
result.metrics = {
|
|
399
|
+
durationMs: event.durationMs,
|
|
400
|
+
inputTokens: event.inputTokens,
|
|
401
|
+
outputTokens: event.outputTokens,
|
|
402
|
+
totalCost: event.totalCost,
|
|
403
|
+
model: event.model
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
break;
|
|
407
|
+
case "plan_result":
|
|
408
|
+
console.log("\n--- Plan Generated ---");
|
|
409
|
+
console.log(JSON.stringify(event.plan ?? event, null, 2));
|
|
410
|
+
break;
|
|
411
|
+
case "approval_request":
|
|
412
|
+
if (opts?.onApprovalRequest) {
|
|
413
|
+
const approval = await opts.onApprovalRequest({
|
|
414
|
+
requestId: event.requestId,
|
|
415
|
+
question: event.question,
|
|
416
|
+
options: event.options,
|
|
417
|
+
machineId: event.machineId,
|
|
418
|
+
taskId: event.taskId
|
|
419
|
+
});
|
|
420
|
+
void approval;
|
|
421
|
+
} else {
|
|
422
|
+
process.stderr.write(`
|
|
423
|
+
[approval] ${event.question}
|
|
424
|
+
`);
|
|
425
|
+
process.stderr.write(` Options: ${event.options.join(", ")}
|
|
426
|
+
`);
|
|
427
|
+
}
|
|
428
|
+
break;
|
|
429
|
+
case "error":
|
|
430
|
+
console.error(`
|
|
323
431
|
Error: ${event.message}`);
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
432
|
+
break;
|
|
433
|
+
case "done":
|
|
434
|
+
case "heartbeat":
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
return result;
|
|
439
|
+
}
|
|
440
|
+
async function streamChatToStdout(response, opts) {
|
|
441
|
+
const result = {};
|
|
442
|
+
let assistantText = "";
|
|
443
|
+
if (!response.body) {
|
|
444
|
+
console.log("No stream received");
|
|
445
|
+
return result;
|
|
446
|
+
}
|
|
447
|
+
await readSSEStream(response, async (event) => {
|
|
448
|
+
const type = event.type;
|
|
449
|
+
if (opts?.json) {
|
|
450
|
+
console.log(JSON.stringify(event));
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
switch (type) {
|
|
454
|
+
case "text":
|
|
455
|
+
const content = event.content ?? "";
|
|
456
|
+
process.stdout.write(content);
|
|
457
|
+
assistantText += content;
|
|
458
|
+
break;
|
|
459
|
+
case "tool_use":
|
|
460
|
+
process.stderr.write(`
|
|
461
|
+
[tool] ${event.name}
|
|
462
|
+
`);
|
|
463
|
+
break;
|
|
464
|
+
case "tool_result":
|
|
465
|
+
break;
|
|
466
|
+
case "session_init":
|
|
467
|
+
result.sessionId = event.sessionId;
|
|
468
|
+
break;
|
|
469
|
+
case "file_change":
|
|
470
|
+
process.stderr.write(`[file] ${event.action} ${event.path}
|
|
471
|
+
`);
|
|
472
|
+
break;
|
|
473
|
+
case "compaction":
|
|
474
|
+
process.stderr.write(`[compaction] History compacted: ${event.originalCount} \u2192 ${event.compactedCount} messages
|
|
475
|
+
`);
|
|
476
|
+
break;
|
|
477
|
+
case "plan_result":
|
|
478
|
+
console.log("\n--- Plan Generated ---");
|
|
479
|
+
console.log(JSON.stringify(event.plan ?? event, null, 2));
|
|
480
|
+
break;
|
|
481
|
+
case "approval_request":
|
|
482
|
+
if (opts?.onApprovalRequest) {
|
|
483
|
+
const approval = await opts.onApprovalRequest({
|
|
484
|
+
requestId: event.requestId,
|
|
485
|
+
question: event.question,
|
|
486
|
+
options: event.options,
|
|
487
|
+
machineId: event.machineId,
|
|
488
|
+
taskId: event.taskId
|
|
489
|
+
});
|
|
490
|
+
void approval;
|
|
491
|
+
} else {
|
|
492
|
+
process.stderr.write(`
|
|
493
|
+
[approval] ${event.question}
|
|
494
|
+
`);
|
|
495
|
+
process.stderr.write(` Options: ${event.options.join(", ")}
|
|
496
|
+
`);
|
|
329
497
|
}
|
|
330
|
-
|
|
498
|
+
break;
|
|
499
|
+
case "done":
|
|
500
|
+
if (event.durationMs || event.inputTokens || event.outputTokens || event.totalCost) {
|
|
501
|
+
result.metrics = {
|
|
502
|
+
durationMs: event.durationMs,
|
|
503
|
+
inputTokens: event.inputTokens,
|
|
504
|
+
outputTokens: event.outputTokens,
|
|
505
|
+
totalCost: event.totalCost,
|
|
506
|
+
model: event.model
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
break;
|
|
510
|
+
case "error":
|
|
511
|
+
console.error(`
|
|
512
|
+
Error: ${event.message}`);
|
|
513
|
+
break;
|
|
514
|
+
case "heartbeat":
|
|
515
|
+
break;
|
|
331
516
|
}
|
|
332
|
-
}
|
|
517
|
+
});
|
|
518
|
+
result.assistantText = assistantText;
|
|
519
|
+
return result;
|
|
333
520
|
}
|
|
334
521
|
var _client = null;
|
|
335
522
|
var _clientUrl;
|
|
@@ -350,5 +537,6 @@ export {
|
|
|
350
537
|
getServerUrl,
|
|
351
538
|
AstroClient,
|
|
352
539
|
streamDispatchToStdout,
|
|
540
|
+
streamChatToStdout,
|
|
353
541
|
getClient
|
|
354
542
|
};
|
package/dist/client.js
CHANGED