@schoolai/shipyard 3.16.0 → 3.16.1-rc.20260616.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.
Files changed (29) hide show
  1. package/dist/capability-detector-worker.js +4 -4
  2. package/dist/{chunk-VTALUCDB.js → chunk-4FVMGXFP.js} +2 -2
  3. package/dist/{chunk-M6VDKNFY.js → chunk-5WJSHXUB.js} +3 -3
  4. package/dist/{chunk-E2NXVJUG.js → chunk-CZPRQJ46.js} +2 -2
  5. package/dist/{chunk-AXHG3QQA.js → chunk-FJXRLZZI.js} +5 -3
  6. package/dist/{chunk-AXHG3QQA.js.map → chunk-FJXRLZZI.js.map} +1 -1
  7. package/dist/{chunk-5PBWS7BB.js → chunk-URRNZGFO.js} +4 -4
  8. package/dist/{chunk-HPDRJ4VZ.js → chunk-UZT6JIJ5.js} +2 -2
  9. package/dist/{chunk-6SK6FBYC.js → chunk-WMD76UPS.js} +2 -2
  10. package/dist/{chunk-RHHRJR3L.js → chunk-X3TOIQUD.js} +2 -2
  11. package/dist/cursor-runner.js +3 -3
  12. package/dist/electron-utility.js +2 -2
  13. package/dist/index.js +4 -4
  14. package/dist/{login-EYGYOEXL.js → login-7YFYG2ZB.js} +3 -3
  15. package/dist/{plan-backfill-SMJEKTMM.js → plan-backfill-DVXCXD3E.js} +4 -4
  16. package/dist/{serve-HGXTONFE.js → serve-JDYY2S3C.js} +206 -80
  17. package/dist/{serve-HGXTONFE.js.map → serve-JDYY2S3C.js.map} +1 -1
  18. package/dist/{start-CUWE2FYT.js → start-VJOHZ5BC.js} +6 -6
  19. package/package.json +1 -1
  20. /package/dist/{chunk-VTALUCDB.js.map → chunk-4FVMGXFP.js.map} +0 -0
  21. /package/dist/{chunk-M6VDKNFY.js.map → chunk-5WJSHXUB.js.map} +0 -0
  22. /package/dist/{chunk-E2NXVJUG.js.map → chunk-CZPRQJ46.js.map} +0 -0
  23. /package/dist/{chunk-5PBWS7BB.js.map → chunk-URRNZGFO.js.map} +0 -0
  24. /package/dist/{chunk-HPDRJ4VZ.js.map → chunk-UZT6JIJ5.js.map} +0 -0
  25. /package/dist/{chunk-6SK6FBYC.js.map → chunk-WMD76UPS.js.map} +0 -0
  26. /package/dist/{chunk-RHHRJR3L.js.map → chunk-X3TOIQUD.js.map} +0 -0
  27. /package/dist/{login-EYGYOEXL.js.map → login-7YFYG2ZB.js.map} +0 -0
  28. /package/dist/{plan-backfill-SMJEKTMM.js.map → plan-backfill-DVXCXD3E.js.map} +0 -0
  29. /package/dist/{start-CUWE2FYT.js.map → start-VJOHZ5BC.js.map} +0 -0
@@ -38,7 +38,7 @@ import {
38
38
  formatTaskFeedback,
39
39
  toRecord,
40
40
  toSdkContent
41
- } from "./chunk-6SK6FBYC.js";
41
+ } from "./chunk-WMD76UPS.js";
42
42
  import {
43
43
  AGENT_IDS,
44
44
  AGENT_SYSTEM_CLAUDE_CODE,
@@ -50,14 +50,14 @@ import {
50
50
  REASONING_EFFORTS,
51
51
  inflateToolResultContent,
52
52
  isImageMimeType
53
- } from "./chunk-VTALUCDB.js";
53
+ } from "./chunk-4FVMGXFP.js";
54
54
  import {
55
55
  AnthropicAuthStatusSchema,
56
56
  CodexAuthStatusSchema,
57
57
  CursorAuthStatusSchema,
58
58
  PermissionModeSchema,
59
59
  TESTED_CODEX_VERSION
60
- } from "./chunk-AXHG3QQA.js";
60
+ } from "./chunk-FJXRLZZI.js";
61
61
  import {
62
62
  logger
63
63
  } from "./chunk-X53VIV2J.js";
