@clawos-dev/clawd 0.2.583 → 0.2.584

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/cli.cjs CHANGED
@@ -53313,6 +53313,23 @@ function stringValue(value) {
53313
53313
  return typeof value === "string" && value.length > 0 ? value : void 0;
53314
53314
  }
53315
53315
 
53316
+ // src/tools/first-byte.ts
53317
+ var VISIBLE = /* @__PURE__ */ new Set(["thinking", "tool_call", "text"]);
53318
+ function createFirstByteClock(now = Date.now) {
53319
+ let at3 = null;
53320
+ return {
53321
+ reset() {
53322
+ at3 = null;
53323
+ },
53324
+ see(events) {
53325
+ if (at3 === null && events.some((e) => VISIBLE.has(e.kind))) at3 = now();
53326
+ },
53327
+ afterFirstByteMs() {
53328
+ return at3 === null ? void 0 : Math.max(0, Math.round(now() - at3));
53329
+ }
53330
+ };
53331
+ }
53332
+
53316
53333
  // src/tools/codex-app-server-params.ts
53317
53334
  function resolveApprovalPolicy(ctx) {
53318
53335
  if (ctx.personaMode === "owner" || ctx.personaMode === "guest") return "never";
@@ -53448,6 +53465,7 @@ function driveCodexThread(opts) {
53448
53465
  let threadId = ctx.toolSessionId;
53449
53466
  let turnId;
53450
53467
  let turnOpen = false;
53468
+ const firstByte = createFirstByteClock(opts.now);
53451
53469
  const approvalIds = /* @__PURE__ */ new Map();
53452
53470
  const subagents = new CodexSubagentTracker();
53453
53471
  const effort = ctx.effort;
@@ -53479,10 +53497,13 @@ function driveCodexThread(opts) {
53479
53497
  ...subagents.handleParentNotification(method, params),
53480
53498
  ...translateNotification(method, params)
53481
53499
  ] : [];
53482
- if (events.length) sink.pushEvents(events);
53500
+ if (events.length) {
53501
+ if (turnOpen) firstByte.see(events);
53502
+ sink.pushEvents(events);
53503
+ }
53483
53504
  if (route === "foreground" && method === "turn/completed") {
53484
53505
  turnOpen = false;
53485
- opts.onTurnCompleted?.(turnOutcomeOf(params));
53506
+ opts.onTurnCompleted?.(turnOutcomeOf(params), firstByte.afterFirstByteMs());
53486
53507
  }
53487
53508
  },
53488
53509
  onServerRequest: (id, method, params) => {
@@ -53531,6 +53552,7 @@ function driveCodexThread(opts) {
53531
53552
  const opened = !turnOpen;
53532
53553
  if (opened) {
53533
53554
  turnOpen = true;
53555
+ firstByte.reset();
53534
53556
  opts.onTurnStarting?.();
53535
53557
  }
53536
53558
  void client.request("turn/start", {
@@ -53547,7 +53569,7 @@ function driveCodexThread(opts) {
53547
53569
  ]);
53548
53570
  if (!opened) return;
53549
53571
  turnOpen = false;
53550
- opts.onTurnCompleted?.("failure");
53572
+ opts.onTurnCompleted?.("failure", firstByte.afterFirstByteMs());
53551
53573
  });
53552
53574
  }
53553
53575
  });
