@bastani/atomic 0.9.44-alpha.2 → 0.9.44-alpha.3

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/web-access",
3
- "version": "0.9.44-alpha.2",
3
+ "version": "0.9.44-alpha.3",
4
4
  "private": true,
5
5
  "description": "Atomic extension for web search, URL fetching, GitHub repo cloning, PDF/video extraction. Fork of: https://github.com/nicobailon/pi-web-access",
6
6
  "contributors": [
@@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.9.44-alpha.3] - 2026-10-25
10
+
11
+ ### Fixed
12
+
13
+ - A workflow whose stages send many Intercom messages to stage patterns (for example `workflow:<rootRunId>/child-*/**`) no longer saturates the workflow host. The host matched every queued pattern message against every stage on each change; it now indexes the patterns and each stage's paths once. In a 150-child fan-out test, delivered sends went from 566 of 900 to 900 of 900 and host event-loop lag p99 from about 1 s to under 200 ms ([#3931](https://github.com/bastani-inc/atomic/issues/3931))
14
+ - Workflow journal events no longer store a run's whole list of pending stage messages each time. Pattern sends stay queued until the root run ends, so every queued message rewrote the growing list and the journal grew quadratically with the number of sends. Each event now records only what changed; older journals still read as before ([#3929](https://github.com/bastani-inc/atomic/issues/3929))
15
+
9
16
  ## [0.9.44-alpha.2] - 2026-10-24
10
17
 
11
18
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/workflows",
3
- "version": "0.9.44-alpha.2",
3
+ "version": "0.9.44-alpha.3",
4
4
  "private": true,
5
5
  "description": "Atomic extension for multi-stage workflow authoring and execution.",
6
6
  "contributors": [
@@ -2120,7 +2120,20 @@ function createWorkflowBoundarySegmentsResolver(runs) {
2120
2120
  };
2121
2121
  }
