@vincenthanxiaodu/pi-web 1.202609.1 → 1.202609.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.
@@ -149,7 +149,7 @@
149
149
  that is not there. Scale belongs to the app's own control. */
150
150
  html { touch-action: pan-x pan-y; }
151
151
  </style>
152
- <script type="module" crossorigin src="./assets/index-POhML0QZ.js"></script>
152
+ <script type="module" crossorigin src="./assets/index-DkqNNLj_.js"></script>
153
153
  </head>
154
154
  <body>
155
155
  <pi-web-app></pi-web-app>
@@ -3811,6 +3811,8 @@ export class PiSessionService {
3811
3811
  }
3812
3812
  this.attachQueuedPromptClientIds(session.sessionId, visibleQueued);
3813
3813
  const backgroundRunCount = this.backgroundRunCounts.get(session.sessionId) ?? 0;
3814
+ const working = session.isStreaming || session.isCompacting || session.isBashRunning;
3815
+ const turnStartedAt = working ? turnStartedAtFromBranch(session.sessionManager.getBranch()) : undefined;
3814
3816
  return {
3815
3817
  sessionId: session.sessionId,
3816
3818
  persisted: sessionFileExists(session.sessionFile),
@@ -3819,6 +3821,10 @@ export class PiSessionService {
3819
3821
  isStreaming: session.isStreaming,
3820
3822
  isCompacting: session.isCompacting,
3821
3823
  isBashRunning: session.isBashRunning,
3824
+ // The turn's own start, read off the transcript: a browser that joins a
3825
+ // working session mid-turn anchors its elapsed readout here instead of
3826
+ // re-clocking from the moment it happened to look.
3827
+ ...(turnStartedAt === undefined ? {} : { turnStartedAt }),
3822
3828
  pendingMessageCount: visibleQueued.length,
3823
3829
  queuedMessages: visibleQueued,
3824
3830
  messageCount: readableMessageCount(session.sessionManager.getBranch()),
@@ -4367,6 +4373,40 @@ function clearParentSessionHeader(sessionManager) {
4367
4373
  function clearSessionQueue(session) {
4368
4374
  session.clearQueue();
4369
4375
  }
4376
+ /**
4377
+ * When the working turn began, read from the transcript itself.
4378
+ *
4379
+ * The turn's start is its last input boundary: the newest user message (a
4380
+ * submitted prompt, a steer, an answered question) or the newest custom entry
4381
+ * that triggered a turn. Scanning from the tail skips assistant and tool
4382
+ * entries so mid-turn activity cannot move the anchor; a branch with no input
4383
+ * at all yields undefined, and the client then clocks from when it first saw
4384
+ * the session working, which is at least an honest lower bound.
4385
+ */
4386
+ export function turnStartedAtFromBranch(branch) {
4387
+ for (let index = branch.length - 1; index >= 0; index -= 1) {
4388
+ const entry = branch[index];
4389
+ if (!isRecord(entry))
4390
+ continue;
4391
+ if (entry["type"] === "custom_message") {
4392
+ const details = entry["details"];
4393
+ if (isRecord(details) && typeof details["timestamp"] === "number")
4394
+ return new Date(details["timestamp"]).toISOString();
4395
+ continue;
4396
+ }
4397
+ if (entry["type"] !== "message")
4398
+ continue;
4399
+ const message = entry["message"];
4400
+ if (!isRecord(message) || message["role"] !== "user")
4401
+ continue;
4402
+ if (typeof entry["timestamp"] === "string")
4403
+ return entry["timestamp"];
4404
+ if (typeof message["timestamp"] === "string")
4405
+ return message["timestamp"];
4406
+ return undefined;
4407
+ }
4408
+ return undefined;
4409
+ }
4370
4410
  function queuedMessagesFromSession(session, extraQueuedMessages = []) {
4371
4411
  const consumed = consumedUserMessageTexts(session);
4372
4412
  return [