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