2122
2122
  function workflowBoundaryHops(runs, runId) {
2123
+ return boundaryHopsFrom(new Map(runs.map((run) => [run.id, run])), runId);
2124
+ }
2125
+ function createWorkflowBoundaryHopsResolver(runs) {
2123
2126
  const runById = new Map(runs.map((run) => [run.id, run]));
2127
+ const cache = new Map;
2128
+ return (runId) => {
2129
+ if (cache.has(runId))
2130
+ return cache.get(runId);
2131
+ const hops = boundaryHopsFrom(runById, runId);
2132
+ cache.set(runId, hops);
2133
+ return hops;
2134
+ };
2135
+ }
2136
+ function boundaryHopsFrom(runById, runId) {
2124
2137
  const hops = [];
2125
2138
  let current = runById.get(runId);
2126
2139
  while (current !== undefined && current.parentRunId !== undefined) {
@@ -2146,6 +2159,35 @@ function workflowStagePathVariants(hops, stageSegments) {
2146
2159
  function stageMatchesPathPattern(patternSegments, hops, stageSegments) {
2147
2160
  return workflowStagePathVariants(hops, stageSegments).some((candidate) => matchStagePathSegments(patternSegments, candidate));
2148
2161
  }
2162
+ function createStagePathPatternIndex(patterns) {
2163
+ const byFirstSegment = new Map;
2164
+ const globFirst = [];
2165
+ patterns.forEach((pattern, index) => {
2166
+ const first = pattern[0];
2167
+ if (first === undefined || first.includes("*")) {
2168
+ globFirst.push(index);
2169
+ return;
2170
+ }
2171
+ const bucket = byFirstSegment.get(first);
2172
+ if (bucket === undefined)
2173
+ byFirstSegment.set(first, [index]);
2174
+ else
2175
+ bucket.push(index);
2176
+ });
2177
+ return {
2178
+ matching(hops, stageSegments) {
2179
+ if (patterns.length === 0)
2180
+ return [];
2181
+ const variants = workflowStagePathVariants(hops, stageSegments);
2182
+ const candidates = new Set(globFirst);
2183
+ for (const variant of variants) {
2184
+ for (const index of byFirstSegment.get(variant[0]) ?? [])
2185
+ candidates.add(index);
2186
+ }
2187
+ return [...candidates].sort((left, right) => left - right).filter((index) => variants.some((variant) => matchStagePathSegments(patterns[index], variant)));
2188
+ }
2189
+ };
2190
+ }
2149
2191
  function pendingStageTarget(runId, stage) {
2150
2192
  return "workflowGraphTarget" in stage ? stage.workflowGraphTarget : { runId, stageId: stage.id };
2151
2193
  }
@@ -6808,12 +6850,16 @@ function removeProcessExitCleanup(cleanup) {
6808
6850
  if (processExitCleanups.delete(cleanup) && processExitCleanups.size === 0)
6809
6851
  process.off("exit", runProcessExitCleanups);
6810
6852
  }
6853
+ function writtenHandle(event) {
6854
+ if (event.type === RUN_EVENT_TYPES.promptAsked || event.type === RUN_EVENT_TYPES.promptReleased)
6855
+ return event.payload.handle;
6856
+ if (event.type === RUN_EVENT_TYPES.checkpointRecorded || event.type === RUN_EVENT_TYPES.messageSettled || event.type === RUN_EVENT_TYPES.messageDelivered)
6857
+ return;
6858
+ return event.payload;
6859
+ }
6811
6860
  function snapshotNeedsHistory(tail) {
6812
- const event = tail.snapshot.event;
6813
- if (event.type !== RUN_EVENT_TYPES.messageQueued)
6814
- return false;
6815
- const payload = event.payload;
6816
- return hasPendingStageDeliveryDelta(payload.pendingStageMessages);
6861
+ const handle = writtenHandle(tail.snapshot.event);
6862
+ return handle !== undefined && (handle.pendingStageMessageChange !== undefined || hasPendingStageDeliveryDelta(handle.pendingStageMessages));
6817
6863
  }
6818
6864
  function* invoke(action) {
6819
6865
  try {
@@ -6927,14 +6973,11 @@ class JournalDurableBackend {
6927
6973
  const payload = event.payload;
6928
6974
  this.projection.archivePendingStageDeliveryReceipt(entry.runId, payload.messageId, payload.delivery, payload.accounting);
6929
6975
  } else if (event.type === RUN_EVENT_TYPES.promptAsked || event.type === RUN_EVENT_TYPES.promptReleased) {
6930
- this.projection.applyWorkflowSnapshot(event.payload.handle);
6976
+ this.projection.applyWorkflowSnapshot(decodeHandle(event.payload.handle, this.projection.getWorkflow(entry.runId)?.pendingStageMessages));
6931
6977
  this.prompts.set(entry.runId, new PromptReservationState(event.payload.handle.pendingPrompts, event.payload.prompts));
6932
6978
  } else {
6933
6979
  const previous = this.projection.getWorkflow(entry.runId);
6934
- const handle = event.type === RUN_EVENT_TYPES.messageQueued && hasPendingStageDeliveryDelta(event.payload.pendingStageMessages) ? {
6935
- ...event.payload,
6936
- pendingStageMessages: decodePendingStageDeliveries(previous?.pendingStageMessages ?? [], event.payload.pendingStageMessages ?? [])
6937
- } : event.payload;
6980
+ const handle = decodeHandle(event.payload, previous?.pendingStageMessages);
6938
6981
  this.projection.applyWorkflowSnapshot(handle);
6939
6982
  if (event.type === RUN_EVENT_TYPES.runStarted || previous?.pendingPrompts !== handle.pendingPrompts)
6940
6983
  this.prompts.delete(entry.runId);
@@ -7054,6 +7097,20 @@ class JournalDurableBackend {
7054
7097
  }
7055
7098
  *append(runId, event, options) {
7056
7099
  const lease = yield* this.ownership(runId);
7100
+ const base = this.sequences.get(runId);
7101
+ const pinned = options?.expectSeq;
7102
+ const encoded = base !== undefined && (pinned === undefined || pinned === base) && event.type !== RUN_EVENT_TYPES.runStarted ? encodeHandleEvent(event, this.projection.getWorkflow(runId)?.pendingStageMessages) : undefined;
7103
+ if (encoded !== undefined) {
7104
+ try {
7105
+ return yield* this.write(runId, lease, encoded, { ...options, expectSeq: base });
7106
+ } catch (error) {
7107
+ if (!(error instanceof JournalCasConflictError) || pinned !== undefined)
7108
+ throw error;
7109
+ }
7110
+ }
7111
+ yield* this.write(runId, lease, event, options);
7112
+ }
7113
+ *write(runId, lease, event, options) {
7057
7114
  try {
7058
7115
  const outcome = yield* invoke(() => this.journal.append(lease, event, options));
7059
7116
  const nextSeq = (this.sequences.get(runId) ?? 0) + 1;
@@ -7235,17 +7292,6 @@ class JournalDurableBackend {
7235
7292
  pendingStageMessages: replacePendingStageMessagesForRun(handle.pendingStageMessages ?? [], logicalRunId, messages),
7236
7293
  updatedAt: Math.max(Date.now(), handle.updatedAt + 1)
7237
7294
  };
7238
- const encoded = encodePendingStageDeliveries(handle.pendingStageMessages ?? [], next.pendingStageMessages ?? []);
7239
- const base = this.sequences.get(runId);
7240
- if (encoded !== undefined && base !== undefined) {
7241
- try {
7242
- yield* this.append(runId, { type: RUN_EVENT_TYPES.messageQueued, payload: { ...next, pendingStageMessages: encoded } }, { expectSeq: base });
7243
- return true;
7244
- } catch (error) {
7245
- if (!(error instanceof JournalCasConflictError))
7246
- throw error;
7247
- }
7248
- }
7249
7295
  yield* this.snapshot(next, RUN_EVENT_TYPES.messageQueued);
7250
7296
  return true;
7251
7297
  }
@@ -7585,31 +7631,143 @@ function uniqueByIdentity(messages) {
7585
7631
  function isDeltaEncoded(message) {
7586
7632
  return message.deliveryDelta !== undefined;
7587
7633
  }
7588
- function encodePendingStageDeliveries(previous, next) {
7589
- const bases = uniqueByIdentity(previous);
7590
- const nextIdentities = uniqueByIdentity(next);
7591
- let encodedAny = false;
7592
- const encoded = next.map((message) => {
7593
- const base = bases.get(identity(message))?.deliveries;
7594
- const deliveries = message.deliveries;
7595
- if (base === undefined || deliveries === undefined || !nextIdentities.has(identity(message)))
7596
- return message;
7597
- const drop = [];
7598
- let kept = 0;
7599
- base.forEach((delivery, index) => {
7600
- if (kept < deliveries.length && JSON.stringify(delivery) === JSON.stringify(deliveries[kept]))
7601
- kept++;
7602
- else
7603
- drop.push(index);
7604
- });
7605
- const add = deliveries.slice(kept);
7606
- if (drop.length + add.length >= deliveries.length)
7607
- return message;
7608
- encodedAny = true;
7609
- const { deliveries: _full, ...rest } = message;
7610
- return { ...rest, deliveryDelta: drop.length === 0 ? { add } : { drop, add } };
7634
+ function deliveryDelta(base, deliveries) {
7635
+ const drop = [];
7636
+ let kept = 0;
7637
+ base.forEach((delivery, index) => {
7638
+ if (kept < deliveries.length && JSON.stringify(delivery) === JSON.stringify(deliveries[kept]))
7639
+ kept++;
7640
+ else
7641
+ drop.push(index);
7642
+ });
7643
+ const add = deliveries.slice(kept);
7644
+ return drop.length === 0 ? { add } : { drop, add };
7645
+ }
7646
+ function pendingStageFields(message) {
7647
+ return Object.keys(message);
7648
+ }
7649
+ function copyField(target, source, key) {
7650
+ target[key] = source[key];
7651
+ }
7652
+ function isRemovedField(message, key) {
7653
+ return message[key] === undefined;
7654
+ }
7655
+ function json(message) {
7656
+ let text = entryJson.get(message);
7657
+ if (text === undefined) {
7658
+ text = JSON.stringify(message);
7659
+ entryJson.set(message, text);
7660
+ }
7661
+ return text;
7662
+ }
7663
+ function patchEntry(index, base, message) {
7664
+ const set = {};
7665
+ const unset = pendingStageFields(base).filter((key) => base[key] !== undefined && isRemovedField(message, key));
7666
+ for (const key of pendingStageFields(message)) {
7667
+ if (message[key] === undefined || key === "deliveries")
7668
+ continue;
7669
+ if (JSON.stringify(message[key]) !== JSON.stringify(base[key]))
7670
+ copyField(set, message, key);
7671
+ }
7672
+ let delta;
7673
+ if (message.deliveries !== undefined) {
7674
+ if (base.deliveries === undefined)
7675
+ set.deliveries = message.deliveries;
7676
+ else if (JSON.stringify(base.deliveries) !== JSON.stringify(message.deliveries))
7677
+ delta = deliveryDelta(base.deliveries, message.deliveries);
7678
+ }
7679
+ return {
7680
+ patch: index,
7681
+ ...Object.keys(set).length === 0 ? {} : { set },
7682
+ ...unset.length === 0 ? {} : { unset },
7683
+ ...delta === undefined ? {} : { deliveryDelta: delta }
7684
+ };
7685
+ }
7686
+ function encodePendingStageList(previous, next) {
7687
+ const positions = new Map;
7688
+ const repeated = new Set;
7689
+ previous.forEach((message, index) => {
7690
+ const key = identity(message);
7691
+ if (positions.has(key))
7692
+ repeated.add(key);
7693
+ positions.set(key, index);
7611
7694
  });
7612
- return encodedAny ? encoded : undefined;
7695
+ for (const key of repeated)
7696
+ positions.delete(key);
7697
+ const items = [];
7698
+ let reused = 0;
7699
+ for (const message of next) {
7700
+ const index = positions.get(identity(message));
7701
+ const base = index === undefined ? undefined : previous[index];
7702
+ if (base === undefined) {
7703
+ items.push(message);
7704
+ continue;
7705
+ }
7706
+ reused++;
7707
+ const patched = base === message || json(base) === json(message) ? undefined : patchEntry(index, base, message);
7708
+ if (patched === undefined || Object.keys(patched).length === 1) {
7709
+ const last = items.at(-1);
7710
+ if (Array.isArray(last) && last[0] + last[1] === index)
7711
+ last[1]++;
7712
+ else
7713
+ items.push([index, 1]);
7714
+ continue;
7715
+ }
7716
+ items.push(JSON.stringify(patched).length < json(message).length ? patched : message);
7717
+ }
7718
+ return reused > 0 ? items : undefined;
7719
+ }
7720
+ function decodePendingStageList(previous, items) {
7721
+ const base = (index) => {
7722
+ if (!Number.isInteger(index) || index < 0 || index >= previous.length)
7723
+ throw new Error(`atomic-workflows: journal pending-stage change names missing entry ${index}`);
7724
+ return previous[index];
7725
+ };
7726
+ const result = [];
7727
+ for (const item of items) {
7728
+ if (Array.isArray(item)) {
7729
+ const [start, count] = item;
7730
+ for (let index = start;index < start + count; index++)
7731
+ result.push(base(index));
7732
+ } else if (typeof item.patch === "number") {
7733
+ const { patch, set, unset, deliveryDelta: delta } = item;
7734
+ const entry = { ...base(patch), ...set };
7735
+ for (const key of unset ?? [])
7736
+ delete entry[key];
7737
+ if (delta !== undefined) {
7738
+ const dropped = new Set(delta.drop ?? []);
7739
+ const deliveries = base(patch).deliveries ?? [];
7740
+ entry.deliveries = [...deliveries.filter((_, index) => !dropped.has(index)), ...delta.add];
7741
+ }
7742
+ result.push(entry);
7743
+ } else
7744
+ result.push(item);
7745
+ }
7746
+ return result;
7747
+ }
7748
+ function encodeHandleEvent(event, previous) {
7749
+ const handle = writtenHandle(event);
7750
+ if (handle?.pendingStageMessages === undefined || previous === undefined)
7751
+ return;
7752
+ const change = encodePendingStageList(previous, handle.pendingStageMessages);
7753
+ if (change === undefined)
7754
+ return;
7755
+ const { pendingStageMessages: _full, ...rest } = handle;
7756
+ const encoded = { ...rest, pendingStageMessageChange: change };
7757
+ if (event.type === RUN_EVENT_TYPES.promptAsked || event.type === RUN_EVENT_TYPES.promptReleased)
7758
+ return { ...event, payload: { ...event.payload, handle: encoded } };
7759
+ return { ...event, payload: encoded };
7760
+ }
7761
+ function decodeHandle(handle, previous) {
7762
+ const { pendingStageMessageChange: change, ...rest } = handle;
7763
+ if (change !== undefined)
7764
+ return { ...rest, pendingStageMessages: decodePendingStageList(previous ?? [], change) };
7765
+ if (!hasPendingStageDeliveryDelta(handle.pendingStageMessages))
7766
+ return handle;
7767
+ return {
7768
+ ...handle,
7769
+ pendingStageMessages: decodePendingStageDeliveries(previous ?? [], handle.pendingStageMessages ?? [])
7770
+ };
7613
7771
  }
7614
7772
  function decodePendingStageDeliveries(previous, messages) {
7615
7773
  if (!messages.some(isDeltaEncoded))
@@ -7629,7 +7787,7 @@ function decodePendingStageDeliveries(previous, messages) {
7629
7787
  function hasPendingStageDeliveryDelta(messages) {
7630
7788
  return messages?.some(isDeltaEncoded) === true;
7631
7789
  }
7632
- var PROCESS_HOLDER_ID, processExitCleanups, JournalOwnershipError, JournalBackendClosedError, JournalOperationAbortedError, JournalExecutionRetiredError, JournalMessageScopeError;
7790
+ var PROCESS_HOLDER_ID, processExitCleanups, JournalOwnershipError, JournalBackendClosedError, JournalOperationAbortedError, JournalExecutionRetiredError, JournalMessageScopeError, entryJson;
7633
7791
  var init_journal_backend = __esm(() => {
7634
7792
  init_workflow_instance_ownership_error();
7635
7793
  init_backend();
@@ -7687,6 +7845,7 @@ var init_journal_backend = __esm(() => {
7687
7845
  this.name = "JournalMessageScopeError";
7688
7846
  }
7689
7847
  };
7848
+ entryJson = new WeakMap;
7690
7849
  });
7691
7850
 
7692
7851
  // dist/builtin/workflows/src/durable/journal/legacy-journal-tables.ts
@@ -60812,24 +60971,63 @@ function stickyStageDeliveryStatuses(runs, rootRunId, availableBackend) {
60812
60971
  const root = runs.find((run) => run.id === rootRunId);
60813
60972
  const entries = (root?.pendingStageMessages ?? []).filter((entry) => entry.sticky === true);
60814
60973
  const result = [];
60974
+ const patternByTarget = new Map;
60975
+ const patterns = [];
60976
+ const entriesByPattern = [];
60977
+ const ownEntries = [];
60978
+ entries.forEach((entry, index) => {
60979
+ const target = entry.targetPath ?? entry.stageKey;
60980
+ let pattern = patternByTarget.get(target);
60981
+ if (pattern === undefined) {
60982
+ const parsed = parseWorkflowStageTarget(target);
60983
+ pattern = parsed?.rootRunId === rootRunId ? patterns.push(parsed.segments) - 1 : -1;
60984
+ if (pattern >= 0)
60985
+ entriesByPattern.push([]);
60986
+ patternByTarget.set(target, pattern);
60987
+ }
60988
+ if (pattern < 0)
60989
+ return;
60990
+ entriesByPattern[pattern].push(index);
60991
+ ownEntries.push(index);
60992
+ });
60993
+ if (ownEntries.length === 0)
60994
+ return result;
60995
+ const patternIndex = createStagePathPatternIndex(patterns);
60996
+ const deliveriesByEntry = new Map;
60997
+ const entryReceipts = (index, runId, stageId) => {
60998
+ let byStage = deliveriesByEntry.get(index);
60999
+ if (byStage === undefined) {
61000
+ byStage = new Map;
61001
+ for (const delivery of entries[index].deliveries ?? []) {
61002
+ const key = `${delivery.runId}\x00${delivery.stageId}`;
61003
+ const list = byStage.get(key);
61004
+ if (list === undefined)
61005
+ byStage.set(key, [delivery]);
61006
+ else
61007
+ list.push(delivery);
61008
+ }
61009
+ deliveriesByEntry.set(index, byStage);
61010
+ }
61011
+ return byStage.get(`${runId}\x00${stageId}`) ?? [];
61012
+ };
60815
61013
  availableBackend = availableRunDurableBackend(runs, rootRunId) ?? availableBackend;
60816
61014
  const backend = availableBackend === undefined ? undefined : durableBackendForRun(availableBackend, runs, rootRunId);
61015
+ const runById = new Map(runs.map((run) => [run.id, run]));
61016
+ const hopsFor = createWorkflowBoundaryHopsResolver(runs);
60817
61017
  for (const run of runs) {
60818
- if (run.id !== rootRunId && run.rootRunId !== rootRunId && durableRootRunIdForRun(runs, run.id) !== rootRunId)
61018
+ const durableRootRunId = reciprocalWorkflowRootRunId(runById, run.id);
61019
+ if (run.id !== rootRunId && run.rootRunId !== rootRunId && durableRootRunId !== rootRunId)
60819
61020
  continue;
60820
- const resolved = durableRootRunIdForRun(runs, run.id) === rootRunId;
60821
- const hops = workflowBoundaryHops(runs, run.id);
61021
+ const resolved = durableRootRunId === rootRunId;
61022
+ const hops = hopsFor(run.id);
60822
61023
  for (const stage of run.stages) {
60823
61024
  if (stage.nodeKind === "tool" || stage.replayKey?.startsWith("prompt:") === true || stage.replayKey?.startsWith("workflow:") === true || stage.workflowChildRun !== undefined || stage.workflowChild !== undefined)
60824
61025
  continue;
60825
- for (const entry of entries) {
61026
+ const matchedEntries = resolved && hops ? patternIndex.matching(hops, [stage.id, stage.name]).flatMap((pattern) => entriesByPattern[pattern]).sort((left, right) => left - right) : ownEntries;
61027
+ for (const index of matchedEntries) {
61028
+ const entry = entries[index];
60826
61029
  const target = entry.targetPath ?? entry.stageKey;
60827
- const parsed = parseWorkflowStageTarget(target);
60828
- if (!parsed || parsed.rootRunId !== rootRunId)
60829
- continue;
60830
- if (resolved && hops && !stageMatchesPathPattern(parsed.segments, hops, [stage.id, stage.name]))
60831
- continue;
60832
- const receipts = (entry.deliveries ?? []).filter((delivery) => delivery.runId === run.id && delivery.stageId === stage.id);
61030
+ const receipts = entryReceipts(index, run.id, stage.id);
60833
61031
  const delivered = backend?.hasCachedPendingStageDeliveryReceipt?.(rootRunId, entry.id, {
60834
61032
  runId: run.id,
60835
61033
  stageId: stage.id,
@@ -61147,20 +61345,27 @@ function possibleStageRows(runs, rootRunId, rootRun, backend) {
61147
61345
  if (isTerminalRunStatus(rootRun.status))
61148
61346
  return [];
61149
61347
  const stickyQueued = (rootRun.pendingStageMessages ?? []).filter((entry) => entry.sticky === true && entry.status === "queued");
61348
+ const segmentsByTarget = new Map;
61150
61349
  const stickySegments = (entry) => {
61151
- const parsed = parseWorkflowStageTarget(entry.targetPath ?? entry.stageKey);
61152
- return parsed?.rootRunId === rootRunId ? parsed.segments : undefined;
61350
+ const target = entry.targetPath ?? entry.stageKey;
61351
+ if (segmentsByTarget.has(target))
61352
+ return segmentsByTarget.get(target);
61353
+ const parsed = parseWorkflowStageTarget(target);
61354
+ const segments = parsed?.rootRunId === rootRunId ? parsed.segments : undefined;
61355
+ segmentsByTarget.set(target, segments);
61356
+ return segments;
61153
61357
  };
61154
61358
  const scanEntries = stickyQueued.filter((entry) => {
61155
61359
  const segments = stickySegments(entry);
61156
61360
  return !(segments !== undefined && segments.length === 1 && segments[0] === "**");
61157
61361
  });
61362
+ const liveStageMatches = materializedStageMatcher(runs, rootRunId);
61158
61363
  const rows = [];
61159
61364
  for (const scanEntry of rootRun.possibleStages ?? []) {
61160
61365
  const rowSegments = splitStagePathSegments(scanEntry);
61161
61366
  if (rowSegments.length === 0 || rowSegments.some((segment) => segment.length === 0))
61162
61367
  continue;
61163
- if (!rowSegments.some((segment) => segment.includes("*")) && materializedStageMatches(runs, rootRunId, rowSegments)) {
61368
+ if (!rowSegments.some((segment) => segment.includes("*")) && liveStageMatches(rowSegments)) {
61164
61369
  continue;
61165
61370
  }
61166
61371
  rows.push({
@@ -61181,28 +61386,43 @@ function possibleStageRows(runs, rootRunId, rootRun, backend) {
61181
61386
  }).length
61182
61387
  });
61183
61388
  const statuses = stickyStageDeliveryStatuses(runs, rootRunId, backend);
61184
- for (const target of new Set(statuses.map((status) => status.target))) {
61185
- if (rows.some((row) => row.target === target))
61389
+ const statusesByTarget = new Map;
61390
+ for (const status of statuses) {
61391
+ const forTarget = statusesByTarget.get(status.target);
61392
+ if (forTarget === undefined)
61393
+ statusesByTarget.set(status.target, [status]);
61394
+ else
61395
+ forTarget.push(status);
61396
+ }
61397
+ const queuedByTarget = new Map;
61398
+ for (const entry of stickyQueued) {
61399
+ const target = entry.targetPath ?? entry.stageKey;
61400
+ queuedByTarget.set(target, (queuedByTarget.get(target) ?? 0) + 1);
61401
+ }
61402
+ const rowTargets = new Set(rows.map((row) => row.target));
61403
+ for (const target of statusesByTarget.keys()) {
61404
+ if (rowTargets.has(target))
61186
61405
  continue;
61187
- rows.push({
61188
- target,
61189
- queuedCount: stickyQueued.filter((entry) => (entry.targetPath ?? entry.stageKey) === target).length,
61190
- deliveryOnly: true
61191
- });
61406
+ rowTargets.add(target);
61407
+ rows.push({ target, queuedCount: queuedByTarget.get(target) ?? 0, deliveryOnly: true });
61192
61408
  }
61193
61409
  for (let index = 0;index < rows.length; index++) {
61194
61410
  const row = rows[index];
61195
- const deliveryStates = statuses.filter((status) => status.target === row.target);
61196
- if (deliveryStates.length > 0)
61411
+ const deliveryStates = statusesByTarget.get(row.target);
61412
+ if (deliveryStates !== undefined)
61197
61413
  rows[index] = { ...row, deliveryStates };
61198
61414
  }
61199
61415
  return rows;
61200
61416
  }
61201
- function materializedStageMatches(runs, rootRunId, entrySegments) {
61202
- for (const run of runs) {
61203
- if (durableRootRunIdForRun(runs, run.id) !== rootRunId)
61204
- continue;
61205
- const hops = workflowBoundaryHops(runs, run.id);
61417
+ function materializedStageMatcher(runs, rootRunId) {
61418
+ const runById = new Map(runs.map((run) => [run.id, run]));
61419
+ const hopsFor = createWorkflowBoundaryHopsResolver(runs);
61420
+ const invocationRuns = runs.filter((run) => reciprocalWorkflowRootRunId(runById, run.id) === rootRunId);
61421
+ return (entrySegments) => materializedStageMatches(invocationRuns, hopsFor, entrySegments);
61422
+ }
61423
+ function materializedStageMatches(invocationRuns, hopsFor, entrySegments) {
61424
+ for (const run of invocationRuns) {
61425
+ const hops = hopsFor(run.id);
61206
61426
  if (hops === undefined)
61207
61427
  continue;
61208
61428
  for (const stage of run.stages) {
@@ -61477,10 +61697,12 @@ async function recordConfirmedStickyDeliveries(activeStore, event) {
61477
61697
  }
61478
61698
  function matchingLiveStages(runs, rootRunId, patternSegments) {
61479
61699
  const matches = [];
61700
+ const runById = new Map(runs.map((run) => [run.id, run]));
61701
+ const hopsFor = createWorkflowBoundaryHopsResolver(runs);
61480
61702
  for (const run of runs) {
61481
- if (durableRootRunIdForRun(runs, run.id) !== rootRunId)
61703
+ if (reciprocalWorkflowRootRunId(runById, run.id) !== rootRunId)
61482
61704
  continue;
61483
- const hops = workflowBoundaryHops(runs, run.id);
61705
+ const hops = hopsFor(run.id);
61484
61706
  if (hops === undefined)
61485
61707
  continue;
61486
61708
  for (const stage of run.stages) {
@@ -61616,11 +61838,26 @@ function writeMessage(socket, msg, callback) {
61616
61838
  }
61617
61839
  function createMessageReader(onMessage, onError) {
61618
61840
  let buffer = Buffer.alloc(0);
61841
+ let pending = [];
61842
+ let pendingLength = 0;
61843
+ let awaitedLength = 0;
61619
61844
  return (data) => {
61620
- buffer = Buffer.concat([buffer, data]);
61845
+ if (pendingLength + data.length < awaitedLength) {
61846
+ pending.push(data);
61847
+ pendingLength += data.length;
61848
+ return;
61849
+ }
61850
+ buffer = pending.length === 0 ? Buffer.concat([buffer, data]) : Buffer.concat([...pending, data]);
61851
+ pending = [];
61852
+ pendingLength = 0;
61853
+ awaitedLength = 0;
61621
61854
  while (buffer.length >= 4) {
61622
61855
  const length = buffer.readUInt32BE(0);
61623
61856
  if (buffer.length < 4 + length) {
61857
+ pending = [buffer];
61858
+ pendingLength = buffer.length;
61859
+ awaitedLength = 4 + length;
61860
+ buffer = Buffer.alloc(0);
61624
61861
  break;
61625
61862
  }
61626
61863
  const payload = buffer.subarray(4, 4 + length);