neatlogs 1.1.9 → 1.1.10

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/index.cjs CHANGED
@@ -6009,7 +6009,7 @@ function _resetMastraCache() {
6009
6009
  }
6010
6010
 
6011
6011
  // src/version.ts
6012
- var __version__ = "1.1.9";
6012
+ var __version__ = "1.1.10";
6013
6013
 
6014
6014
  // src/init.ts
6015
6015
  var logger13 = getLogger();
@@ -11278,6 +11278,9 @@ var TraceShipper = class {
11278
11278
  workflowName;
11279
11279
  queue = [];
11280
11280
  prefix = "[neatlogs/opencode]";
11281
+ /** In-flight flush round-trips — awaited by `settle()` on dispose so a
11282
+ * short-lived host (`opencode run`) can force pending exports to complete. */
11283
+ inflight = /* @__PURE__ */ new Set();
11281
11284
  constructor(opts) {
11282
11285
  this.apiKey = opts.apiKey;
11283
11286
  this.endpoint = opts.endpoint.endsWith("/") ? opts.endpoint.slice(0, -1) : opts.endpoint;
@@ -11295,8 +11298,26 @@ var TraceShipper = class {
11295
11298
  * Ship all queued spans in a single awaited POST. Resolves only once the HTTP
11296
11299
  * response is received (or all retries are exhausted) — so a short-lived host
11297
11300
  * can safely exit immediately after awaiting this.
11301
+ *
11302
+ * The returned promise is also tracked in `inflight` so `settle()` can await
11303
+ * it even when the caller (an un-awaited opencode `event` hook) drops it.
11304
+ */
11305
+ flush() {
11306
+ const p = this._flush().finally(() => this.inflight.delete(p));
11307
+ this.inflight.add(p);
11308
+ return p;
11309
+ }
11310
+ /**
11311
+ * Await every flush started so far (including ones whose promise the caller
11312
+ * discarded). Called from the plugin's `dispose` hook, which opencode DOES
11313
+ * await on scope teardown — unlike the fire-and-forget `event` hook.
11298
11314
  */
11299
- async flush() {
11315
+ async settle() {
11316
+ while (this.inflight.size > 0) {
11317
+ await Promise.allSettled(Array.from(this.inflight));
11318
+ }
11319
+ }
11320
+ async _flush() {
11300
11321
  if (this.queue.length === 0) return;
11301
11322
  if (!this.apiKey) {
11302
11323
  this.queue = [];
@@ -11472,6 +11493,22 @@ var NeatlogsOpencodePlugin = async (_ctx) => {
11472
11493
  void sessionID;
11473
11494
  }
11474
11495
  return {
11496
+ /**
11497
+ * Awaited by opencode on scope teardown (registered via an internal
11498
+ * `addFinalizer`), unlike the fire-and-forget `event` hook. On a short-lived
11499
+ * `opencode run`, `session.idle`'s `await shipper.flush()` is a dangling
11500
+ * promise the process kills before the POST resolves — so we close any turn
11501
+ * still open and `settle()` all in-flight flushes here, before exit.
11502
+ */
11503
+ dispose: async () => {
11504
+ try {
11505
+ for (const [sessionID, st] of sessions) {
11506
+ if (st.rootSpan) await closeAndFlush(st, sessionID);
11507
+ }
11508
+ await shipper.settle();
11509
+ } catch {
11510
+ }
11511
+ },
11475
11512
  /** Fired when the user submits a prompt — open the turn's AGENT root. */
11476
11513
  "chat.message": async (_input, output) => {
11477
11514
  try {
@@ -11668,6 +11705,7 @@ function emitLlmSpan2(shipper, st, info, sessionID) {
11668
11705
  push(attrs, attrInt("neatlogs.llm.token_count.cache_write", tokens.cache?.write));
11669
11706
  }
11670
11707
  push(attrs, attrDouble("neatlogs.llm.cost_usd", info?.cost));
11708
+ push(attrs, attrStr("neatlogs.llm.finish_reason", info?.finish ? String(info.finish) : void 0));
11671
11709
  const createdMs = info?.time?.created;
11672
11710
  const startNano = typeof createdMs === "number" ? msToNanoString(Math.floor(createdMs)) : nowNanoString();
11673
11711
  shipper.enqueue({