@@ -8207,4 +8207,4 @@ export {
8207
8207
  refreshInstalledAgents,
8208
8208
  refreshCodexAuthSlice
8209
8209
  };
8210
- //# sourceMappingURL=chunk-5PBWS7BB.js.map
8210
+ //# sourceMappingURL=chunk-URRNZGFO.js.map
@@ -30,7 +30,7 @@ import {
30
30
  parseShipyardDeliverableUrl,
31
31
  planEditorSerializer,
32
32
  toTaskIndexEntry
33
- } from "./chunk-VTALUCDB.js";
33
+ } from "./chunk-4FVMGXFP.js";
34
34
  import {
35
35
  assertNever
36
36
  } from "./chunk-X3MULCV5.js";
@@ -34718,4 +34718,4 @@ export {
34718
34718
  runPlanBackfill,
34719
34719
  buildTaskStateStore
34720
34720
  };
34721
- //# sourceMappingURL=chunk-HPDRJ4VZ.js.map
34721
+ //# sourceMappingURL=chunk-UZT6JIJ5.js.map
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  isImageMimeType,
4
4
  parseAssetUri
5
- } from "./chunk-VTALUCDB.js";
5
+ } from "./chunk-4FVMGXFP.js";
6
6
  import {
7
7
  assertNever
8
8
  } from "./chunk-X3MULCV5.js";
@@ -588,4 +588,4 @@ export {
588
588
  toRecord,
589
589
  buildCursorUserPrompt
590
590
  };
591
- //# sourceMappingURL=chunk-6SK6FBYC.js.map
591
+ //# sourceMappingURL=chunk-WMD76UPS.js.map
@@ -15,7 +15,7 @@ import {
15
15
  DevicePollResponseSchema,
16
16
  DeviceStartResponseSchema,
17
17
  ROUTES
18
- } from "./chunk-AXHG3QQA.js";
18
+ } from "./chunk-FJXRLZZI.js";
19
19
  import {
20
20
  isDevMode,
21
21
  validateEnv
@@ -223,4 +223,4 @@ export {
223
223
  ensureAuthenticated,
224
224
  loginCommand
225
225
  };
226
- //# sourceMappingURL=chunk-RHHRJR3L.js.map
226
+ //# sourceMappingURL=chunk-X3TOIQUD.js.map
@@ -4,12 +4,12 @@ import {
4
4
  } from "./chunk-D3JA5MXR.js";
5
5
  import {
6
6
  buildCursorUserPrompt
7
- } from "./chunk-6SK6FBYC.js";
7
+ } from "./chunk-WMD76UPS.js";
8
8
  import {
9
9
  ContentBlockSchema,
10
10
  HARNESS_SERVER_NAME
11
- } from "./chunk-VTALUCDB.js";
12
- import "./chunk-AXHG3QQA.js";
11
+ } from "./chunk-4FVMGXFP.js";
12
+ import "./chunk-FJXRLZZI.js";
13
13
  import "./chunk-EHQITHQX.js";
14
14
  import "./chunk-X3MULCV5.js";
15
15
  import "./chunk-X53VIV2J.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getDaemonVersion
4
- } from "./chunk-M6VDKNFY.js";
4
+ } from "./chunk-5WJSHXUB.js";
5
5
  import {
6
6
  enableNativeCrashReports
7
7
  } from "./chunk-TSJOSKN3.js";
