@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.
@@ -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
- async function streamDispatchToStdout(response) {
291
- if (!response.body) {
292
- console.log("Task dispatched (no stream)");
293
- return;
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 line of lines) {
305
- if (line.startsWith("data: ")) {
306
- try {
307
- const event = JSON.parse(line.slice(6));
308
- switch (event.type) {
309
- case "text":
310
- process.stdout.write(event.content ?? "");
311
- break;
312
- case "tool_use":
313
- console.log(`
314
- [tool] ${event.name}`);
315
- break;
316
- case "result":
317
- console.log(`
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
- if (event.summary) console.log(event.summary);
320
- break;
321
- case "error":
322
- console.error(`
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
- break;
325
- case "done":
326
- break;
327
- }
328
- } catch {
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
@@ -2,10 +2,12 @@
2
2
  import {
3
3
  AstroClient,
4
4
  getClient,
5
+ streamChatToStdout,
5
6
  streamDispatchToStdout
6
- } from "./chunk-7H7WD7QX.js";
7
+ } from "./chunk-SYY2HHOY.js";
7
8
  export {
8
9
  AstroClient,
9
10
  getClient,
11
+ streamChatToStdout,
10
12
  streamDispatchToStdout
11
13
  };