@astrosheep/keiyaku 4.5.21 → 4.5.23

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.
@@ -338,12 +338,16 @@ function terminalResult(params, state) {
338
338
  }
339
339
  export function codexNotificationResult(notification, state, events) {
340
340
  const method = notification.method;
341
+ const params = codexObject(notification.params) ?? {};
342
+ const notificationThreadId = codexText(params.threadId);
343
+ if (state.threadId !== undefined && notificationThreadId !== undefined && notificationThreadId !== state.threadId) {
344
+ return undefined;
345
+ }
341
346
  if (!Object.hasOwn(CODEX_NOTIFICATION_DISPOSITIONS, method)) {
342
347
  events.emit(unknownEvent(method));
343
348
  return undefined;
344
349
  }
345
350
  const disposition = CODEX_NOTIFICATION_DISPOSITIONS[method];
346
- const params = codexObject(notification.params) ?? {};
347
351
  switch (disposition) {
348
352
  case "drop":
349
353
  return undefined;
@@ -26,8 +26,9 @@ type RowLayout = Readonly<{
26
26
  marker: (count: number) => string;
27
27
  }>;
28
28
  /**
29
- * Shared snapshot activity rendering. Full snapshots focus known tool evidence;
30
- * `latest` preserves compact callers' established newest-entry selection.
29
+ * Shared snapshot activity rendering. Full snapshots render the selected
30
+ * activity evidence; an idle snapshot is settled evidence. `latest` preserves
31
+ * compact callers' established newest-entry selection.
31
32
  */
32
33
  export declare function snapshotActivityLines(snapshot: RenderedSnapshot, context: TextRenderContext, selection?: Readonly<{
33
34
  latest?: boolean;
@@ -35,7 +36,7 @@ export declare function snapshotActivityLines(snapshot: RenderedSnapshot, contex
35
36
  /** One command's append-only activity view, with a baseline and a final tail flush. */
36
37
  export type ActivityStream = ((snapshot: RenderedSnapshot) => readonly string[]) & Readonly<{
37
38
  /** Seed the sequence cursor without spending the command's live evidence budget. */
38
- seed: (snapshot: RenderedSnapshot) => void;
39
+ seed: (snapshot: RenderedSnapshot) => readonly string[];
39
40
  /** Emit the deferred tail exactly once before the command's conclusion. */
40
41
  flush: () => readonly string[];
41
42
  }>;
@@ -236,48 +236,61 @@ function orderedSnapshotEntries(snapshot) {
236
236
  return entries;
237
237
  }
238
238
  /**
239
- * Focus one complete snapshot without making its provider-side gaps mean more
240
- * than they do. Thought rows disappear; known tool rows use the same opening
241
- * and recent budgets as live activity, while every other row keeps its place.
239
+ * The current open turn starts from either its initial commission or a Tell
240
+ * delivered when the Body launched it. A live Tell belongs to an already
241
+ * pursuing turn and is not its boundary.
242
242
  */
243
- function focusedSnapshotEntries(entries) {
244
- const tools = entries.filter((entry) => entry.kind === "row" && entry.row.kind === "tool");
245
- const focused = [];
246
- let toolIndex = 0;
247
- let omittedTools = 0;
248
- const flushOmittedTools = () => {
249
- if (omittedTools > 0)
250
- focused.push({ kind: "gap", count: omittedTools });
251
- omittedTools = 0;
252
- };
253
- for (const entry of entries) {
254
- if (entry.kind === "row" && entry.row.kind === "thought")
255
- continue;
256
- if (entry.kind !== "row" || entry.row.kind !== "tool") {
257
- flushOmittedTools();
258
- focused.push(entry);
259
- continue;
243
+ function currentTurnBoundary(snapshot) {
244
+ if (snapshot.kind !== "open")
245
+ return undefined;
246
+ const rows = snapshot.entries.flatMap((entry) => (entry.kind === "row" ? [entry.row] : []));
247
+ const wake = rows.findLast((row) => row.kind === "tell" &&
248
+ row.state === "told" &&
249
+ row.deliveries.some((delivery) => delivery.route === "launch" && delivery.turnSequence === snapshot.turn.turnSequence));
250
+ if (wake !== undefined)
251
+ return { row: wake, turnSequence: snapshot.turn.turnSequence };
252
+ const call = rows.find((row) => row.kind === "call" && row.turnSequence === snapshot.turn.turnSequence);
253
+ return call === undefined ? undefined : { row: call, turnSequence: snapshot.turn.turnSequence };
254
+ }
255
+ /** Move the visible current-turn boundary ahead of activity without duplicating it. */
256
+ function boundaryFirstSnapshotEntries(snapshot) {
257
+ const entries = orderedSnapshotEntries(snapshot);
258
+ const boundary = currentTurnBoundary(snapshot);
259
+ if (boundary === undefined)
260
+ return entries;
261
+ return [
262
+ { kind: "row", row: boundary.row },
263
+ ...entries.filter((entry) => entry.kind !== "row" || entry.row !== boundary.row),
264
+ ];
265
+ }
266
+ /** Open status hides internal thought narration without selecting a second activity window. */
267
+ function visibleOpenSnapshotEntries(snapshot) {
268
+ return boundaryFirstSnapshotEntries(snapshot).filter((entry) => entry.kind !== "row" || entry.row.kind !== "thought");
269
+ }
270
+ /** Adjacent omitted spans are one continuous unknown portion of the retained timeline. */
271
+ function coalesceAdjacentGaps(entries) {
272
+ return entries.reduce((coalesced, entry) => {
273
+ const previous = coalesced.at(-1);
274
+ if (entry.kind === "gap" && previous?.kind === "gap") {
275
+ coalesced[coalesced.length - 1] = { kind: "gap", count: previous.count + entry.count };
260
276
  }
261
- const keep = toolIndex < OPENING_TOOL_BUDGET || toolIndex >= tools.length - RECENT_TOOL_BUDGET;
262
- toolIndex += 1;
263
- if (keep)
264
- flushOmittedTools();
265
- else
266
- omittedTools += 1;
267
- if (keep)
268
- focused.push(entry);
269
- }
270
- flushOmittedTools();
271
- return focused;
277
+ else {
278
+ coalesced.push(entry);
279
+ }
280
+ return coalesced;
281
+ }, []);
272
282
  }
273
283
  /**
274
- * Shared snapshot activity rendering. Full snapshots focus known tool evidence;
275
- * `latest` preserves compact callers' established newest-entry selection.
284
+ * Shared snapshot activity rendering. Full snapshots render the selected
285
+ * activity evidence; an idle snapshot is settled evidence. `latest` preserves
286
+ * compact callers' established newest-entry selection.
276
287
  */
277
288
  export function snapshotActivityLines(snapshot, context, selection = {}) {
278
289
  const entries = orderedSnapshotEntries(snapshot);
279
- if (selection.latest !== true)
280
- return groupedEntries(focusedSnapshotEntries(entries), context);
290
+ if (selection.latest !== true) {
291
+ const full = snapshot.kind === "open" ? visibleOpenSnapshotEntries(snapshot) : entries;
292
+ return groupedEntries(coalesceAdjacentGaps(full), context);
293
+ }
281
294
  const latest = entries.filter((entry) => entry.kind === "row").at(-1);
282
295
  return latest === undefined ? [] : groupedEntries([latest], context);
283
296
  }
@@ -344,15 +357,25 @@ function flushSafeActivityPrefix(state, lines, context, layout) {
344
357
  lines.push(layout.marker(first.count));
345
358
  }
346
359
  }
360
+ function renderCurrentTurnBoundary(state, snapshot, lines, context, layout) {
361
+ const boundary = currentTurnBoundary(snapshot);
362
+ if (boundary !== undefined && !state.renderedBoundaries.has(boundary.turnSequence)) {
363
+ renderStreamRow(state, boundary.row, lines, context, layout);
364
+ state.renderedBoundaries.add(boundary.turnSequence);
365
+ }
366
+ return boundary;
367
+ }
347
368
  function observeActivitySnapshot(state, snapshot, context, layout) {
369
+ const lines = [];
370
+ const boundary = renderCurrentTurnBoundary(state, snapshot, lines, context, layout);
348
371
  const rows = settledRows(snapshot)
372
+ .filter((row) => row !== boundary?.row)
349
373
  .filter((row) => state.newestSequence === undefined || row.sequence > state.newestSequence)
350
374
  // Thoughts remain retained activity, but are ineligible for default live progress.
351
375
  .filter((row) => row.kind !== "thought");
352
376
  if (rows.length === 0)
353
- return [];
377
+ return lines;
354
378
  state.newestSequence = rows.reduce((newest, row) => Math.max(newest, row.sequence), state.newestSequence ?? rows[0].sequence);
355
- const lines = [];
356
379
  for (const row of rows) {
357
380
  if (row.kind === "tool" && state.openingTools < OPENING_TOOL_BUDGET) {
358
381
  state.openingTools += 1;
@@ -395,13 +418,17 @@ export function activityStream(context, layout = plainLayout()) {
395
418
  const state = {
396
419
  newestSequence: undefined,
397
420
  previousClock: undefined,
421
+ renderedBoundaries: new Set(),
398
422
  openingTools: 0,
399
423
  deferred: [],
400
424
  };
401
425
  const seed = (snapshot) => {
426
+ const lines = [];
427
+ renderCurrentTurnBoundary(state, snapshot, lines, context, layout);
402
428
  const rows = settledRows(snapshot);
403
429
  if (rows.length > 0)
404
430
  state.newestSequence = rows.reduce((newest, row) => Math.max(newest, row.sequence), rows[0].sequence);
431
+ return lines;
405
432
  };
406
433
  const observe = (snapshot) => observeActivitySnapshot(state, snapshot, context, layout);
407
434
  const flush = () => flushActivityTail(state, context, layout);
@@ -481,7 +508,7 @@ function observeWaitRound(state, round, context, now) {
481
508
  : plainLayout());
482
509
  state.streams.set(status.id, stream);
483
510
  // A wait starts at the current settled frontier: its backlog is neither evidence nor budget.
484
- stream.seed(status.timeline);
511
+ lines.push(...stream.seed(status.timeline));
485
512
  }
486
513
  else {
487
514
  lines.push(...known(status.timeline));
@@ -2,7 +2,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
2
2
  import { join } from "node:path";
3
3
  import { acquireSqliteTransactionLock, SqliteTransactionLockError } from "../coordination/sqlite-transaction-lock.js";
4
4
  const PRIVATE_STATE_SEAT = "private-state.sqlite";
5
- const PRIVATE_STATE_SEAT_ACQUIRE_TIMEOUT_MS = 5_000;
5
+ const PRIVATE_STATE_SEAT_ACQUIRE_TIMEOUT_MS = 15_000;
6
6
  const privateStateSeat = Symbol("private-state-seat");
7
7
  const confirmedPublications = new WeakSet();
8
8
  const heldPrivateStateSeats = new AsyncLocalStorage();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrosheep/keiyaku",
3
- "version": "4.5.21",
3
+ "version": "4.5.23",
4
4
  "workspaces": [
5
5
  "plugins/*"
6
6
  ],