@@ -71,7 +71,7 @@ async function main() {
71
71
  await loadAuthFromConfig(env);
72
72
  crumb("post-auth-load");
73
73
  crumb("pre-serve-import");
74
- const { serve } = await import("./serve-HGXTONFE.js");
74
+ const { serve } = await import("./serve-JDYY2S3C.js");
75
75
  crumb("post-serve-import");
76
76
  const portQueue = [];
77
77
  let acceptor = null;
package/dist/index.js CHANGED
@@ -113,7 +113,7 @@ async function loadAuthFromConfig(env) {
113
113
  async function handleSubcommand() {
114
114
  const subcommand = process.argv[2];
115
115
  if (subcommand === "login") {
116
- const { loginCommand } = await import("./login-EYGYOEXL.js");
116
+ const { loginCommand } = await import("./login-7YFYG2ZB.js");
117
117
  const hasCheck = process.argv.includes("--check");
118
118
  await loginCommand({ check: hasCheck });
119
119
  return true;
@@ -124,7 +124,7 @@ async function handleSubcommand() {
124
124
  return true;
125
125
  }
126
126
  if (subcommand === "start") {
127
- const { startCommand } = await import("./start-CUWE2FYT.js");
127
+ const { startCommand } = await import("./start-VJOHZ5BC.js");
128
128
  await startCommand();
129
129
  return true;
130
130
  }
@@ -134,7 +134,7 @@ async function handleSubcommand() {
134
134
  return true;
135
135
  }
136
136
  if (subcommand === "plan-backfill") {
137
- const { planBackfillCommand } = await import("./plan-backfill-SMJEKTMM.js");
137
+ const { planBackfillCommand } = await import("./plan-backfill-DVXCXD3E.js");
138
138
  await planBackfillCommand();
139
139
  return true;
140
140
  }
@@ -146,7 +146,7 @@ async function main() {
146
146
  const args = parseCliArgs();
147
147
  if (args.serve) {
148
148
  await loadAuthFromConfig(env);
149
- const { serve } = await import("./serve-HGXTONFE.js");
149
+ const { serve } = await import("./serve-JDYY2S3C.js");
150
150
  return serve({ isDev: env.SHIPYARD_DEV });
151
151
  }
152
152
  logger.error("Use `shipyard start` to run the daemon. Use --help for usage.");
@@ -3,10 +3,10 @@ import {
3
3
  ensureAuthenticated,
4
4
  getSignalingUrl,
5
5
  loginCommand
6
- } from "./chunk-RHHRJR3L.js";
6
+ } from "./chunk-X3TOIQUD.js";
7
7
  import "./chunk-ZHLJRR5O.js";
8
8
  import "./chunk-TFWDJCUJ.js";
9
- import "./chunk-AXHG3QQA.js";
9
+ import "./chunk-FJXRLZZI.js";
10
10
  import "./chunk-EHQITHQX.js";
11
11
  import "./chunk-X53VIV2J.js";
12
12
  import "./chunk-UTL5PF43.js";
@@ -17,4 +17,4 @@ export {
17
17
  getSignalingUrl,
18
18
  loginCommand
19
19
  };
20
- //# sourceMappingURL=login-EYGYOEXL.js.map
20
+ //# sourceMappingURL=login-7YFYG2ZB.js.map
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  buildTaskStateStore,
4
4
  runPlanBackfill
5
- } from "./chunk-HPDRJ4VZ.js";
5
+ } from "./chunk-UZT6JIJ5.js";
6
6
  import "./chunk-RR6V6SNM.js";
7
- import "./chunk-VTALUCDB.js";
8
- import "./chunk-AXHG3QQA.js";
7
+ import "./chunk-4FVMGXFP.js";
8
+ import "./chunk-FJXRLZZI.js";
9
9
  import "./chunk-EHQITHQX.js";
10
10
  import "./chunk-X3MULCV5.js";
11
11
  import {
@@ -65,4 +65,4 @@ async function planBackfillCommand(argv = process.argv.slice(3)) {
65
65
  export {
66
66
  planBackfillCommand
67
67
  };
68
- //# sourceMappingURL=plan-backfill-SMJEKTMM.js.map
68
+ //# sourceMappingURL=plan-backfill-DVXCXD3E.js.map
@@ -12,7 +12,7 @@ import {
12
12
  guardedSubscribe,
13
13
  makeInitialAttemptState,
14
14
  shutdownFileWatcherGuard
15
- } from "./chunk-E2NXVJUG.js";
15
+ } from "./chunk-CZPRQJ46.js";
16
16
  import {
17
17
  TRAILER_SCHEMA_VERSION,
18
18
  appendTrailerToMessage,
@@ -39,13 +39,13 @@ import {
39
39
  startPlanBackfillForDaemon,
40
40
  sync,
41
41
  validatePeerId
42
- } from "./chunk-HPDRJ4VZ.js";
42
+ } from "./chunk-UZT6JIJ5.js";
43
43
  import {
44
44
  loadAuthToken
45
45
  } from "./chunk-TFWDJCUJ.js";
46
46
  import {
47
47
  getDaemonVersion
48
- } from "./chunk-M6VDKNFY.js";
48
+ } from "./chunk-5WJSHXUB.js";
49
49
  import {
50
50
  collectPriorCrashDetail,
51
51
  getRecentWasmPanicMessages
@@ -168,7 +168,7 @@ import {
168
168
  translateWarningNotification,
169
169
  unresolveReviewThread,
170
170
  writeCursorApiKeyToVault
171
- } from "./chunk-5PBWS7BB.js";
171
+ } from "./chunk-URRNZGFO.js";
172
172
  import {
173
173
  buildNodeSpawnEnv,
174
174
  nodeSpawnEnvOverlay,
@@ -229,7 +229,7 @@ import {
229
229
  createAssetResolver,
230
230
  toSdkContent,
231
231
  toSdkPermissionMode
232
- } from "./chunk-6SK6FBYC.js";
232
+ } from "./chunk-WMD76UPS.js";
233
233
  import {
234
234
  AGENT_IDS,
235
235
  AGENT_SYSTEM_CLAUDE_CODE,
@@ -411,7 +411,7 @@ import {
411
411
  unsafeAssertSourceId,
412
412
  vizFileExtension,
413
413
  withPreferredRuntimeAuthMethod
414
- } from "./chunk-VTALUCDB.js";
414
+ } from "./chunk-4FVMGXFP.js";
415
415
  import {
416
416
  AuthGitHubCallbackRequestSchema,
417
417
  AuthGitHubCallbackResponseSchema,
@@ -459,7 +459,7 @@ import {
459
459
  VaultKeyPutResponseSchema,
460
460
  classifyClaudeCodeCompatibility,
461
461
  classifyCodexCompatibility
462
- } from "./chunk-AXHG3QQA.js";
462
+ } from "./chunk-FJXRLZZI.js";
463
463
  import {
464
464
  external_exports as external_exports2
465
465
  } from "./chunk-EHQITHQX.js";
@@ -5769,7 +5769,7 @@ function nanoid(size = 21) {
5769
5769
  }
5770
5770
 
5771
5771
  // src/services/bootstrap/signaling.ts
5772
- var DAEMON_NPM_VERSION = true ? "3.16.0" : "unknown";
5772
+ var DAEMON_NPM_VERSION = true ? "3.16.1" : "unknown";
5773
5773
  function createDaemonSignaling(config) {
5774
5774
  const agentId = config.agentId ?? nanoid();
5775
5775
  function send(msg) {
@@ -30218,10 +30218,24 @@ function assertNever4(x2) {
30218
30218
  function machineIdToPeerId(machineId) {
30219
30219
  return machineId;
30220
30220
  }
30221
+ var MAX_REINITIATE_ATTEMPTS = 5;
30222
+ function computeReinitiateDelayMs(attempt) {
30223
+ const clamped = Math.min(Math.max(attempt, 1), MAX_REINITIATE_ATTEMPTS);
30224
+ return 2 ** (clamped - 1) * 1e3;
30225
+ }
30226
+ function hasTurnServer(iceServers) {
30227
+ return iceServers.some((server) => {
30228
+ const urls = Array.isArray(server.urls) ? server.urls : [server.urls];
30229
+ return urls.some((url) => url.startsWith("turn:") || url.startsWith("turns:"));
30230
+ });
30231
+ }
30221
30232
  async function loadDefaultFactory(iceServers) {
30222
30233
  const { RTCPeerConnection } = await import("node-datachannel/polyfill");
30223
- return () => {
30224
- const pc = new RTCPeerConnection({ iceServers: iceServers ?? DEFAULT_ICE_SERVERS });
30234
+ return (iceTransportPolicy) => {
30235
+ const pc = new RTCPeerConnection({
30236
+ iceServers: iceServers ?? DEFAULT_ICE_SERVERS,
30237
+ ...iceTransportPolicy ? { iceTransportPolicy } : {}
30238
+ });
30225
30239
  return pc;
30226
30240
  };
30227
30241
  }
@@ -30371,6 +30385,10 @@ function createPeerManager(config) {
30371
30385
  const peers = /* @__PURE__ */ new Map();
30372
30386
  const pendingCreates = /* @__PURE__ */ new Map();
30373
30387
  const loroGuards = /* @__PURE__ */ new Map();
30388
+ const initiatorTargets = /* @__PURE__ */ new Set();
30389
+ const relayPreferred = /* @__PURE__ */ new Set();
30390
+ const reinitiateAttempts = /* @__PURE__ */ new Map();
30391
+ const reinitiateTimers = /* @__PURE__ */ new Map();
30374
30392
  let factoryPromise = null;
30375
30393
  function disposeLoroGuard(peerId) {
30376
30394
  const guard = loroGuards.get(peerId);
@@ -30537,6 +30555,24 @@ function createPeerManager(config) {
30537
30555
  });
30538
30556
  return true;
30539
30557
  }
30558
+ function flushPendingCandidates(fromMachineId, entry) {
30559
+ const buffered = entry.pendingCandidates;
30560
+ entry.pendingCandidates = [];
30561
+ for (const candidate of buffered) {
30562
+ entry.pc.addIceCandidate(candidate).catch((err3) => {
30563
+ config.logAdapter?.({
30564
+ event: "webrtc_ice_apply_failed",
30565
+ fromMachineId,
30566
+ generationId: entry.generationId,
30567
+ err: String(err3)
30568
+ });
30569
+ config.log.warn(
30570
+ { fromMachineId, generationId: entry.generationId, err: String(err3) },
30571
+ "addIceCandidate (buffered flush) failed"
30572
+ );
30573
+ });
30574
+ }
30575
+ }
30540
30576
  function tearDownPeer(machineId, reason) {
30541
30577
  const peerId = machineIdToPeerId(machineId);
30542
30578
  disposeLoroGuard(peerId);
@@ -30722,6 +30758,44 @@ function createPeerManager(config) {
30722
30758
  );
30723
30759
  }
30724
30760
  }
30761
+ function clearReinitiateState(targetMachineId) {
30762
+ relayPreferred.delete(targetMachineId);
30763
+ reinitiateAttempts.delete(targetMachineId);
30764
+ const timer = reinitiateTimers.get(targetMachineId);
30765
+ if (timer) {
30766
+ clearTimeout(timer);
30767
+ reinitiateTimers.delete(targetMachineId);
30768
+ }
30769
+ }
30770
+ function scheduleReinitiate(targetMachineId) {
30771
+ if (!initiatorTargets.has(targetMachineId)) return;
30772
+ const attempts = reinitiateAttempts.get(targetMachineId) ?? 0;
30773
+ if (attempts >= MAX_REINITIATE_ATTEMPTS) {
30774
+ config.logAdapter?.({ event: "collab_reinitiate_exhausted", targetMachineId });
30775
+ config.log.warn({ targetMachineId, attempts }, "collab re-initiate exhausted");
30776
+ return;
30777
+ }
30778
+ const attempt = attempts + 1;
30779
+ reinitiateAttempts.set(targetMachineId, attempt);
30780
+ relayPreferred.add(targetMachineId);
30781
+ const existing = reinitiateTimers.get(targetMachineId);
30782
+ if (existing) clearTimeout(existing);
30783
+ const delayMs = computeReinitiateDelayMs(attempt);
30784
+ const timer = setTimeout(() => {
30785
+ reinitiateTimers.delete(targetMachineId);
30786
+ if (!initiatorTargets.has(targetMachineId)) return;
30787
+ void initiateOfferImpl(targetMachineId).catch(() => {
30788
+ scheduleReinitiate(targetMachineId);
30789
+ });
30790
+ }, delayMs);
30791
+ reinitiateTimers.set(targetMachineId, timer);
30792
+ config.logAdapter?.({
30793
+ event: "collab_reinitiate_scheduled",
30794
+ targetMachineId,
30795
+ attempt,
30796
+ delayMs
30797
+ });
30798
+ }
30725
30799
  function applyDisconnectWatchdog(machineId, entry, newState) {
30726
30800
  if (newState === "disconnected") {
30727
30801
  if (entry.disconnectWatchdog) clearTimeout(entry.disconnectWatchdog);
@@ -30730,6 +30804,7 @@ function createPeerManager(config) {
30730
30804
  if (stillCurrent !== entry) return;
30731
30805
  if (stillCurrent.lastState !== "disconnected") return;
30732
30806
  tearDownPeer(machineId, "disconnect_watchdog");
30807
+ scheduleReinitiate(machineId);
30733
30808
  }, DISCONNECT_WATCHDOG_MS);
30734
30809
  return;
30735
30810
  }
@@ -30791,11 +30866,105 @@ function createPeerManager(config) {
30791
30866
  currentEntry.lastStateAt = Date.now();
30792
30867
  if (isClose) {
30793
30868
  tearDownPeer(machineId, newState);
30869
+ scheduleReinitiate(machineId);
30794
30870
  return;
30795
30871
  }
30872
+ if (newState === "connected") {
30873
+ clearReinitiateState(machineId);
30874
+ }
30796
30875
  applyDisconnectWatchdog(machineId, currentEntry, newState);
30797
30876
  };
30798
30877
  }
30878
+ async function initiateOfferImpl(targetMachineId) {
30879
+ const generationId = crypto.randomUUID();
30880
+ initiatorTargets.add(targetMachineId);
30881
+ const useRelay = relayPreferred.has(targetMachineId) && hasTurnServer(config.iceServers ?? DEFAULT_ICE_SERVERS);
30882
+ const relayPolicy = useRelay ? "relay" : void 0;
30883
+ config.log.info(
30884
+ { targetMachineId, generationId, iceTransportPolicy: useRelay ? "relay" : "all" },
30885
+ "Initiating WebRTC offer"
30886
+ );
30887
+ config.logAdapter?.({
30888
+ event: "webrtc_initiate",
30889
+ targetMachineId,
30890
+ generationId,
30891
+ iceTransportPolicy: useRelay ? "relay" : "all"
30892
+ });
30893
+ const existing = peers.get(targetMachineId);
30894
+ if (existing) {
30895
+ tearDownPeer(targetMachineId, "replaced_by_initiate");
30896
+ }
30897
+ const now = Date.now();
30898
+ let promise;
30899
+ promise = (async () => {
30900
+ try {
30901
+ const factory = await getFactory();
30902
+ const pc = factory(relayPolicy);
30903
+ setupPeerHandlers(targetMachineId, pc, generationId);
30904
+ if (!pc.createOffer) {
30905
+ throw new Error("PeerConnection does not support createOffer");
30906
+ }
30907
+ setupInitiatorDataChannel(pc, targetMachineId, generationId);
30908
+ const offer = await pc.createOffer();
30909
+ await pc.setLocalDescription(offer);
30910
+ const entry = {
30911
+ pc,
30912
+ generationId,
30913
+ createdAt: now,
30914
+ lastState: "new",
30915
+ lastStateAt: now,
30916
+ offerSdp: offer.sdp,
30917
+ /** Initiator has only its local offer; the remote answer lands later via handleAnswer. */
30918
+ remoteDescriptionApplied: false,
30919
+ pendingCandidates: []
30920
+ };
30921
+ if (pendingCreates.get(targetMachineId) !== promise) {
30922
+ disposeLoroGuard(machineIdToPeerId(targetMachineId));
30923
+ discardSupersededPc(pc, "webrtc_initiate_superseded", {
30924
+ targetMachineId,
30925
+ generationId
30926
+ });
30927
+ return entry;
30928
+ }
30929
+ peers.set(targetMachineId, entry);
30930
+ pendingCreates.delete(targetMachineId);
30931
+ config.onOffer?.(targetMachineId, { type: "offer", sdp: offer.sdp }, generationId);
30932
+ return entry;
30933
+ } catch (err3) {
30934
+ if (pendingCreates.get(targetMachineId) === promise) {
30935
+ pendingCreates.delete(targetMachineId);
30936
+ }
30937
+ config.logAdapter?.({
30938
+ event: "webrtc_initiate_handshake_failed",
30939
+ targetMachineId,
30940
+ generationId,
30941
+ err: String(err3)
30942
+ });
30943
+ throw err3;
30944
+ }
30945
+ })();
30946
+ pendingCreates.set(targetMachineId, promise);
30947
+ setTimeout(() => {
30948
+ handleInitiateHandshakeTimeout(targetMachineId, generationId, promise);
30949
+ }, HANDSHAKE_TIMEOUT_MS);
30950
+ await promise;
30951
+ }
30952
+ function handleInitiateHandshakeTimeout(targetMachineId, generationId, promise) {
30953
+ if (pendingCreates.get(targetMachineId) === promise) {
30954
+ pendingCreates.delete(targetMachineId);
30955
+ config.logAdapter?.({
30956
+ event: "webrtc_handshake_timeout",
30957
+ machineId: targetMachineId,
30958
+ generationId
30959
+ });
30960
+ config.log.warn({ targetMachineId, generationId }, "WebRTC handshake timed out (initiator)");
30961
+ }
30962
+ const entry = peers.get(targetMachineId);
30963
+ if (!entry || entry.generationId !== generationId) return;
30964
+ if (entry.lastState === "connected") return;
30965
+ tearDownPeer(targetMachineId, "handshake_timeout");
30966
+ scheduleReinitiate(targetMachineId);
30967
+ }
30799
30968
  return {
30800
30969
  async handleOffer(fromMachineId, offer, generationId) {
30801
30970
  const existing = peers.get(fromMachineId);
@@ -30841,7 +31010,10 @@ function createPeerManager(config) {
30841
31010
  generationId,
30842
31011
  createdAt: now,
30843
31012
  lastState: "new",
30844
- lastStateAt: now
31013
+ lastStateAt: now,
31014
+ /** Answerer applied the offer above; no separate remote-answer step follows. */
31015
+ remoteDescriptionApplied: true,
31016
+ pendingCandidates: []
30845
31017
  };
30846
31018
  if (pendingCreates.get(fromMachineId) !== promise) {
30847
31019
  discardSupersededPc(pc, "webrtc_offer_superseded", { fromMachineId, generationId });
@@ -30879,74 +31051,7 @@ function createPeerManager(config) {
30879
31051
  await promise;
30880
31052
  },
30881
31053
  async initiateOffer(targetMachineId) {
30882
- const generationId = crypto.randomUUID();
30883
- config.log.info({ targetMachineId, generationId }, "Initiating WebRTC offer");
30884
- const existing = peers.get(targetMachineId);
30885
- if (existing) {
30886
- tearDownPeer(targetMachineId, "replaced_by_initiate");
30887
- }
30888
- const now = Date.now();
30889
- let promise;
30890
- promise = (async () => {
30891
- try {
30892
- const factory = await getFactory();
30893
- const pc = factory();
30894
- setupPeerHandlers(targetMachineId, pc, generationId);
30895
- if (!pc.createOffer) {
30896
- throw new Error("PeerConnection does not support createOffer");
30897
- }
30898
- setupInitiatorDataChannel(pc, targetMachineId, generationId);
30899
- const offer = await pc.createOffer();
30900
- await pc.setLocalDescription(offer);
30901
- const entry = {
30902
- pc,
30903
- generationId,
30904
- createdAt: now,
30905
- lastState: "new",
30906
- lastStateAt: now,
30907
- offerSdp: offer.sdp
30908
- };
30909
- if (pendingCreates.get(targetMachineId) !== promise) {
30910
- disposeLoroGuard(machineIdToPeerId(targetMachineId));
30911
- discardSupersededPc(pc, "webrtc_initiate_superseded", {
30912
- targetMachineId,
30913
- generationId
30914
- });
30915
- return entry;
30916
- }
30917
- peers.set(targetMachineId, entry);
30918
- pendingCreates.delete(targetMachineId);
30919
- config.onOffer?.(targetMachineId, { type: "offer", sdp: offer.sdp }, generationId);
30920
- return entry;
30921
- } catch (err3) {
30922
- if (pendingCreates.get(targetMachineId) === promise) {
30923
- pendingCreates.delete(targetMachineId);
30924
- }
30925
- config.logAdapter?.({
30926
- event: "webrtc_initiate_handshake_failed",
30927
- targetMachineId,
30928
- generationId,
30929
- err: String(err3)
30930
- });
30931
- throw err3;
30932
- }
30933
- })();
30934
- pendingCreates.set(targetMachineId, promise);
30935
- setTimeout(() => {
30936
- if (pendingCreates.get(targetMachineId) === promise) {
30937
- pendingCreates.delete(targetMachineId);
30938
- config.logAdapter?.({
30939
- event: "webrtc_handshake_timeout",
30940
- machineId: targetMachineId,
30941
- generationId
30942
- });
30943
- config.log.warn(
30944
- { targetMachineId, generationId },
30945
- "WebRTC handshake timed out (initiator)"
30946
- );
30947
- }
30948
- }, HANDSHAKE_TIMEOUT_MS);
30949
- await promise;
31054
+ await initiateOfferImpl(targetMachineId);
30950
31055
  },
30951
31056
  async handleAnswer(fromMachineId, answer, generationId) {
30952
31057
  const entry = await resolveLiveEntry(fromMachineId, "answer", generationId);
@@ -30969,6 +31074,8 @@ function createPeerManager(config) {
30969
31074
  return assertNever4(decision);
30970
31075
  }
30971
31076
  await entry.pc.setRemoteDescription(answer);
31077
+ entry.remoteDescriptionApplied = true;
31078
+ flushPendingCandidates(fromMachineId, entry);
30972
31079
  },
30973
31080
  async handleIce(fromMachineId, candidate, generationId) {
30974
31081
  const entry = await resolveLiveEntry(fromMachineId, "ice", generationId);
@@ -30990,6 +31097,16 @@ function createPeerManager(config) {
30990
31097
  default:
30991
31098
  return assertNever4(decision);
30992
31099
  }
31100
+ if (!entry.remoteDescriptionApplied) {
31101
+ entry.pendingCandidates.push(candidate);
31102
+ config.logAdapter?.({
31103
+ event: "webrtc_ice_buffered",
31104
+ fromMachineId,
31105
+ generationId,
31106
+ pendingCount: entry.pendingCandidates.length
31107
+ });
31108
+ return;
31109
+ }
30993
31110
  try {
30994
31111
  await entry.pc.addIceCandidate(candidate);
30995
31112
  } catch (err3) {
@@ -31011,6 +31128,8 @@ function createPeerManager(config) {
31011
31128
  },
31012
31129
  closePeer(targetId) {
31013
31130
  tearDownPeer(targetId, "close_peer");
31131
+ initiatorTargets.delete(targetId);
31132
+ clearReinitiateState(targetId);
31014
31133
  },
31015
31134
  destroy() {
31016
31135
  for (const machineId of [...peers.keys()]) {
@@ -31019,9 +31138,16 @@ function createPeerManager(config) {
31019
31138
  for (const guard of loroGuards.values()) {
31020
31139
  guard.dispose();
31021
31140
  }
31141
+ for (const timer of reinitiateTimers.values()) {
31142
+ clearTimeout(timer);
31143
+ }
31022
31144
  peers.clear();
31023
31145
  pendingCreates.clear();
31024
31146
  loroGuards.clear();
31147
+ initiatorTargets.clear();
31148
+ relayPreferred.clear();
31149
+ reinitiateAttempts.clear();
31150
+ reinitiateTimers.clear();
31025
31151
  }
31026
31152
  };
31027
31153
  }
@@ -101186,4 +101312,4 @@ export {
101186
101312
  decideWorkspaceScope,
101187
101313
  serve
101188
101314
  };
101189
- //# sourceMappingURL=serve-HGXTONFE.js.map
101315
+ //# sourceMappingURL=serve-JDYY2S3C.js.map