@cortexkit/aft-bridge 0.64.0 → 0.65.0

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.
@@ -24,6 +24,7 @@ import { isRouteOpenReloadWindowError, isRouteRequestReloadRefusal } from "./err
24
24
  import { asCanonicalRootPath, asRootGeneration, LifecycleRegistry, } from "./lifecycle-registry.js";
25
25
  import { canonicalizeProjectRoot } from "./project-identity.js";
26
26
  import { callPresetFor, HOST_TOOL_NAMES_FIELD, PRESET_FIELD, WORKER_SESSION_FIELD, } from "./transport.js";
27
+ import { deadlineTimer, RESUME_ALLOWANCE_MS, RequestDeadline, WaitClock } from "./wait-clock.js";
27
28
  /** The subc pool is closing and cannot carry another request. */
28
29
  export class SubcTransportShuttingDownError extends SubcCallError {
29
30
  constructor() {
@@ -1081,6 +1082,8 @@ export class SubcTransportPool {
1081
1082
  harness;
1082
1083
  connectionFile;
1083
1084
  handshakeTimeoutMs;
1085
+ clock;
1086
+ waitClock;
1084
1087
  consumerIdentity;
1085
1088
  hostScopes;
1086
1089
  /** Scope identity is host-session-wide, even when the session uses multiple project roots. */
@@ -1144,6 +1147,13 @@ export class SubcTransportPool {
1144
1147
  editSlotSurvives;
1145
1148
  editSlotSurvivesCaptured = false;
1146
1149
  constructor(options) {
1150
+ this.clock = options.clock ?? {
1151
+ now: () => Date.now(),
1152
+ awakeNow: () => performance.now(),
1153
+ setTimeout: (callback, ms) => setTimeout(callback, ms),
1154
+ clearTimeout: (timer) => clearTimeout(timer),
1155
+ };
1156
+ this.waitClock = new WaitClock(() => this.clock.now(), () => this.clock.awakeNow?.() ?? this.clock.now());
1147
1157
  this.connectionFile = options.connectionFile;
1148
1158
  this.harness = options.harness;
1149
1159
  this.handshakeTimeoutMs = options.handshakeTimeoutMs;
@@ -1865,12 +1875,13 @@ export class SubcTransportPool {
1865
1875
  }
1866
1876
  /** Open or reuse a route while guarding every lifecycle boundary. */
1867
1877
  async routeRequest(identity, body, timeoutMs, onProgress, expectedGeneration, abortSignal) {
1868
- const callStartedAt = performance.now();
1878
+ const callStartedAt = this.waitClock.now();
1869
1879
  const callDeadlineMs = timeoutMs ?? SUBC_DEFAULT_REQUEST_TIMEOUT_MS;
1880
+ const deadline = new RequestDeadline(this.waitClock, callDeadlineMs);
1870
1881
  // Charge shared backoff delays even when an injected sleeper advances no real time.
1871
1882
  let scheduledDelayMs = 0;
1872
- const spentMs = () => Math.max(performance.now() - callStartedAt, scheduledDelayMs);
1873
- const remainingMs = () => callDeadlineMs - spentMs();
1883
+ const spentMs = () => Math.max(this.waitClock.now() - callStartedAt, scheduledDelayMs);
1884
+ const remainingMs = () => deadline.remaining() - Math.max(0, scheduledDelayMs - (this.waitClock.now() - callStartedAt));
1874
1885
  const root = asCanonicalRootPath(identity.project_root);
1875
1886
  let generation = expectedGeneration;
1876
1887
  if (this.lifecycleEnabled()) {
@@ -1891,13 +1902,13 @@ export class SubcTransportPool {
1891
1902
  const remaining = remainingMs();
1892
1903
  if (remaining <= 0)
1893
1904
  throw keyChanged ?? callDeadlinePassedError(undefined, callDeadlineMs);
1894
- let timer;
1905
+ let cancelTimer;
1895
1906
  try {
1896
1907
  // Each attempt calls SubcClient.connect anew, which re-reads the connection file.
1897
1908
  const acquired = await Promise.race([
1898
1909
  this.ensureClient(),
1899
1910
  new Promise((resolve) => {
1900
- timer = setTimeout(() => resolve(CALL_DEADLINE_EXPIRED), remaining);
1911
+ cancelTimer = deadlineTimer(this.clock, remainingMs, () => resolve(CALL_DEADLINE_EXPIRED));
1901
1912
  }),
1902
1913
  ]);
1903
1914
  if (acquired === CALL_DEADLINE_EXPIRED) {
@@ -1914,24 +1925,24 @@ export class SubcTransportPool {
1914
1925
  throw error;
1915
1926
  }
1916
1927
  finally {
1917
- clearTimeout(timer);
1928
+ cancelTimer?.();
1918
1929
  }
1919
1930
  const { delayMs, wait } = this.waitForRouteReopenBackoff();
1920
1931
  scheduledDelayMs = spentMs() + delayMs;
1921
1932
  // A shared retry sleeper may outlive this caller's remaining budget.
1922
- let retryTimer;
1933
+ let cancelRetryTimer;
1923
1934
  try {
1924
1935
  const waited = await Promise.race([
1925
1936
  wait,
1926
1937
  new Promise((resolve) => {
1927
- retryTimer = setTimeout(() => resolve(CALL_DEADLINE_EXPIRED), callDeadlineMs - (performance.now() - callStartedAt));
1938
+ cancelRetryTimer = deadlineTimer(this.clock, remainingMs, () => resolve(CALL_DEADLINE_EXPIRED));
1928
1939
  }),
1929
1940
  ]);
1930
1941
  if (waited === CALL_DEADLINE_EXPIRED)
1931
1942
  throw keyChanged;
1932
1943
  }
1933
1944
  finally {
1934
- clearTimeout(retryTimer);
1945
+ cancelRetryTimer?.();
1935
1946
  }
1936
1947
  }
1937
1948
  this.assertRecordLive(record);
@@ -1996,9 +2007,9 @@ export class SubcTransportPool {
1996
2007
  const remaining = remainingMs();
1997
2008
  if (remaining <= 0)
1998
2009
  throw callDeadlinePassedError(lastRefusal, callDeadlineMs);
1999
- let timer;
2010
+ let cancelTimer;
2000
2011
  const expired = new Promise((resolve) => {
2001
- timer = setTimeout(() => resolve(CALL_DEADLINE_EXPIRED), remaining);
2012
+ cancelTimer = deadlineTimer(this.clock, remainingMs, () => resolve(CALL_DEADLINE_EXPIRED));
2002
2013
  });
2003
2014
  try {
2004
2015
  const opened = await Promise.race([openRoute(), expired]);
@@ -2008,7 +2019,7 @@ export class SubcTransportPool {
2008
2019
  return opened;
2009
2020
  }
2010
2021
  finally {
2011
- clearTimeout(timer);
2022
+ cancelTimer?.();
2012
2023
  }
2013
2024
  };
2014
2025
  const openRouteAfterReloadWindow = async () => {
@@ -2101,8 +2112,13 @@ export class SubcTransportPool {
2101
2112
  entry.inflight += 1;
2102
2113
  let request;
2103
2114
  try {
2115
+ // The SDK re-arms an expired request once across sleep, retaining
2116
+ // its correlation while a wake-delayed reply is delivered.
2104
2117
  request = client.request(route, body, {
2105
2118
  timeoutMs: Math.ceil(requestTimeoutMs),
2119
+ // Disable SDK sleep grace if admission already granted the call
2120
+ // its one resume allowance.
2121
+ ...(deadline.resumed ? { sleepGraceMs: 0 } : {}),
2106
2122
  onProgress,
2107
2123
  });
2108
2124
  }
@@ -2262,6 +2278,7 @@ export class SubcTransportPool {
2262
2278
  this.connecting = this.connectFn({
2263
2279
  connectionFile: this.connectionFile,
2264
2280
  handshakeTimeoutMs: this.handshakeTimeoutMs,
2281
+ sleepGraceMs: RESUME_ALLOWANCE_MS,
2265
2282
  onControlPush: (push) => {
2266
2283
  if (owner && this.client === owner)
2267
2284
  this.onScopeRouteClose(push);