@@ -64007,7 +64029,7 @@ function openHttpLineStream(opts) {
64007
64029
  if (closed || !sessionId) return;
64008
64030
  const url = gatewayUrl + GATEWAY_ROUTES.sessionMirror(personaId2, sessionId);
64009
64031
  try {
64010
- const res = await fetchImpl(url, { method: "POST", headers, body: turn ? JSON.stringify({ turn: { outcome: turn.outcome } }) : "" });
64032
+ const res = await fetchImpl(url, { method: "POST", headers, body: turn ? JSON.stringify({ turn: { outcome: turn.outcome, ...turn.afterFirstByteMs !== void 0 ? { afterFirstByteMs: turn.afterFirstByteMs } : {} } }) : "" });
64011
64033
  if (!res.ok) logger?.warn("cloud session mirror failed", { status: res.status });
64012
64034
  } catch (e) {
64013
64035
  if (!closed) logger?.warn("cloud session mirror error", { message: e.message });
@@ -64226,7 +64248,9 @@ function createCloudCodexSession(ctx, sink, deps) {
64226
64248
  kill: () => stream.close(),
64227
64249
  // 云 persona 运行看板(design 2026-09-23-cloud-persona-metrics §3.7):提问那一行带「一轮开始」头,轮末镜像顺带报这一轮的结果
64228
64250
  onTurnStarting: () => channel?.markNextLineTurnStart(),
64229
- onTurnCompleted: (outcome) => void channel?.mirror({ outcome })
64251
+ // 轮末镜像带上这一轮的结果与首字节(design 2026-09-23-cloud-persona-metrics §3.7)
64252
+ onTurnCompleted: (outcome, afterFirstByteMs) => void channel?.mirror({ outcome, ...afterFirstByteMs !== void 0 ? { afterFirstByteMs } : {} }),
64253
+ now: deps.now
64230
64254
  });
64231
64255
  if (!personaId2) {
64232
64256
  queueMicrotask(() => {
@@ -64563,6 +64587,7 @@ function drivePiSession(opts) {
64563
64587
  let turnErrored = false;
64564
64588
  let turnInterrupted = false;
64565
64589
  let turnOpen = false;
64590
+ const firstByte = createFirstByteClock(opts.now);
64566
64591
  let handshakeFailed = false;
64567
64592
  let exited = false;
64568
64593
  const finish = (code) => {
@@ -64574,7 +64599,7 @@ function drivePiSession(opts) {
64574
64599
  sink.pushEvents([{ kind: "error", message }, { kind: "turn_end", reason: "completed" }]);
64575
64600
  if (!opened) return;
64576
64601
  turnOpen = false;
64577
- opts.onTurnCompleted?.("failure");
64602
+ opts.onTurnCompleted?.("failure", firstByte.afterFirstByteMs());
64578
64603
  };
64579
64604
  const handleUiRequest = (ev) => {
64580
64605
  const method = str2(ev.method);
@@ -64601,14 +64626,17 @@ function drivePiSession(opts) {
64601
64626
  return;
64602
64627
  }
64603
64628
  const events = translatePiEvent(ev, st2);
64604
- if (events.length) sink.pushEvents(events);
64629
+ if (events.length) {
64630
+ if (turnOpen) firstByte.see(events);
64631
+ sink.pushEvents(events);
64632
+ }
64605
64633
  for (const e of events) {
64606
64634
  if (e.kind === "error") turnErrored = true;
64607
64635
  if (e.kind === "turn_end" && e.reason === "interrupted") turnInterrupted = true;
64608
64636
  }
64609
64637
  if (ev.type === "agent_settled") {
64610
64638
  turnOpen = false;
64611
- opts.onTurnCompleted?.(turnInterrupted ? "interrupted" : turnErrored ? "failure" : "success");
64639
+ opts.onTurnCompleted?.(turnInterrupted ? "interrupted" : turnErrored ? "failure" : "success", firstByte.afterFirstByteMs());
64612
64640
  }
64613
64641
  },
64614
64642
  onClose: () => finish(opts.exitCodeOnClose?.() ?? null)
@@ -64644,6 +64672,7 @@ function drivePiSession(opts) {
64644
64672
  opened = !turnOpen;
64645
64673
  if (opened) {
64646
64674
  turnOpen = true;
64675
+ firstByte.reset();
64647
64676
  opts.onTurnStarting?.();
64648
64677
  }
64649
64678
  const r2 = await client.request({
@@ -64949,7 +64978,9 @@ function createCloudPiSession(ctx, sink, deps) {
64949
64978
  kill: () => stream.close(),
64950
64979
  // 云 persona 运行看板(design 2026-09-23-cloud-persona-metrics §3.7):提问那一行带「一轮开始」头,轮末镜像顺带报这一轮的结果
64951
64980
  onTurnStarting: () => channel?.markNextLineTurnStart(),
64952
- onTurnCompleted: (outcome) => void channel?.mirror({ outcome })
64981
+ // 轮末镜像带上这一轮的结果与首字节(design 2026-09-23-cloud-persona-metrics §3.7)
64982
+ onTurnCompleted: (outcome, afterFirstByteMs) => void channel?.mirror({ outcome, ...afterFirstByteMs !== void 0 ? { afterFirstByteMs } : {} }),
64983
+ now: deps.now
64953
64984
  });
64954
64985
  if (!personaId2) {
64955
64986
  queueMicrotask(() => {
@@ -72253,7 +72284,7 @@ function computeMethodAccess(args) {
72253
72284
  }
72254
72285
 
72255
72286
  // src/version.ts
72256
- var version = "0.2.583".length > 0 ? "0.2.583" : "dev";
72287
+ var version = "0.2.584".length > 0 ? "0.2.584" : "dev";
72257
72288
 
72258
72289
  // src/cli-probe/probe.ts
72259
72290
  var fs80 = __toESM(require("fs"), 1);