create-walle 0.10.1 → 0.10.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.
Files changed (681) hide show
  1. package/README.md +7 -1
  2. package/lib/owner-write-safety.js +135 -0
  3. package/lib/public-runtime.js +13 -5
  4. package/lib/release-schema.json +3 -2
  5. package/lib/runtime-closure-policy.json +11 -8
  6. package/package.json +1 -1
  7. package/template/bin/deps-doctor.js +1 -1
  8. package/template/bin/node-bin.sh +11 -0
  9. package/template/coding-task-manager/api-prompts.js +55 -29
  10. package/template/coding-task-manager/bin/claude-hook.js +62 -4
  11. package/template/coding-task-manager/bin/claude-table-parity.js +307 -0
  12. package/template/coding-task-manager/bin/conversation-storage-auto-migration-lib.js +16 -1
  13. package/template/coding-task-manager/bin/conversation-storage-generation-evidence.js +9 -2
  14. package/template/coding-task-manager/bin/conversation-storage-service-entry-lib.js +16 -1
  15. package/template/coding-task-manager/bin/conversation-storage-walle-owner.js +247 -0
  16. package/template/coding-task-manager/bin/ctm-machine-pair.js +160 -0
  17. package/template/coding-task-manager/bin/ctm-relay-client.js +35 -12
  18. package/template/coding-task-manager/bin/land.js +2069 -0
  19. package/template/coding-task-manager/bin/lead-wait-census.js +1348 -0
  20. package/template/coding-task-manager/bin/memory-census.js +4 -2
  21. package/template/coding-task-manager/bin/memory-sync-verify.js +151 -0
  22. package/template/coding-task-manager/bin/probe-refusal-scope.js +530 -0
  23. package/template/coding-task-manager/bin/repair-foreign-clone.js +564 -0
  24. package/template/coding-task-manager/bin/repair-resume-echo-titles.js +248 -0
  25. package/template/coding-task-manager/bin/write-lock-bench.js +111 -0
  26. package/template/coding-task-manager/db.js +860 -317
  27. package/template/coding-task-manager/git-utils.js +44 -0
  28. package/template/coding-task-manager/lib/acp/acp-client.js +383 -0
  29. package/template/coding-task-manager/lib/acp/dsh-context-truth.js +176 -0
  30. package/template/coding-task-manager/lib/acp/dsh-launch-model.js +302 -0
  31. package/template/coding-task-manager/lib/acp/dsh-mcp-servers.js +194 -0
  32. package/template/coding-task-manager/lib/acp/dsh-prompt-lane.js +616 -0
  33. package/template/coding-task-manager/lib/acp/dsh-route-patch.js +308 -0
  34. package/template/coding-task-manager/lib/acp/dsh-session-runtime.js +522 -0
  35. package/template/coding-task-manager/lib/acp/dsh-transcript.js +395 -0
  36. package/template/coding-task-manager/lib/acp/dsh-usage-log.js +162 -0
  37. package/template/coding-task-manager/lib/acp/ndjson-stdio-transport.js +225 -0
  38. package/template/coding-task-manager/lib/adopted-host-redial.js +47 -7
  39. package/template/coding-task-manager/lib/adopted-launch-environment.js +123 -0
  40. package/template/coding-task-manager/lib/agent-auto-update-runtime.js +0 -3
  41. package/template/coding-task-manager/lib/agent-auto-update.js +26 -10
  42. package/template/coding-task-manager/lib/agent-bundle/build.js +657 -0
  43. package/template/coding-task-manager/lib/agent-bundle/codex-install.js +558 -0
  44. package/template/coding-task-manager/lib/agent-bundle/drift.js +120 -0
  45. package/template/coding-task-manager/lib/agent-bundle/gc.js +522 -0
  46. package/template/coding-task-manager/lib/agent-bundle/inventory.js +346 -0
  47. package/template/coding-task-manager/lib/agent-bundle/push.js +717 -0
  48. package/template/coding-task-manager/lib/agent-bundle/skill-transfer.js +724 -0
  49. package/template/coding-task-manager/lib/agent-bundle/spawn.js +119 -0
  50. package/template/coding-task-manager/lib/agent-bundle/store.js +568 -0
  51. package/template/coding-task-manager/lib/agent-capabilities.js +142 -12
  52. package/template/coding-task-manager/lib/agent-cli-cache.js +30 -5
  53. package/template/coding-task-manager/lib/agent-definitions.js +19 -0
  54. package/template/coding-task-manager/lib/agent-hooks-codex-toml.js +28 -16
  55. package/template/coding-task-manager/lib/agent-hooks-codex-workspace.js +9 -1
  56. package/template/coding-task-manager/lib/agent-hooks-installer.js +23 -8
  57. package/template/coding-task-manager/lib/agent-hooks-prune.js +37 -11
  58. package/template/coding-task-manager/lib/agent-hooks-shim.js +105 -0
  59. package/template/coding-task-manager/lib/agent-presets.js +99 -1
  60. package/template/coding-task-manager/lib/agent-title-apply.js +88 -0
  61. package/template/coding-task-manager/lib/agent-title-backfill-read.js +92 -0
  62. package/template/coding-task-manager/lib/agent-upgrade-jobs.js +12 -1
  63. package/template/coding-task-manager/lib/agent-version-service.js +74 -11
  64. package/template/coding-task-manager/lib/all-sessions-query.js +6 -2
  65. package/template/coding-task-manager/lib/api/agent-bundles.js +436 -0
  66. package/template/coding-task-manager/lib/api/backup-retention.js +83 -0
  67. package/template/coding-task-manager/lib/api/conversation-sync-routes.js +124 -0
  68. package/template/coding-task-manager/lib/api/diagnostics.js +549 -69
  69. package/template/coding-task-manager/lib/api/fleet.js +118 -0
  70. package/template/coding-task-manager/lib/api/host-stats.js +98 -0
  71. package/template/coding-task-manager/lib/api/hub-bridge.js +243 -0
  72. package/template/coding-task-manager/lib/api/ingress.js +43 -12
  73. package/template/coding-task-manager/lib/api/landing.js +403 -0
  74. package/template/coding-task-manager/lib/api/machine-pairing.js +285 -0
  75. package/template/coding-task-manager/lib/api/machine-pool.js +307 -0
  76. package/template/coding-task-manager/lib/api/machines.js +1150 -0
  77. package/template/coding-task-manager/lib/api/memory-sync-routes.js +335 -0
  78. package/template/coding-task-manager/lib/api/misc-ops.js +25 -5
  79. package/template/coding-task-manager/lib/api/providers.js +53 -6
  80. package/template/coding-task-manager/lib/api/remote-sessions.js +1326 -0
  81. package/template/coding-task-manager/lib/api/resume-from-store.js +25 -0
  82. package/template/coding-task-manager/lib/api/session-attach.js +623 -0
  83. package/template/coding-task-manager/lib/api/session-messages.js +1384 -0
  84. package/template/coding-task-manager/lib/api/sessions.js +237 -59
  85. package/template/coding-task-manager/lib/api/setup-network.js +544 -16
  86. package/template/coding-task-manager/lib/api/setup-wizard-handlers.js +884 -0
  87. package/template/coding-task-manager/lib/api/setup.js +829 -10
  88. package/template/coding-task-manager/lib/api/transcript-history.js +17 -4
  89. package/template/coding-task-manager/lib/api/walle-bridge.js +9 -1
  90. package/template/coding-task-manager/lib/api/worktrees.js +38 -37
  91. package/template/coding-task-manager/lib/approval-drift.js +16 -1
  92. package/template/coding-task-manager/lib/approval-logical-frame.js +5 -1
  93. package/template/coding-task-manager/lib/approval-scope.js +68 -4
  94. package/template/coding-task-manager/lib/attachment-reconciler-wiring.js +5 -2
  95. package/template/coding-task-manager/lib/auth-context.js +32 -2
  96. package/template/coding-task-manager/lib/auth-rate-limit.js +64 -1
  97. package/template/coding-task-manager/lib/auth-rules.js +474 -62
  98. package/template/coding-task-manager/lib/background-stop.js +369 -0
  99. package/template/coding-task-manager/lib/best-of-attempts.js +4 -1
  100. package/template/coding-task-manager/lib/best-of-launch-plan.js +52 -0
  101. package/template/coding-task-manager/lib/box-keep-awake.js +89 -0
  102. package/template/coding-task-manager/lib/broadcast-reason-stats.js +152 -0
  103. package/template/coding-task-manager/lib/broadcast-serialize.js +7 -1
  104. package/template/coding-task-manager/lib/browser-session-broker.js +9 -1
  105. package/template/coding-task-manager/lib/browser-use-adapter.js +33 -2
  106. package/template/coding-task-manager/lib/build-info.js +4 -2
  107. package/template/coding-task-manager/lib/claude-markdown-ansi.js +27 -85
  108. package/template/coding-task-manager/lib/claude-model-truth.js +13 -2
  109. package/template/coding-task-manager/lib/claude-session-title.js +6 -30
  110. package/template/coding-task-manager/lib/claude-table-layout.js +322 -0
  111. package/template/coding-task-manager/lib/claude-transcript-terminal-renderer.js +17 -13
  112. package/template/coding-task-manager/lib/client-diag-handler.js +69 -2
  113. package/template/coding-task-manager/lib/codex-app-server-client.js +14 -16
  114. package/template/coding-task-manager/lib/codex-config-guard.js +33 -3
  115. package/template/coding-task-manager/lib/codex-configuration-history.js +55 -0
  116. package/template/coding-task-manager/lib/codex-harness-qualification.js +55 -20
  117. package/template/coding-task-manager/lib/codex-launch-health.js +29 -2
  118. package/template/coding-task-manager/lib/codex-link-preparation.js +9 -8
  119. package/template/coding-task-manager/lib/codex-paths.js +2 -1
  120. package/template/coding-task-manager/lib/codex-rollout-history.js +743 -0
  121. package/template/coding-task-manager/lib/coding-agent-models.js +48 -42
  122. package/template/coding-task-manager/lib/coding-cli-skill-installer.js +44 -14
  123. package/template/coding-task-manager/lib/coding-session-model-adapters.js +70 -4
  124. package/template/coding-task-manager/lib/coding-session-model-owner.js +1 -1
  125. package/template/coding-task-manager/lib/coding-session-model-projection.js +5 -0
  126. package/template/coding-task-manager/lib/coding-session-model-public.js +7 -1
  127. package/template/coding-task-manager/lib/coding-session-model-runtime.js +24 -6
  128. package/template/coding-task-manager/lib/coding-session-model-scan.js +31 -0
  129. package/template/coding-task-manager/lib/coding-session-model-state.js +17 -0
  130. package/template/coding-task-manager/lib/coding-session-model-sync-state.js +0 -1
  131. package/template/coding-task-manager/lib/conversation-freshness-diagnostics.js +280 -0
  132. package/template/coding-task-manager/lib/conversation-import/cursor-guard-owner.js +10 -0
  133. package/template/coding-task-manager/lib/conversation-item-clock.js +261 -0
  134. package/template/coding-task-manager/lib/conversation-source-registry.js +5 -0
  135. package/template/coding-task-manager/lib/conversation-store-v2.js +44 -0
  136. package/template/coding-task-manager/lib/conversation-sync.js +355 -0
  137. package/template/coding-task-manager/lib/create/resolve-launch-params.js +104 -13
  138. package/template/coding-task-manager/lib/create/worker-role-profile.js +4 -4
  139. package/template/coding-task-manager/lib/create-intent-lease.js +51 -0
  140. package/template/coding-task-manager/lib/ctm-boot-lifecycle.js +17 -1
  141. package/template/coding-task-manager/lib/ctm-session-context-api.js +97 -6
  142. package/template/coding-task-manager/lib/db-domain-tables.js +8 -0
  143. package/template/coding-task-manager/lib/db-domains.js +22 -2
  144. package/template/coding-task-manager/lib/db-owner-dispatch-probe.js +32 -0
  145. package/template/coding-task-manager/lib/db-owner-op-registry.js +7 -0
  146. package/template/coding-task-manager/lib/db-owner-request-counts.js +178 -0
  147. package/template/coding-task-manager/lib/db-owner-worker-client.js +68 -14
  148. package/template/coding-task-manager/lib/db-schema-source-files.js +6 -0
  149. package/template/coding-task-manager/lib/deferred-restore-attempt.js +6 -2
  150. package/template/coding-task-manager/lib/feature-manifest.js +5 -1
  151. package/template/coding-task-manager/lib/fleet-conversation-route.js +97 -0
  152. package/template/coding-task-manager/lib/fleet-fanout.js +78 -0
  153. package/template/coding-task-manager/lib/fleet-hub.js +762 -0
  154. package/template/coding-task-manager/lib/fleet-origin-follower.js +252 -0
  155. package/template/coding-task-manager/lib/fleet-resolver-effects.js +147 -0
  156. package/template/coding-task-manager/lib/fleet-resolver-tick.js +148 -0
  157. package/template/coding-task-manager/lib/fleet-resolver.js +454 -0
  158. package/template/coding-task-manager/lib/fleet-session-list-routes.js +114 -0
  159. package/template/coding-task-manager/lib/fleet-session-lists.js +672 -0
  160. package/template/coding-task-manager/lib/fleet-update.js +798 -0
  161. package/template/coding-task-manager/lib/fs-watcher-root-watch.js +141 -0
  162. package/template/coding-task-manager/lib/fs-watcher.js +61 -44
  163. package/template/coding-task-manager/lib/harness-history-transition.js +52 -11
  164. package/template/coding-task-manager/lib/headless-inflight-ops.js +203 -0
  165. package/template/coding-task-manager/lib/headless-missing-reply.js +42 -0
  166. package/template/coding-task-manager/lib/headless-term-service.js +139 -25
  167. package/template/coding-task-manager/lib/hermetic-agent-launch-guard.js +10 -0
  168. package/template/coding-task-manager/lib/history-transition-read-op.js +175 -8
  169. package/template/coding-task-manager/lib/host-control-dial.js +167 -0
  170. package/template/coding-task-manager/lib/host-cpu-categories.js +310 -0
  171. package/template/coding-task-manager/lib/host-fseventsd-sampler.js +399 -0
  172. package/template/coding-task-manager/lib/host-handoff-orchestrator.js +16 -2
  173. package/template/coding-task-manager/lib/host-handoff.js +50 -15
  174. package/template/coding-task-manager/lib/host-health-ledger.js +164 -12
  175. package/template/coding-task-manager/lib/host-self-truth-watchdog.js +4 -0
  176. package/template/coding-task-manager/lib/host-stats.js +475 -0
  177. package/template/coding-task-manager/lib/host-threadpool-evacuation.js +160 -0
  178. package/template/coding-task-manager/lib/host-threadpool-monitor.js +14 -1
  179. package/template/coding-task-manager/lib/hosted-input-dispatch.js +203 -0
  180. package/template/coding-task-manager/lib/hosted-sync-worker.js +141 -310
  181. package/template/coding-task-manager/lib/hub-bridge-access.js +798 -0
  182. package/template/coding-task-manager/lib/hub-bridge-box.js +409 -0
  183. package/template/coding-task-manager/lib/hub-bridge-mcp.js +380 -0
  184. package/template/coding-task-manager/lib/hub-bridge-mesh.js +313 -0
  185. package/template/coding-task-manager/lib/hub-bridge-ops.js +721 -0
  186. package/template/coding-task-manager/lib/hub-bridge.js +398 -0
  187. package/template/coding-task-manager/lib/idle-notify.js +491 -0
  188. package/template/coding-task-manager/lib/instance-id-ownership-manifest.js +12 -0
  189. package/template/coding-task-manager/lib/instance-manifest-runtime.js +3 -0
  190. package/template/coding-task-manager/lib/instance-manifest.js +18 -2
  191. package/template/coding-task-manager/lib/instance-sync-status.js +33 -8
  192. package/template/coding-task-manager/lib/landing/agent-rule.txt +1 -0
  193. package/template/coding-task-manager/lib/landing/batch-runner.js +366 -0
  194. package/template/coding-task-manager/lib/landing/config.js +536 -0
  195. package/template/coding-task-manager/lib/landing/ctm-view.js +256 -0
  196. package/template/coding-task-manager/lib/landing/gate.js +360 -0
  197. package/template/coding-task-manager/lib/landing/git.js +344 -0
  198. package/template/coding-task-manager/lib/landing/lease.js +247 -0
  199. package/template/coding-task-manager/lib/landing/merge-delta.js +380 -0
  200. package/template/coding-task-manager/lib/landing/proof.js +223 -0
  201. package/template/coding-task-manager/lib/landing/queue.js +998 -0
  202. package/template/coding-task-manager/lib/landing/radar.js +489 -0
  203. package/template/coding-task-manager/lib/landing/resolve-cli.js +424 -0
  204. package/template/coding-task-manager/lib/landing/state.js +263 -0
  205. package/template/coding-task-manager/lib/landing/stop.js +49 -0
  206. package/template/coding-task-manager/lib/landing/sync-cli.js +475 -0
  207. package/template/coding-task-manager/lib/landing/sync.js +456 -0
  208. package/template/coding-task-manager/lib/landing/train.js +885 -0
  209. package/template/coding-task-manager/lib/landing/window.js +57 -0
  210. package/template/coding-task-manager/lib/launch-environment.js +121 -0
  211. package/template/coding-task-manager/lib/launch-model-override.js +193 -8
  212. package/template/coding-task-manager/lib/launch-plan-pool.js +2 -1
  213. package/template/coding-task-manager/lib/launch-plan-warm-cache.js +6 -0
  214. package/template/coding-task-manager/lib/launch-plan-worker.js +59 -2
  215. package/template/coding-task-manager/lib/lead-model-observer.js +57 -1
  216. package/template/coding-task-manager/lib/lead-model-options.js +160 -3
  217. package/template/coding-task-manager/lib/lead-model-restore-reconciliation.js +106 -24
  218. package/template/coding-task-manager/lib/lead-model-switch-runtime.js +409 -72
  219. package/template/coding-task-manager/lib/lead-model-switch.js +115 -10
  220. package/template/coding-task-manager/lib/lead-model-transition-runtime.js +14 -2
  221. package/template/coding-task-manager/lib/lead-model-transition-store.js +85 -9
  222. package/template/coding-task-manager/lib/lead-route-preflight.js +179 -0
  223. package/template/coding-task-manager/lib/lead-switch-history-mode.js +110 -0
  224. package/template/coding-task-manager/lib/lead-wire-agent.js +7 -0
  225. package/template/coding-task-manager/lib/legacy-draft-cancellation-recovery.js +111 -0
  226. package/template/coding-task-manager/lib/lifecycle-wake-experiment.js +9 -2
  227. package/template/coding-task-manager/lib/live-defer-announce.js +45 -0
  228. package/template/coding-task-manager/lib/login-tripwire.js +1 -0
  229. package/template/coding-task-manager/lib/machine-pairing.js +238 -0
  230. package/template/coding-task-manager/lib/machine-pool.js +409 -0
  231. package/template/coding-task-manager/lib/machine-registry.js +1494 -0
  232. package/template/coding-task-manager/lib/machine-self.js +66 -0
  233. package/template/coding-task-manager/lib/macos-capabilities.js +32 -15
  234. package/template/coding-task-manager/lib/main-thread-lint-exemptions.json +485 -57
  235. package/template/coding-task-manager/lib/mainloop-observability.js +14 -9
  236. package/template/coding-task-manager/lib/media-draft-owner.js +16 -3
  237. package/template/coding-task-manager/lib/media-journal-control-reader.js +473 -0
  238. package/template/coding-task-manager/lib/media-journal.js +84 -27
  239. package/template/coding-task-manager/lib/media-store-options.js +43 -15
  240. package/template/coding-task-manager/lib/memory-join.js +337 -0
  241. package/template/coding-task-manager/lib/memory-sync-verify.js +393 -0
  242. package/template/coding-task-manager/lib/memory-sync.js +565 -0
  243. package/template/coding-task-manager/lib/migrations/v56-host-samples-and-machine-pool.js +76 -0
  244. package/template/coding-task-manager/lib/migrations/v57-delegate-pref-mirror-opencode.js +68 -0
  245. package/template/coding-task-manager/lib/migrations/v58-subagent-launch-native-subagents.js +42 -0
  246. package/template/coding-task-manager/lib/migrations/v59-coding-session-model-state-dsh.js +73 -0
  247. package/template/coding-task-manager/lib/migrations/v60-delegate-pref-mirror-dsh.js +78 -0
  248. package/template/coding-task-manager/lib/migrations/v61-conversation-item-clock.js +71 -0
  249. package/template/coding-task-manager/lib/mirror-feed-sanitize.js +12 -3
  250. package/template/coding-task-manager/lib/model-availability.js +727 -0
  251. package/template/coding-task-manager/lib/model-execution-recipe-metadata.js +4 -6
  252. package/template/coding-task-manager/lib/model-host-receipt.js +6 -3
  253. package/template/coding-task-manager/lib/model-id-rule.js +19 -0
  254. package/template/coding-task-manager/lib/model-proxy/anthropic-face.js +8 -0
  255. package/template/coding-task-manager/lib/model-proxy/auto-mode-review.js +110 -23
  256. package/template/coding-task-manager/lib/model-proxy/chat-response-translators.js +6 -0
  257. package/template/coding-task-manager/lib/model-proxy/generation-probe.js +60 -17
  258. package/template/coding-task-manager/lib/model-proxy/handoff.js +494 -0
  259. package/template/coding-task-manager/lib/model-proxy/historical-tool-declarations.js +37 -0
  260. package/template/coding-task-manager/lib/model-proxy/lead-request-validation.js +1 -0
  261. package/template/coding-task-manager/lib/model-proxy/lead-token-admin.js +130 -0
  262. package/template/coding-task-manager/lib/model-proxy/lead-worker-picks.js +25 -0
  263. package/template/coding-task-manager/lib/model-proxy/native-lead-listener.js +61 -7
  264. package/template/coding-task-manager/lib/model-proxy/proxy-cli.js +200 -0
  265. package/template/coding-task-manager/lib/model-proxy/proxy-instance-record.js +257 -0
  266. package/template/coding-task-manager/lib/model-proxy/refusal-scope.js +151 -0
  267. package/template/coding-task-manager/lib/model-proxy/request-budget-store.js +11 -2
  268. package/template/coding-task-manager/lib/model-proxy/stream-accounting.js +205 -0
  269. package/template/coding-task-manager/lib/model-proxy/tokens.js +147 -5
  270. package/template/coding-task-manager/lib/model-proxy/upstream-outcome.js +18 -0
  271. package/template/coding-task-manager/lib/native-agent-model-args.js +25 -22
  272. package/template/coding-task-manager/lib/native-history-control.js +7 -5
  273. package/template/coding-task-manager/lib/native-lead-settings-client.js +46 -5
  274. package/template/coding-task-manager/lib/native-lead-tls.js +18 -4
  275. package/template/coding-task-manager/lib/oauth-proxy-supervisor.js +776 -75
  276. package/template/coding-task-manager/lib/online-backup-worker-client.js +2 -0
  277. package/template/coding-task-manager/lib/opencode-cli.js +480 -0
  278. package/template/coding-task-manager/lib/opencode-launch-model.js +471 -0
  279. package/template/coding-task-manager/lib/opencode-v1-plugin/model-carrier.mjs +35 -0
  280. package/template/coding-task-manager/lib/opencode-v2-plugin/server.js +118 -0
  281. package/template/coding-task-manager/lib/owner-action-manifest-data.json +15 -1
  282. package/template/coding-task-manager/lib/painted-row-recorder.js +9 -1
  283. package/template/coding-task-manager/lib/park-composer-draft.js +54 -0
  284. package/template/coding-task-manager/lib/park-fresh-relaunch.js +41 -10
  285. package/template/coding-task-manager/lib/perf-phase-trace.js +72 -0
  286. package/template/coding-task-manager/lib/perf-summary.js +7 -0
  287. package/template/coding-task-manager/lib/perf-tracker.js +63 -2
  288. package/template/coding-task-manager/lib/project-config.js +7 -0
  289. package/template/coding-task-manager/lib/prompt-purge-v2.js +52 -1
  290. package/template/coding-task-manager/lib/prompt-submission-contract.js +21 -1
  291. package/template/coding-task-manager/lib/provider-login-broker.js +264 -24
  292. package/template/coding-task-manager/lib/provider-login-capture.js +153 -0
  293. package/template/coding-task-manager/lib/provider-login-tab.js +10 -2
  294. package/template/coding-task-manager/lib/queue-draft-status-overlay.js +36 -0
  295. package/template/coding-task-manager/lib/raw-codex-history-window.js +5 -3
  296. package/template/coding-task-manager/lib/read-pool-client.js +94 -4
  297. package/template/coding-task-manager/lib/read-pool-op-registry.js +10 -1
  298. package/template/coding-task-manager/lib/read-pool-worker-handle.js +29 -4
  299. package/template/coding-task-manager/lib/recent-catalog-query.js +41 -0
  300. package/template/coding-task-manager/lib/recent-session-catalog-response.js +76 -10
  301. package/template/coding-task-manager/lib/recovery-evidence.js +26 -11
  302. package/template/coding-task-manager/lib/relay-client.js +57 -3
  303. package/template/coding-task-manager/lib/relink-audit.js +34 -5
  304. package/template/coding-task-manager/lib/remote-command-context.js +12 -0
  305. package/template/coding-task-manager/lib/remote-command-runtime.js +13 -1
  306. package/template/coding-task-manager/lib/remote-machine-catalog.js +1357 -0
  307. package/template/coding-task-manager/lib/remote-machine-create.js +1233 -0
  308. package/template/coding-task-manager/lib/remote-machine-link.js +1426 -0
  309. package/template/coding-task-manager/lib/remote-machine-proxy.js +654 -0
  310. package/template/coding-task-manager/lib/remote-session-forward.js +364 -0
  311. package/template/coding-task-manager/lib/remote-submission-status.js +6 -0
  312. package/template/coding-task-manager/lib/remote-terminal-target.js +9 -2
  313. package/template/coding-task-manager/lib/restart-guard.js +18 -6
  314. package/template/coding-task-manager/lib/restart-outcome-truth.js +20 -3
  315. package/template/coding-task-manager/lib/restart-preflight.js +9 -2
  316. package/template/coding-task-manager/lib/restore-backoff-gate.js +10 -2
  317. package/template/coding-task-manager/lib/restore-prepare-retry.js +12 -5
  318. package/template/coding-task-manager/lib/restore-resume-batch.js +22 -1
  319. package/template/coding-task-manager/lib/restore-seed-modes.js +87 -0
  320. package/template/coding-task-manager/lib/restored-scrollback-hydration-runtime.js +22 -2
  321. package/template/coding-task-manager/lib/resume-admission.js +17 -3
  322. package/template/coding-task-manager/lib/resume-blocked-wire.js +62 -1
  323. package/template/coding-task-manager/lib/resume-cwd.js +13 -0
  324. package/template/coding-task-manager/lib/resume-from-store.js +12 -1
  325. package/template/coding-task-manager/lib/resume-origin-facts.js +38 -1
  326. package/template/coding-task-manager/lib/resume-preflight.js +21 -16
  327. package/template/coding-task-manager/lib/review-repo-admission.js +39 -6
  328. package/template/coding-task-manager/lib/review-repo-registry.js +74 -18
  329. package/template/coding-task-manager/lib/root-delivery-runtime.js +74 -17
  330. package/template/coding-task-manager/lib/root-delivery-selection.js +37 -1
  331. package/template/coding-task-manager/lib/root-prompt-admission.js +33 -2
  332. package/template/coding-task-manager/lib/root-prompt-flow.js +168 -34
  333. package/template/coding-task-manager/lib/runtime-contract.js +3 -1
  334. package/template/coding-task-manager/lib/schema-indexes.js +1 -0
  335. package/template/coding-task-manager/lib/scrollback-archive-store.js +7 -4
  336. package/template/coding-task-manager/lib/session-analysis-memory.js +2 -0
  337. package/template/coding-task-manager/lib/session-context-locator.js +742 -0
  338. package/template/coding-task-manager/lib/session-create/attachment.js +2 -2
  339. package/template/coding-task-manager/lib/session-create/codex-native-provider-gate.js +218 -0
  340. package/template/coding-task-manager/lib/session-create/codex-resume-exit-classify.js +52 -0
  341. package/template/coding-task-manager/lib/session-create/create-phases.js +118 -0
  342. package/template/coding-task-manager/lib/session-create/delegate-worker.js +179 -20
  343. package/template/coding-task-manager/lib/session-create/dsh-session.js +930 -0
  344. package/template/coding-task-manager/lib/session-create/identity.js +20 -1
  345. package/template/coding-task-manager/lib/session-create/lead-route-launch.js +186 -13
  346. package/template/coding-task-manager/lib/session-create/native-lead-lifetime.js +55 -3
  347. package/template/coding-task-manager/lib/session-create/opencode-lead-provider.js +50 -0
  348. package/template/coding-task-manager/lib/session-create/prepared.js +201 -9
  349. package/template/coding-task-manager/lib/session-create/provider-launch-context.js +77 -0
  350. package/template/coding-task-manager/lib/session-create/provider-process.js +193 -64
  351. package/template/coding-task-manager/lib/session-create/response.js +37 -19
  352. package/template/coding-task-manager/lib/session-create/structured-session.js +27 -0
  353. package/template/coding-task-manager/lib/session-create/subagent-pick-table.js +3 -1
  354. package/template/coding-task-manager/lib/session-create/subagent-pick.js +458 -9
  355. package/template/coding-task-manager/lib/session-create/transcript.js +14 -5
  356. package/template/coding-task-manager/lib/session-create/worker-budget-setup.js +21 -2
  357. package/template/coding-task-manager/lib/session-create/worker-continuation.js +50 -2
  358. package/template/coding-task-manager/lib/session-create/worker-launch-sandbox.js +39 -10
  359. package/template/coding-task-manager/lib/session-create/worker-notices.js +94 -5
  360. package/template/coding-task-manager/lib/session-create/worker-observability.js +101 -9
  361. package/template/coding-task-manager/lib/session-create/worker-stop.js +11 -3
  362. package/template/coding-task-manager/lib/session-create/worker-wait-watcher.js +315 -0
  363. package/template/coding-task-manager/lib/session-empty.js +13 -10
  364. package/template/coding-task-manager/lib/session-geometry-authority-handler.js +10 -1
  365. package/template/coding-task-manager/lib/session-host-manager.js +212 -206
  366. package/template/coding-task-manager/lib/session-jobs.js +20 -10
  367. package/template/coding-task-manager/lib/session-lifecycle.js +28 -4
  368. package/template/coding-task-manager/lib/session-model-action-preconditions.js +15 -2
  369. package/template/coding-task-manager/lib/session-model-intent-contract.js +11 -8
  370. package/template/coding-task-manager/lib/session-park.js +738 -0
  371. package/template/coding-task-manager/lib/session-path-grant.js +13 -4
  372. package/template/coding-task-manager/lib/session-resource-sampler.js +19 -9
  373. package/template/coding-task-manager/lib/session-standup.js +67 -4
  374. package/template/coding-task-manager/lib/session-status-ledger.js +147 -6
  375. package/template/coding-task-manager/lib/session-status-runtime.js +45 -1
  376. package/template/coding-task-manager/lib/session-title-mirror.js +25 -57
  377. package/template/coding-task-manager/lib/session-transcript-trash.js +8 -1
  378. package/template/coding-task-manager/lib/session-transport.js +17 -0
  379. package/template/coding-task-manager/lib/session-workspace-projection.js +54 -5
  380. package/template/coding-task-manager/lib/session-workspace-tracking-runtime.js +213 -1
  381. package/template/coding-task-manager/lib/skill-autocomplete-query.js +120 -3
  382. package/template/coding-task-manager/lib/skill-autocomplete.js +15 -1
  383. package/template/coding-task-manager/lib/sqlite-file-set.js +39 -0
  384. package/template/coding-task-manager/lib/standup-search-adapter.js +16 -2
  385. package/template/coding-task-manager/lib/startup-pointer-write.js +57 -0
  386. package/template/coding-task-manager/lib/state-sync/client-ledger.js +12 -0
  387. package/template/coding-task-manager/lib/state-sync/frame-emitter.js +319 -100
  388. package/template/coding-task-manager/lib/state-sync/painted-frame-field.js +11 -0
  389. package/template/coding-task-manager/lib/storage/coding-session-model-store.js +25 -23
  390. package/template/coding-task-manager/lib/storage/delegate-pref-mirror-store.js +32 -9
  391. package/template/coding-task-manager/lib/structured-session-boot-sweep.js +235 -0
  392. package/template/coding-task-manager/lib/submission-ack.js +90 -2
  393. package/template/coding-task-manager/lib/surviving-owner-bootstrap.js +7 -2
  394. package/template/coding-task-manager/lib/surviving-owner-recovery.js +2 -1
  395. package/template/coding-task-manager/lib/systemd-scope.js +115 -0
  396. package/template/coding-task-manager/lib/telemetry-receiver.js +39 -0
  397. package/template/coding-task-manager/lib/terminal-attach-geometry.js +985 -0
  398. package/template/coding-task-manager/lib/terminal-bootstrap.js +30 -0
  399. package/template/coding-task-manager/lib/terminal-draft-http-status.js +25 -0
  400. package/template/coding-task-manager/lib/terminal-draft-operation.js +357 -0
  401. package/template/coding-task-manager/lib/terminal-input-admission.js +17 -1
  402. package/template/coding-task-manager/lib/terminal-input-prepared.js +563 -0
  403. package/template/coding-task-manager/lib/transcript-archiver.js +229 -229
  404. package/template/coding-task-manager/lib/transcript-cache-temps.js +171 -0
  405. package/template/coding-task-manager/lib/transcript-frame-cache.js +20 -5
  406. package/template/coding-task-manager/lib/transcript-guard-job.js +55 -4
  407. package/template/coding-task-manager/lib/transcript-link.js +77 -0
  408. package/template/coding-task-manager/lib/transcript-manifest-store.js +8 -4
  409. package/template/coding-task-manager/lib/transcript-source.js +44 -7
  410. package/template/coding-task-manager/lib/transcript-store.js +49 -0
  411. package/template/coding-task-manager/lib/tunnel-lane-governor.js +6 -3
  412. package/template/coding-task-manager/lib/typing-interaction-trace.js +198 -3
  413. package/template/coding-task-manager/lib/typing-worker-stages.js +60 -0
  414. package/template/coding-task-manager/lib/usage-ledger/backfill.js +40 -5
  415. package/template/coding-task-manager/lib/usage-ledger/client.js +4 -1
  416. package/template/coding-task-manager/lib/usage-ledger/dsh-parse.js +152 -0
  417. package/template/coding-task-manager/lib/usage-ledger/dsh-read.js +73 -0
  418. package/template/coding-task-manager/lib/usage-ledger/ingest.js +34 -6
  419. package/template/coding-task-manager/lib/usage-ledger/live.js +35 -8
  420. package/template/coding-task-manager/lib/usage-ledger/read.js +29 -20
  421. package/template/coding-task-manager/lib/usage-ledger/schema.js +61 -1
  422. package/template/coding-task-manager/lib/usage-ledger/task-coordinator.js +4 -2
  423. package/template/coding-task-manager/lib/visible-revision-watchdog.js +8 -12
  424. package/template/coding-task-manager/lib/wake-skip-reasons.js +47 -0
  425. package/template/coding-task-manager/lib/walle/turn.js +1 -1
  426. package/template/coding-task-manager/lib/walle-history-serve.js +838 -0
  427. package/template/coding-task-manager/lib/walle-kill-authority.js +2 -2
  428. package/template/coding-task-manager/lib/walle-log-rotation.js +164 -1
  429. package/template/coding-task-manager/lib/walle-mcp-auto-config.js +56 -2
  430. package/template/coding-task-manager/lib/walle-row-history.js +495 -0
  431. package/template/coding-task-manager/lib/walle-supervisor.js +130 -27
  432. package/template/coding-task-manager/lib/watch-worker-client.js +203 -0
  433. package/template/coding-task-manager/lib/worker-failure-classify.js +13 -1
  434. package/template/coding-task-manager/lib/worker-terminal-output.js +5 -2
  435. package/template/coding-task-manager/lib/ws/hub-bridge.js +35 -0
  436. package/template/coding-task-manager/lib/ws/lifecycle.js +6 -11
  437. package/template/coding-task-manager/lib/ws/misc.js +1 -1
  438. package/template/coding-task-manager/lib/ws/state-sync.js +125 -6
  439. package/template/coding-task-manager/lib/ws/terminal-attach.js +123 -1
  440. package/template/coding-task-manager/lib/ws-router.js +68 -1
  441. package/template/coding-task-manager/lib/ws-send-admission.js +22 -4
  442. package/template/coding-task-manager/oauth-proxy.js +211 -170
  443. package/template/coding-task-manager/package-lock.json +34 -94
  444. package/template/coding-task-manager/package.json +7 -3
  445. package/template/coding-task-manager/protocol/message-table.json +10 -0
  446. package/template/coding-task-manager/protocol/messages.js +10 -0
  447. package/template/coding-task-manager/protocol/ws-schema.json +20 -0
  448. package/template/coding-task-manager/protocol/ws-schema.md +2 -0
  449. package/template/coding-task-manager/providers/codex-mcp-extract.js +121 -19
  450. package/template/coding-task-manager/providers/codex-mcp.js +14 -5
  451. package/template/coding-task-manager/public/css/app.css +449 -1
  452. package/template/coding-task-manager/public/css/reviews.css +4 -0
  453. package/template/coding-task-manager/public/css/walle-session.css +4 -0
  454. package/template/coding-task-manager/public/index.html +766 -465
  455. package/template/coding-task-manager/public/js/agent-command.js +86 -0
  456. package/template/coding-task-manager/public/js/app/backups-panel.js +111 -5
  457. package/template/coding-task-manager/public/js/app/coding-agent-upgrade.js +103 -4
  458. package/template/coding-task-manager/public/js/app/machines-page.js +2572 -0
  459. package/template/coding-task-manager/public/js/app/models-tab.js +658 -73
  460. package/template/coding-task-manager/public/js/app/restart-banner.js +53 -0
  461. package/template/coding-task-manager/public/js/app/worktrees-panel.js +191 -7
  462. package/template/coding-task-manager/public/js/background-work.js +203 -28
  463. package/template/coding-task-manager/public/js/coding-session-model-presentation.js +181 -13
  464. package/template/coding-task-manager/public/js/core/active-session-groups.js +179 -0
  465. package/template/coding-task-manager/public/js/core/pending-create.js +238 -0
  466. package/template/coding-task-manager/public/js/core/recent-machine-source.js +228 -0
  467. package/template/coding-task-manager/public/js/core/session-commands.js +847 -5
  468. package/template/coding-task-manager/public/js/core/session-selectors.js +5 -1
  469. package/template/coding-task-manager/public/js/dashboard-client-function-order.json +8 -0
  470. package/template/coding-task-manager/public/js/document-review-links.js +9 -1
  471. package/template/coding-task-manager/public/js/file-resolution-client.js +52 -1
  472. package/template/coding-task-manager/public/js/history-app-seam.js +48 -4
  473. package/template/coding-task-manager/public/js/history-painted-rows.js +17 -2
  474. package/template/coding-task-manager/public/js/history-reader-park.js +13 -1
  475. package/template/coding-task-manager/public/js/history-scroller.js +187 -9
  476. package/template/coding-task-manager/public/js/history-transcript-pages.js +5 -5
  477. package/template/coding-task-manager/public/js/machine-pool-shared.js +991 -0
  478. package/template/coding-task-manager/public/js/message-renderer.js +4 -3
  479. package/template/coding-task-manager/public/js/model-picker.js +3 -1
  480. package/template/coding-task-manager/public/js/native-subagent-review.js +15 -2
  481. package/template/coding-task-manager/public/js/new-session-agent-grid.js +346 -0
  482. package/template/coding-task-manager/public/js/pasted-content.js +236 -0
  483. package/template/coding-task-manager/public/js/pe-private-content-lifetime.js +39 -7
  484. package/template/coding-task-manager/public/js/private-model-lifetime.js +6 -2
  485. package/template/coding-task-manager/public/js/private-state-scope.js +31 -3
  486. package/template/coding-task-manager/public/js/prompt-submission-client.js +173 -8
  487. package/template/coding-task-manager/public/js/prompt-submission-tray.js +281 -0
  488. package/template/coding-task-manager/public/js/prompts.js +11 -10
  489. package/template/coding-task-manager/public/js/protocol.js +10 -0
  490. package/template/coding-task-manager/public/js/queue-panel-submission-reconcile.js +174 -1
  491. package/template/coding-task-manager/public/js/restart-banner-policy.js +29 -1
  492. package/template/coding-task-manager/public/js/reviews.js +7 -3
  493. package/template/coding-task-manager/public/js/root-draft-lifetime.js +139 -2
  494. package/template/coding-task-manager/public/js/root-queue-builder-lifetime.js +16 -0
  495. package/template/coding-task-manager/public/js/row-join.js +4 -2
  496. package/template/coding-task-manager/public/js/session-model-picker.js +447 -57
  497. package/template/coding-task-manager/public/js/session-search-utils.js +64 -21
  498. package/template/coding-task-manager/public/js/session-usage-view.js +2 -1
  499. package/template/coding-task-manager/public/js/session-workspace-tracking.js +51 -1
  500. package/template/coding-task-manager/public/js/state-sync-client.js +14 -1
  501. package/template/coding-task-manager/public/js/stream-view.js +6 -5
  502. package/template/coding-task-manager/public/js/terminal/conv-only-session.js +287 -0
  503. package/template/coding-task-manager/public/js/terminal/runtime-02.js +16 -7
  504. package/template/coding-task-manager/public/js/terminal/runtime-03.js +41 -0
  505. package/template/coding-task-manager/public/js/terminal/runtime-04.js +41 -4
  506. package/template/coding-task-manager/public/js/terminal/runtime-09.js +2 -0
  507. package/template/coding-task-manager/public/js/terminal/runtime-10.js +5 -5
  508. package/template/coding-task-manager/public/js/terminal/runtime-12.js +60 -3
  509. package/template/coding-task-manager/public/js/terminal/runtime-16.js +16 -12
  510. package/template/coding-task-manager/public/js/terminal/runtime-18.js +14 -0
  511. package/template/coding-task-manager/public/js/terminal/runtime-19.js +8 -4
  512. package/template/coding-task-manager/public/js/terminal/runtime-20.js +211 -74
  513. package/template/coding-task-manager/public/js/terminal/runtime-21.js +19 -6
  514. package/template/coding-task-manager/public/js/terminal/runtime-22.js +86 -0
  515. package/template/coding-task-manager/public/js/terminal-attachment-draft.js +67 -13
  516. package/template/coding-task-manager/public/js/terminal-history-viewport.js +1 -1
  517. package/template/coding-task-manager/public/js/terminal-image-orchestration.js +52 -6
  518. package/template/coding-task-manager/public/js/terminal-wheel.js +62 -5
  519. package/template/coding-task-manager/public/js/walle/chat-conversation.js +15 -7
  520. package/template/coding-task-manager/public/js/walle-session.js +30 -7
  521. package/template/coding-task-manager/public/js/walle.js +6 -0
  522. package/template/coding-task-manager/public/js/ws/live-dispatch.js +10 -0
  523. package/template/coding-task-manager/public/m/app.css +366 -8
  524. package/template/coding-task-manager/public/m/app.js +1006 -74
  525. package/template/coding-task-manager/public/m/index.html +55 -1
  526. package/template/coding-task-manager/public/m/machines.js +2147 -0
  527. package/template/coding-task-manager/public/m/pool-failover.js +391 -0
  528. package/template/coding-task-manager/public/m/private-api.js +31 -1
  529. package/template/coding-task-manager/public/m/private-queue-actions.js +26 -7
  530. package/template/coding-task-manager/public/m/sw.js +5 -0
  531. package/template/coding-task-manager/public/usage.html +1 -0
  532. package/template/coding-task-manager/queue-engine.js +13 -0
  533. package/template/coding-task-manager/scripts/dev-route-fixture/synthetic-route-upstream.js +104 -0
  534. package/template/coding-task-manager/scripts/dev-route-fixture.js +339 -0
  535. package/template/coding-task-manager/scripts/opencode-lead-route-probe.js +195 -0
  536. package/template/coding-task-manager/scripts/opencode-v2-contract-probe/fake-anthropic.js +168 -0
  537. package/template/coding-task-manager/scripts/opencode-v2-contract-probe/probe-plugin/server.js +95 -0
  538. package/template/coding-task-manager/scripts/opencode-v2-contract-probe.js +673 -0
  539. package/template/coding-task-manager/server/approvals.js +5 -6
  540. package/template/coding-task-manager/server/boot.js +136 -17
  541. package/template/coding-task-manager/server.js +2819 -11885
  542. package/template/coding-task-manager/session-integrity.js +71 -13
  543. package/template/coding-task-manager/workers/db-owner-worker.js +72 -9
  544. package/template/coding-task-manager/workers/online-backup-worker.js +1 -0
  545. package/template/coding-task-manager/workers/read-pool-model-collector.js +51 -3
  546. package/template/coding-task-manager/workers/read-pool-worker.js +93 -12
  547. package/template/coding-task-manager/workers/session-host-pool-process.js +24 -10
  548. package/template/coding-task-manager/workers/session-host-process.js +19 -8
  549. package/template/coding-task-manager/workers/transcript-archive-worker.js +1 -1
  550. package/template/coding-task-manager/workers/watch-worker.js +105 -0
  551. package/template/coding-task-manager/workers/worktree-worker.js +202 -33
  552. package/template/ctm-relay/lib/protocol.js +14 -1
  553. package/template/package-lock.json +2 -2
  554. package/template/package.json +1 -1
  555. package/template/scripts/conversation-storage-v2-migration.js +78 -11
  556. package/template/shared/backup-retention.js +82 -0
  557. package/template/shared/conversation-admission.js +2 -0
  558. package/template/shared/conversation-provenance.js +3 -7
  559. package/template/shared/conversation-storage-v2-contract.js +47 -6
  560. package/template/shared/fixtures/worker-status-payloads.json +392 -0
  561. package/template/shared/git-remote-key.js +83 -0
  562. package/template/shared/host-identity.js +98 -2
  563. package/template/shared/linked-worktree.js +51 -0
  564. package/template/shared/macos-fda-target.js +57 -0
  565. package/template/shared/orphan-parents.js +55 -0
  566. package/template/shared/owner-write-safety.js +135 -0
  567. package/template/shared/public-runtime.js +13 -5
  568. package/template/shared/release-schema.json +3 -2
  569. package/template/shared/report-citations.js +14 -0
  570. package/template/shared/sqlite-write-lock.js +361 -223
  571. package/template/shared/storage/contract.js +38 -3
  572. package/template/wall-e/adapters/imessage.js +12 -0
  573. package/template/wall-e/agent.js +92 -4
  574. package/template/wall-e/api-walle.js +26 -1
  575. package/template/wall-e/bin/brain-purge-legacy-ctm.js +3 -2
  576. package/template/wall-e/bin/train-gemma-e4b-tooluse.js +2 -2
  577. package/template/wall-e/bin/walle-mcp-stdio.js +14 -8
  578. package/template/wall-e/brain/brain-join.js +859 -0
  579. package/template/wall-e/brain/brain-sync-membership.js +20 -0
  580. package/template/wall-e/brain/brain-sync-store.js +131 -77
  581. package/template/wall-e/brain/brain-sync-v2-schema.js +203 -0
  582. package/template/wall-e/brain/brain-sync-v2.js +578 -0
  583. package/template/wall-e/brain/delegate-model-prefs-store.js +13 -4
  584. package/template/wall-e/brain/deterministic-id.js +51 -0
  585. package/template/wall-e/brain/helper-rules-schema.js +129 -0
  586. package/template/wall-e/brain/memories.js +2 -2
  587. package/template/wall-e/brain/migrations.js +91 -28
  588. package/template/wall-e/brain/model-deployment-facts.js +31 -1
  589. package/template/wall-e/brain/model-identity-migration.js +1 -1
  590. package/template/wall-e/brain/owner-call-whitelist.js +39 -7
  591. package/template/wall-e/brain/schema-ensures.js +22 -0
  592. package/template/wall-e/brain/schema.js +45 -85
  593. package/template/wall-e/brain.js +172 -36
  594. package/template/wall-e/chat.js +3 -3
  595. package/template/wall-e/coding/agent-shell-env.js +7 -2
  596. package/template/wall-e/coding/journal-dispatcher.js +51 -0
  597. package/template/wall-e/coding/prompt-bundle.js +66 -21
  598. package/template/wall-e/coding/session-journal.js +28 -40
  599. package/template/wall-e/coding-orchestrator.js +23 -26
  600. package/template/wall-e/config/main-loop-exemptions.json +2 -2
  601. package/template/wall-e/http/admin-api.js +37 -0
  602. package/template/wall-e/http/auth.js +18 -1
  603. package/template/wall-e/http/blog-views-api.js +318 -0
  604. package/template/wall-e/http/gws-api.js +4 -0
  605. package/template/wall-e/http/helper-rules-api.js +327 -0
  606. package/template/wall-e/http/model-admin.js +8 -1
  607. package/template/wall-e/http/model-delegate-pref-admin.js +3 -3
  608. package/template/wall-e/http/model-proxy-providers.js +177 -2
  609. package/template/wall-e/http/model-route-health.js +157 -0
  610. package/template/wall-e/http/sync-api.js +278 -464
  611. package/template/wall-e/http/telemetry-api.js +12 -0
  612. package/template/wall-e/jobs/job-runner.js +28 -1
  613. package/template/wall-e/lib/blog-view-policy.js +88 -0
  614. package/template/wall-e/lib/blog-view-store.js +169 -0
  615. package/template/wall-e/lib/brain-owner-op-priority.js +9 -1
  616. package/template/wall-e/lib/client-config-lock.js +2 -1
  617. package/template/wall-e/lib/coding-journal-writer-child-client.js +67 -18
  618. package/template/wall-e/lib/ctm-data-dir.js +26 -0
  619. package/template/wall-e/lib/derivation-home.js +147 -0
  620. package/template/wall-e/lib/error-kinds.js +10 -1
  621. package/template/wall-e/lib/feature-manifest.js +1 -1
  622. package/template/wall-e/lib/helper-rules/cell-state.js +123 -0
  623. package/template/wall-e/lib/helper-rules/evaluate.js +398 -0
  624. package/template/wall-e/lib/helper-rules/explore-rubric.md +12 -0
  625. package/template/wall-e/lib/helper-rules/grade.js +320 -0
  626. package/template/wall-e/lib/helper-rules/label.js +247 -0
  627. package/template/wall-e/lib/helper-rules/lead-call-hook.js +555 -0
  628. package/template/wall-e/lib/helper-rules/store.js +669 -0
  629. package/template/wall-e/lib/landing-mcp-tools.js +170 -0
  630. package/template/wall-e/lib/mcp-client-config.js +133 -14
  631. package/template/wall-e/lib/mcp-gateway-migrate.js +28 -64
  632. package/template/wall-e/lib/mcp-integration.js +63 -19
  633. package/template/wall-e/lib/parent-death.js +7 -1
  634. package/template/wall-e/lib/runtime-worker-pool.js +1 -0
  635. package/template/wall-e/lib/scheduler-worker-jobs.js +12 -4
  636. package/template/wall-e/lib/telemetry-db-schema.js +37 -0
  637. package/template/wall-e/lib/telemetry-process-client.js +76 -1
  638. package/template/wall-e/llm/default-fallback.js +4 -0
  639. package/template/wall-e/llm/delegate-lead-prefs.js +16 -1
  640. package/template/wall-e/llm/delegate-vendor-default.js +12 -5
  641. package/template/wall-e/llm/model-catalog.js +13 -4
  642. package/template/wall-e/llm/model-roles.js +7 -1
  643. package/template/wall-e/llm/native-delegate-selection.js +56 -8
  644. package/template/wall-e/llm/portkey-http.js +150 -0
  645. package/template/wall-e/llm/portkey-sync.js +15 -145
  646. package/template/wall-e/llm/worker-delegate-args.js +72 -7
  647. package/template/wall-e/llm/worker-mcp-routing.js +117 -7
  648. package/template/wall-e/llm/worker-route.js +43 -1
  649. package/template/wall-e/loops/brain-custom-writes.js +64 -0
  650. package/template/wall-e/loops/ingest.js +17 -1
  651. package/template/wall-e/loops/think.js +19 -4
  652. package/template/wall-e/mcp-contract.js +222 -6
  653. package/template/wall-e/mcp-protocol-contract.js +77 -2
  654. package/template/wall-e/mcp-server.js +141 -31
  655. package/template/wall-e/mcp-worker-schemas.js +25 -7
  656. package/template/wall-e/memory/ctm-context-client.js +110 -5
  657. package/template/wall-e/memory/ctm-session-context.js +9 -3
  658. package/template/wall-e/memory/hub-bridge-client.js +388 -0
  659. package/template/wall-e/memory/replica-origin.js +56 -0
  660. package/template/wall-e/memory/session-pool.js +135 -0
  661. package/template/wall-e/runtime/live-capabilities.js +8 -3
  662. package/template/wall-e/server.js +4 -2
  663. package/template/wall-e/shared/release-schema.json +3 -2
  664. package/template/wall-e/shared/sqlite-file-set.js +39 -0
  665. package/template/wall-e/shared/sqlite-write-lock.js +361 -223
  666. package/template/wall-e/shared/storage/contract.js +38 -3
  667. package/template/wall-e/skills/_templates/delegate-worker/VERSION +1 -1
  668. package/template/wall-e/skills/_templates/delegate-worker/released-sha256.json +13 -1
  669. package/template/wall-e/skills/_templates/delegate-worker/templates/claude/SKILL.md +11 -6
  670. package/template/wall-e/skills/_templates/delegate-worker/templates/codex/SKILL.md +13 -8
  671. package/template/wall-e/skills/_templates/fleet-sync/VERSION +1 -0
  672. package/template/wall-e/skills/_templates/fleet-sync/released-sha256.json +16 -0
  673. package/template/wall-e/skills/_templates/fleet-sync/templates/claude/SKILL.md +64 -0
  674. package/template/wall-e/skills/_templates/fleet-sync/templates/codex/SKILL.md +64 -0
  675. package/template/wall-e/tools/chrome-automation.js +6 -0
  676. package/template/wall-e/tools/local-tools.js +6 -4
  677. package/template/wall-e/training/setup-cuda-train-env.sh +2 -2
  678. package/template/wall-e/workers/brain-owner-worker.js +27 -4
  679. package/template/wall-e/workers/coding-journal-writer-child.js +8 -1
  680. package/template/wall-e/workers/mcp-gateway-process.js +5 -5
  681. package/template/wall-e/workers/telemetry-worker.js +8 -0
@@ -4,24 +4,35 @@
4
4
  // shape, keyed PER CLIENT (a "delivery" = sessionId + clientId + socketGeneration) instead of
5
5
  // per-session, because CTM (unlike 0.9.33) fans one session out to more than one viewer.
6
6
  //
7
+ // WP-1 (docs/state-sync-pipelined-deltas-echo-never-waits-for-ack-2026-10-31.html §5 D-1..D-5):
8
+ // the single in-flight slot is replaced IN PLACE by a BOUNDED WINDOW of unacked frames per delivery
9
+ // (Mosh's rule: diff each frame against the last state SENT, and let an ack advance only what is
10
+ // assumed received). No flag: the window is the only code path.
11
+ //
7
12
  // The whole state machine, per delivery:
8
- // mirror updated -> in flight? dirty=true, refuse
9
- // -> else rate gate refuse('rate')
10
- // -> owedKeyframe/dims changed -> keyframe (else diff vs ackedGrid)
13
+ // mirror updated -> window full (≥8 frames or ≥256 KiB)? dirty=true, refuse('window-full')
14
+ // -> else rate gate refuse('rate')
15
+ // -> owedKeyframe/dims changed -> keyframe (else diff vs sentGrid)
11
16
  // -> nothing changed (rows+cursor) -> nothing
12
- // ack(seq) -> seq === inFlightSeq -> advance base, retire acked scrollback, clear in
13
- // flight, flush one dirty catch-up (bypass rate). Any other seq -> ignore.
14
- // NO proofs, NO dispositions, NO suppression.
15
- // keyframe req -> ALWAYS served for a known delivery (reset base, clear in flight, force).
16
- // Unknown delivery -> attach it, then serve. Never refused.
17
- // undeliverable -> clear in flight; a dropped KEYFRAME owes one (owedKeyframe=true); a
18
- // dropped delta is simply dirty (next emit diffs losslessly against ackedGrid).
19
- // sweep -> in flight past stallMs -> clear in flight, force a keyframe. Nothing else.
17
+ // ack(seq) -> an entry SEQUENCE === seq is in the window -> retire every entry with
18
+ // seq ≤ seq in order (advance ackedSeq/ackedGridRevision/ackedGrid to that
19
+ // entry, retire its scroll-out counts, sample RTT from THAT entry only,
20
+ // never a resent one), then flush one dirty catch-up (bypass rate).
21
+ // Any other seq -> ignore. NO proofs, NO dispositions, NO suppression.
22
+ // keyframe req -> ALWAYS served for a known delivery (reset base, clear window, force) UNLESS
23
+ // a KEYFRAME already in the window is newer than the client's haveSeq (WP-2
24
+ // D-6: that keyframe IS the answer). Unknown delivery -> attach, then serve.
25
+ // Never refused.
26
+ // undeliverable -> the named seq is in the window: drop every entry with seq ≥ it, keep the
27
+ // rest (they still reach the client, in order), owe ONE keyframe whose
28
+ // scroll-out base is the newest kept grid (rows the client already has are not
29
+ // re-donated). A seq not in the window is a no-op. Do not emit here.
30
+ // sweep -> the OLDEST entry past stallMs -> clear the window, force a keyframe. Nothing else.
20
31
  // attach/detach -> create/delete the delivery. Nothing else remembers a client.
21
32
  //
22
33
  // No suppression latch, no no-audience stand-down, no nack-episode/content-fence bookkeeping, no
23
34
  // client-fault squelch, no interactive-supersession lane, no revision-store eviction/fencing. A
24
- // delivery either has a frame in flight or it doesn't; a keyframe either fixes it or the sweep does.
35
+ // delivery has a bounded window of unacked frames; a keyframe either fixes it or the sweep does.
25
36
 
26
37
  const { computeAnsiPatch } = require('./cell-diff'); const { stripWrapPrefix } = require('./row-serializer');const { paintedFrameField } = require('./painted-frame-field');
27
38
  const { frameDue, noteEmit } = require('./frame-rate');
@@ -31,6 +42,12 @@ const { normalizeMouseTracking, normalizeMouseEncoding } = require('./surface-mo
31
42
  const EMPTY_GRID = { cols: 0, rows: 0, rowAnsi: [] };
32
43
  const DEFAULT_SCROLL_OUT_MAX = 400;
33
44
  const DEFAULT_MAX_ACTIVE_CLIENTS = 32;
45
+ // WP-1 (§5 D-2, §6): the per-delivery unacked window. Module constants, never env flags -- the
46
+ // rollback is branch isolation + git revert. Frames are 2–19 KB measured, so 8 frames ≈ 152 KB <
47
+ // 256 KiB < the 1 MiB stream high-water; at the 16 ms frame floor 8 frames = 128 ms of output ahead
48
+ // of the oldest ack. Overridable ONLY by the test injection (deps.windowFrames / deps.windowBytes).
49
+ const STATE_SYNC_WINDOW_FRAMES = 8;
50
+ const STATE_SYNC_WINDOW_BYTES = 262144;
34
51
 
35
52
  function parseScrollOutMax(value) {
36
53
  if (value === null || value === undefined || value === '') return DEFAULT_SCROLL_OUT_MAX;
@@ -173,10 +190,18 @@ function newDeliveryState() {
173
190
  ackedGrid: EMPTY_GRID,
174
191
  ackedSeq: 0,
175
192
  ackedGridRevision: 0,
193
+ // WP-1 (§5 D-1/D-2): the unacked window, ordered oldest→newest, and the last state SENT (the
194
+ // assumed receiver state a fresh delta diffs against). inFlightSeq/inFlightKind/inFlightAt are
195
+ // DERIVED from the OLDEST entry by syncOldest() and kept for readers/tests.
196
+ inFlight: [],
197
+ inFlightBytes: 0,
176
198
  inFlightSeq: 0,
177
- inFlightGrid: null,
178
199
  inFlightAt: 0,
179
200
  inFlightKind: '', // report-only, for onRefused's gate name
201
+ sentGrid: EMPTY_GRID,
202
+ sentSeq: 0,
203
+ sentGridRevision: 0,
204
+ resetBaseGrid: null, // D-5: the scroll-out base for the keyframe after a mid-window drop
180
205
  dirty: false,
181
206
  owedKeyframe: false,
182
207
  fr: { lastEmitAt: 0 },
@@ -186,12 +211,17 @@ function newDeliveryState() {
186
211
  lastAckClientId: '',
187
212
  pendingScrollbackRows: [],
188
213
  pendingScrollbackElidedCount: 0,
189
- inFlightScrollbackRowCount: 0, // retire-on-ack: how much of the queue THIS in-flight frame carried
190
- inFlightScrollbackElidedCount: 0,
191
- pendingClearScrollback: false, // a clearScrollback request coalesced behind an in-flight frame
214
+ pendingClearScrollback: false, // a clearScrollback request coalesced behind a full window
192
215
  surfaceEpoch: 0,
193
216
  surfaceIdentity: null,
194
217
  sweepResends: 0, // how many times sweepStalledInFlight has re-emitted into this delivery since its last ack
218
+ // WP-2 (§5 D-5, docs/remote-relay-ack-rate-limit-typing-delay-2026-10-28.html): this delivery's
219
+ // own measured ack RTT (RFC 6298 §2 SRTT/RTTVAR), so the lost-ack watchdog is sized from the
220
+ // real round trip instead of one global 3 s constant. Per DELIVERY, so a slow viewer's history
221
+ // never inflates a fast viewer's stall.
222
+ srttMs: 0,
223
+ rttvarMs: 0,
224
+ rttSamples: 0,
195
225
  };
196
226
  }
197
227
 
@@ -199,17 +229,92 @@ function deliveryKey(clientId, socketGeneration) {
199
229
  return JSON.stringify([String(clientId || ''), Number(socketGeneration || 0)]);
200
230
  }
201
231
 
232
+ // WP-1 (§5 D-1, §6): the ONE place the derived oldest-entry fields are maintained. Called after
233
+ // every window change (push, retire, clear) so inFlightSeq/inFlightKind/inFlightAt always name the
234
+ // OLDEST unacked entry (0/''/0 when the window is empty), which is what the sweep and the
235
+ // diagnostics read.
236
+ function syncOldest(s) {
237
+ const oldest = s.inFlight[0];
238
+ s.inFlightSeq = oldest ? oldest.seq : 0;
239
+ s.inFlightKind = oldest ? oldest.kind : '';
240
+ s.inFlightAt = oldest ? oldest.at : 0;
241
+ }
242
+
243
+ // WP-0 (D-4c): hand one lost-ack recovery to the caller's report-only hook. The recovery has
244
+ // ALREADY happened by the time this runs, so a throwing hook is swallowed rather than allowed to
245
+ // abort the sweep mid-loop.
246
+ function _noteRecovered(opts, id, info) {
247
+ try {
248
+ if (opts && typeof opts.onRecovered === 'function') opts.onRecovered(id, info);
249
+ } catch {
250
+ // expected: diagnostics hook fault never breaks recovery
251
+ }
252
+ }
253
+
254
+ // WP-0 (D-5, docs/state-sync-pipelined-deltas-echo-never-waits-for-ack-2026-10-31.html §5 D-5,
255
+ // §9 S-11): hand ONE matched ack's round trip to the caller's report-only hook, while both legs are
256
+ // still knowable — the host leg is measured here (send -> ack), the main leg is passed through from
257
+ // the worker (`ctx.mainRttMs`, the ledger's own sentAt delta). Diagnostics only: the ack has already
258
+ // been applied by the time this runs, so a throwing hook is swallowed rather than allowed to abort
259
+ // the delivery's ack path.
260
+ function _noteAcked(deps, id, info) {
261
+ try {
262
+ if (deps && typeof deps.onAcked === 'function') deps.onAcked(id, info);
263
+ } catch {
264
+ /* expected: report-only diagnostics hook must never break the ack path */
265
+ }
266
+ }
267
+
268
+ // WP-2 (RFC 6298 §2, docs/remote-relay-ack-rate-limit-typing-delay-2026-10-28.html §5 D-5, §6):
269
+ // fold one measured ack RTT into the delivery's SRTT/RTTVAR. The first sample seeds SRTT = R and
270
+ // RTTVAR = R/2; every later sample uses RTTVAR = 3/4·RTTVAR + 1/4·|SRTT − R| then
271
+ // SRTT = 7/8·SRTT + 1/8·R. A non-finite or negative sample (clock skew, a stale inFlightAt) is
272
+ // dropped rather than allowed to poison the estimate.
273
+ function noteAckRtt(state, sampleMs) {
274
+ if (!state) return;
275
+ const r = Number(sampleMs);
276
+ if (!Number.isFinite(r) || r < 0) return;
277
+ if (!Number(state.rttSamples)) {
278
+ state.srttMs = r;
279
+ state.rttvarMs = r / 2;
280
+ } else {
281
+ const srtt = Number(state.srttMs) || 0;
282
+ state.rttvarMs = 0.75 * (Number(state.rttvarMs) || 0) + 0.25 * Math.abs(srtt - r);
283
+ state.srttMs = 0.875 * srtt + 0.125 * r;
284
+ }
285
+ state.rttSamples = Number(state.rttSamples || 0) + 1;
286
+ }
287
+
288
+ // A delivery with no ack sample yet keeps the caller's CEILING (today's fixed 3 s), so the very
289
+ // first attach can never be spuriously recovered. Once sampled, the stall is clamp(SRTT + 4·RTTVAR)
290
+ // bounded below by the private-path floor (mosh's MIN_RTO intuition, §5 P3) and above by the same
291
+ // ceiling (the CTM_STATE_SYNC_INFLIGHT_STALL_MS override).
292
+ function stallMsFor(state, opts) {
293
+ const ceilingMs = Number(opts && opts.ceilingMs);
294
+ const ceiling = Number.isFinite(ceilingMs) ? ceilingMs : 0;
295
+ const rawFloor = Number(opts && opts.floorMs);
296
+ const floor = Number.isFinite(rawFloor) ? rawFloor : 250;
297
+ if (!state || !Number(state.rttSamples)) return ceiling;
298
+ const rto = (Number(state.srttMs) || 0) + 4 * (Number(state.rttvarMs) || 0);
299
+ return Math.min(ceiling, Math.max(floor, rto));
300
+ }
301
+
202
302
  function createFrameEmitter(deps) {
203
303
  deps = deps || {};
204
304
  const send = deps.send || (() => {});
205
305
  // WP-0b (§5 D-2, §6): report-only hook so a caller can attribute a refused emit to its exact
206
- // gate. WP-2 reduces the enum to the two gates that still exist: in-flight-delta |
207
- // in-flight-keyframe | rate (see lib/typing-interaction-trace.js GATES).
306
+ // gate. WP-1 reduces the enum to the two gates that still exist: window-full | rate (see
307
+ // lib/typing-interaction-trace.js GATES; the old in-flight-* names are kept there so pre-WP-1
308
+ // rows still parse).
208
309
  const onRefused = deps.onRefused || (() => {});
209
310
  const log = deps.log || (() => {});
210
311
  const extractGrid = deps.extractGrid || (() => EMPTY_GRID);
211
312
  const now = deps.now || (() => Date.now());
212
313
  const frameOpts = deps.frameOpts || {};
314
+ // §5 D-2/D-8: the window bounds are module constants, overridable ONLY by the test injection --
315
+ // never an env flag.
316
+ const windowFrames = Math.max(1, Number(deps.windowFrames) || STATE_SYNC_WINDOW_FRAMES);
317
+ const windowBytes = Math.max(1, Number(deps.windowBytes) || STATE_SYNC_WINDOW_BYTES);
213
318
  const scrollOutMax = parseScrollOutMax(
214
319
  deps.scrollOutMax ?? frameOpts.scrollOutMax ?? process.env.CTM_STATE_SYNC_SCROLL_OUT_MAX
215
320
  );
@@ -277,36 +382,49 @@ function createFrameEmitter(deps) {
277
382
  return { rows, elided };
278
383
  }
279
384
 
280
- // The one send path. Assumes the caller has already decided this delivery may emit right now
281
- // (nothing in flight). Gate 2 budget: ≤60 lines / 8 ifs / 6 returns.
385
+ // The one send path. Gate 2 budget: ≤72 lines / 8 ifs / 6 returns.
282
386
  function emit(id, delivery, opts = {}) {
283
387
  const session = st(id);
284
388
  const s = delivery.state;
285
389
  const t = now();
286
390
  const grid = extractGrid(id) || EMPTY_GRID;
287
- const ackedGrid = s.ackedGrid || EMPTY_GRID;
288
391
  const identityChanged = surfaceIdentityChanged(s, grid);
289
- const keyframeFrame = !!opts.force || !!s.owedKeyframe || identityChanged || Number(s.ackedSeq || 0) === 0;
290
- const cursorMoved = !cursorsEqual(grid.cursor, ackedGrid.cursor);
291
- const hasPendingScrollback = s.pendingScrollbackRows.length > 0 || s.pendingScrollbackElidedCount > 0;
292
- if (!keyframeFrame && !cursorMoved && !opts.clearScrollback && !hasPendingScrollback && gridsEqual(grid, ackedGrid)) {
392
+ // §5 D-1: a delta diffs against the last state SENT (the assumed receiver state), not the last
393
+ // acked one -- with a window, several frames can be unacked and each must build on its
394
+ // predecessor. The first frame of a delivery (or after any reset) is still a keyframe: the
395
+ // keyframe rule keys on sentSeq === 0, never ackedSeq (which stays 0 until the first ack, so
396
+ // every emit before it would otherwise be a keyframe).
397
+ const keyframeFrame = !!opts.force || !!s.owedKeyframe || identityChanged || Number(s.sentSeq || 0) === 0;
398
+ // §5 D-5: after a mid-window drop the next keyframe re-donates scroll-out rows against the
399
+ // newest KEPT entry's grid (the client already has those rows), then the override is consumed.
400
+ const baseGrid = keyframeFrame
401
+ ? (s.resetBaseGrid || s.ackedGrid || EMPTY_GRID)
402
+ : (s.sentGrid || EMPTY_GRID);
403
+ if (keyframeFrame) s.resetBaseGrid = null;
404
+ const cursorMoved = !cursorsEqual(grid.cursor, baseGrid.cursor);
405
+ // No pending-scrollback term: a refused update leaves nothing owed, because the next emit
406
+ // recomputes its scroll-out rows against sentGrid (and a drop forces a keyframe, D-5).
407
+ if (!keyframeFrame && !cursorMoved && !opts.clearScrollback && gridsEqual(grid, baseGrid)) {
293
408
  return false;
294
409
  }
295
- // A keyframe still diffs its scroll-out recovery against the delivery's own last-known
296
- // ackedGrid (a WIRE reset declares baseSeq 0, but internally the diff base is only actually
297
- // discarded by resetDeliveryBaseline -- a snapshot/restore reset, where ackedGrid is already
298
- // EMPTY_GRID here and scrollOutRecovery is naturally a no-op). This is "lossless by
299
- // construction" (R-2): a dropped/coalesced frame never advances ackedGrid, so the NEXT
300
- // successful emit recomputes the SAME recovery fresh against the unchanged base -- there is no
301
- // separate multi-frame queue to lose track of or retire.
302
- const recovery = scrollOutRecovery(id, ackedGrid, grid);
410
+ // Each frame carries exactly the scroll-out rows between ITS base and its grid. For a delta that
411
+ // is the predecessor frame's grid; for a keyframe it is the delivery's own last-known grid (a
412
+ // WIRE reset declares baseSeq 0, but the internal diff base is only discarded by
413
+ // resetDeliveryBaseline -- a snapshot/restore reset, where ackedGrid is already EMPTY_GRID here
414
+ // and scrollOutRecovery is naturally a no-op) or the kept base a drop left behind (D-5).
415
+ const recovery = scrollOutRecovery(id, baseGrid, grid);
416
+ const batch = recovery.delta > 0 ? scrollbackBatch(baseGrid, recovery.delta, recovery.rows, recovery.elided) : { rows: [], elided: 0 };
417
+ // The frame's (and its window entry's) scroll-out counts are THIS frame's batch only -- a later
418
+ // frame must never re-advertise rows/elision an earlier unacked frame carried (the client draws
419
+ // one elision marker per frame that reports scrollbackElidedCount > 0). pendingScrollback* is
420
+ // the queue of rows carried by the unacked frames; onAck retires each entry's share in order.
303
421
  if (keyframeFrame || opts.clearScrollback) { s.pendingScrollbackRows = []; s.pendingScrollbackElidedCount = 0; }
304
- const batch = recovery.delta > 0 ? scrollbackBatch(ackedGrid, recovery.delta, recovery.rows, recovery.elided) : { rows: [], elided: 0 };
305
- if (recovery.delta > 0) { s.pendingScrollbackRows = batch.rows; s.pendingScrollbackElidedCount = batch.elided; }
306
- const pendingRowCount = s.pendingScrollbackRows.length;
307
- const pendingElidedCount = s.pendingScrollbackElidedCount;
422
+ s.pendingScrollbackRows = s.pendingScrollbackRows.concat(batch.rows);
423
+ s.pendingScrollbackElidedCount += batch.elided;
424
+ const pendingRowCount = batch.rows.length;
425
+ const pendingElidedCount = batch.elided;
308
426
  const scrollbackDelta = recovery.delta;
309
- let patch = computeAnsiPatch(ackedGrid, grid, {
427
+ let patch = computeAnsiPatch(baseGrid, grid, {
310
428
  scrolledOutRows: batch.rows, scrolledOutElidedCount: batch.elided,
311
429
  clearScrollback: opts.clearScrollback, keyframe: keyframeFrame,
312
430
  });
@@ -323,7 +441,7 @@ function createFrameEmitter(deps) {
323
441
  if (cursorMoved && !keyframeFrame) {
324
442
  const cursorRows = new Set(Array.isArray(patch.changedRows) ? patch.changedRows : []);
325
443
  const gridRows = Number(grid.rows) || 0;
326
- for (const row of [Number(ackedGrid.cursor?.row || 0), Number(grid.cursor?.row || 0)]) {
444
+ for (const row of [Number(baseGrid.cursor?.row || 0), Number(grid.cursor?.row || 0)]) {
327
445
  if (row > 0 && row <= gridRows) cursorRows.add(row);
328
446
  }
329
447
  patch = { ...patch, changedRows: Array.from(cursorRows).sort((a, b) => a - b) };
@@ -331,14 +449,14 @@ function createFrameEmitter(deps) {
331
449
  }
332
450
  const authority = frameAuthority(s, grid, patch, keyframeFrame, identityChanged);
333
451
  const frame = {
334
- type: 'frame', id, seq, gridRevision: seq, baseGridRevision: keyframeFrame ? 0 : Number(s.ackedGridRevision || 0),
452
+ type: 'frame', id, seq, gridRevision: seq, baseGridRevision: keyframeFrame ? 0 : Number(s.sentGridRevision || 0),
335
453
  ...authority,
336
454
  keyframe: keyframeFrame, displayStable: keyframeFrame,
337
- ...paintedFrameField(deps, id, keyframeFrame, ackedGrid, grid), // D-6: the reader's painted-row position (and the rows this viewer lacks)
455
+ ...paintedFrameField(deps, id, keyframeFrame, baseGrid, grid), // D-6: the reader's painted-row position (and the rows this viewer lacks)
338
456
  scrollbackDelta,
339
457
  ...(pendingRowCount > 0 ? { scrollbackRowCount: pendingRowCount } : {}),
340
458
  ...(pendingElidedCount > 0 ? { scrollbackElidedCount: pendingElidedCount } : {}),
341
- baseSeq: keyframeFrame ? 0 : s.ackedSeq,
459
+ baseSeq: keyframeFrame ? 0 : Number(s.sentSeq || 0),
342
460
  ansiPatch: patch.ansi,
343
461
  cursor: grid.cursor || null,
344
462
  rows: Number(grid.rows) || 0,
@@ -352,12 +470,19 @@ function createFrameEmitter(deps) {
352
470
  ...(opts.requestToken ? { requestToken: String(opts.requestToken) } : {}),
353
471
  };
354
472
  send(id, frame);
355
- s.inFlightSeq = seq;
356
- s.inFlightScrollbackRowCount = pendingRowCount;
357
- s.inFlightScrollbackElidedCount = pendingElidedCount;
358
- s.inFlightKind = keyframeFrame ? 'keyframe' : 'delta';
359
- s.inFlightGrid = grid;
360
- s.inFlightAt = t;
473
+ // §5 D-2/D-3: the entry is the retire-on-ack record -- its byte cost bounds the window, and its
474
+ // scroll-out counts are retired when (and only when) this seq is acked.
475
+ const bytes = Buffer.byteLength(String(patch.ansi || ''), 'utf8');
476
+ s.inFlight.push({
477
+ seq, at: t, kind: keyframeFrame ? 'keyframe' : 'delta', grid, bytes,
478
+ scrollbackRowCount: pendingRowCount,
479
+ scrollbackElidedCount: pendingElidedCount,
480
+ });
481
+ s.inFlightBytes += bytes;
482
+ s.sentGrid = grid;
483
+ s.sentSeq = seq;
484
+ s.sentGridRevision = seq;
485
+ syncOldest(s);
361
486
  return true;
362
487
  }
363
488
 
@@ -371,19 +496,25 @@ function createFrameEmitter(deps) {
371
496
  state.ackedGrid = EMPTY_GRID;
372
497
  state.ackedSeq = 0;
373
498
  state.ackedGridRevision = 0;
499
+ // §5 D-5: the SENT baseline is gone too -- the next emit is a keyframe (sentSeq 0 still fails
500
+ // the keyframe rule) and must not diff against a state the client never had.
501
+ state.sentGrid = EMPTY_GRID;
502
+ state.sentSeq = 0;
503
+ state.sentGridRevision = 0;
504
+ state.resetBaseGrid = null;
374
505
  }
375
506
 
376
507
  // A keyframe-req / lost-ack recovery is a WIRE reset (frame.baseSeq/baseGridRevision go to 0 --
377
- // the client repaints everything) but internally keeps the delivery's own last-known ackedGrid as
378
- // the scroll-out diff base, exactly like the sweep's lost-ack recovery always has -- otherwise a
379
- // desync resync would silently drop whatever scrolled out of view since the last ack.
508
+ // the client repaints everything) but internally keeps the delivery's own last-known grid as the
509
+ // scroll-out diff base, exactly like the sweep's lost-ack recovery always has -- otherwise a
510
+ // desync resync would silently drop whatever scrolled out of view since the last ack. WP-1 (§5
511
+ // D-2): "clear in flight" now means EMPTY THE WHOLE WINDOW.
380
512
  function clearInFlightOnly(state) {
381
- state.inFlightSeq = 0;
382
- state.inFlightGrid = null;
383
- state.inFlightScrollbackRowCount = 0;
384
- state.inFlightScrollbackElidedCount = 0;
513
+ state.inFlight = [];
514
+ state.inFlightBytes = 0;
385
515
  state.pendingClearScrollback = false;
386
516
  state.dirty = false;
517
+ syncOldest(state);
387
518
  }
388
519
 
389
520
  // The clientId-less keyframe entry point (resize / set-visibility / restore-hold release / a
@@ -432,17 +563,22 @@ function createFrameEmitter(deps) {
432
563
  let sent = false;
433
564
  forEachDelivery(id, (delivery) => {
434
565
  const s = delivery.state;
435
- if (s.inFlightSeq) {
566
+ // §5 D-2: refuse ONLY when the window is full -- one frame in flight no longer holds a
567
+ // newer echo back. The bound is frames OR bytes; nothing else refuses.
568
+ if (s.inFlight.length >= windowFrames || s.inFlightBytes >= windowBytes) {
436
569
  s.dirty = true;
437
570
  if (ctx.clearScrollback) s.pendingClearScrollback = true;
438
- onRefused(id, s.inFlightKind === 'keyframe' ? 'in-flight-keyframe' : 'in-flight-delta', {
439
- inFlightSeq: s.inFlightSeq, inFlightKind: s.inFlightKind,
440
- inFlightAgeMs: Math.max(0, now() - Number(s.inFlightAt || now())),
571
+ onRefused(id, 'window-full', {
572
+ inFlightCount: s.inFlight.length, inFlightBytes: s.inFlightBytes,
573
+ oldestSeq: s.inFlightSeq, oldestKind: s.inFlightKind,
574
+ oldestAgeMs: Math.max(0, now() - Number(s.inFlightAt || now())),
441
575
  });
442
576
  return;
443
577
  }
444
578
  const t = now();
445
- const forced = !!s.owedKeyframe || Number(s.ackedSeq || 0) === 0;
579
+ // §5 D-1: "the first frame of this delivery" is sentSeq === 0, not ackedSeq === 0 -- with a
580
+ // window, every emit before the first ack would otherwise be a forced keyframe.
581
+ const forced = !!s.owedKeyframe || Number(s.sentSeq || 0) === 0;
446
582
  if (!forced && !ctx.bypassRate && !frameDue(s.fr, t, { ...frameOpts, flooding: s.flooding })) {
447
583
  onRefused(id, 'rate', {});
448
584
  return;
@@ -458,43 +594,66 @@ function createFrameEmitter(deps) {
458
594
  return sent;
459
595
  },
460
596
 
461
- // seq === inFlightSeq -> advance the diff base, flush one dirty catch-up. Any other seq is
462
- // ignored: no proofs, no dispositions, no suppression. Gate 2 budget: ≤20 lines / 3 ifs / 3 returns.
597
+ // §5 D-3: a CUMULATIVE ack -- retire every in-flight entry with seq ≤ n in order, advance the
598
+ // committed base to entry n, flush one dirty catch-up. A seq with no matching entry is ignored:
599
+ // no proofs, no dispositions, no suppression. Gate 2 budget: ≤32 lines / 3 ifs / 3 returns.
463
600
  onAck(id, seq, ctx) {
464
601
  const session = st(id);
465
602
  const n = Number(seq || 0);
466
603
  const clientKey = deliveryKey(ctx && ctx.clientId, ctx && ctx.socketGeneration);
467
604
  const delivery = ctx && ctx.clientId ? session.clients.get(clientKey) : null;
468
- if (!n || !delivery || n !== delivery.state.inFlightSeq) return false;
605
+ if (!n || !delivery) return false;
469
606
  const s = delivery.state;
607
+ const entry = s.inFlight.find((e) => e.seq === n);
608
+ if (!entry) return false; // stale/reordered/unknown seq: touch nothing
609
+ // WP-0 (D-5, §9 S-11): report this ack's two round-trip legs BEFORE the window is retired --
610
+ // `entry.at` names the send time of the seq just matched.
611
+ _noteAcked(deps, id, {
612
+ seq: n,
613
+ clientId: String((ctx && ctx.clientId) || ''),
614
+ socketGeneration: Number((ctx && ctx.socketGeneration) || 0),
615
+ hostRttMs: Math.max(0, now() - Number(entry.at || now())),
616
+ mainRttMs: (ctx && ctx.mainRttMs) ?? -1,
617
+ windowFrames: STATE_SYNC_WINDOW_FRAMES,
618
+ });
619
+ // WP-2 (D-5, P4/Karn): sample the RTT of EXACTLY the entry named. A sweep re-emit mints a NEW
620
+ // seq, so its ack is unambiguous and samples; a late ack for a swept seq matches no entry.
621
+ noteAckRtt(s, now() - Number(entry.at || now()));
622
+ // Retire every entry at or below n, in order: exactly the scroll-out rows/elision each of
623
+ // those frames carried are now represented in the client's own scrollback -- never more.
624
+ for (const retired of s.inFlight) {
625
+ if (retired.seq > n) break;
626
+ if (retired.scrollbackRowCount > 0) s.pendingScrollbackRows.splice(0, retired.scrollbackRowCount);
627
+ if (retired.scrollbackElidedCount > 0) {
628
+ s.pendingScrollbackElidedCount = Math.max(0, s.pendingScrollbackElidedCount - retired.scrollbackElidedCount);
629
+ }
630
+ s.inFlightBytes = Math.max(0, s.inFlightBytes - Number(retired.bytes || 0));
631
+ }
632
+ s.inFlight = s.inFlight.filter((e) => e.seq > n);
470
633
  s.ackedSeq = n;
471
634
  s.ackedGridRevision = n; // this module's own convention: gridRevision === the seq that minted it
472
- s.ackedGrid = s.inFlightGrid || s.ackedGrid || EMPTY_GRID;
473
- s.inFlightSeq = 0;
474
- s.inFlightGrid = null;
475
- // Retire-on-ack: exactly the scroll-out rows/elision THIS frame carried are now represented
476
- // in the client's own scrollback -- never more (a later drop must not re-donate them).
477
- if (s.inFlightScrollbackRowCount > 0) s.pendingScrollbackRows.splice(0, s.inFlightScrollbackRowCount);
478
- if (s.inFlightScrollbackElidedCount > 0) {
479
- s.pendingScrollbackElidedCount = Math.max(0, s.pendingScrollbackElidedCount - s.inFlightScrollbackElidedCount);
480
- }
481
- s.inFlightScrollbackRowCount = 0;
482
- s.inFlightScrollbackElidedCount = 0;
635
+ s.ackedGrid = entry.grid || s.ackedGrid || EMPTY_GRID;
483
636
  s.sweepResends = 0;
484
637
  s.lastAckAt = now();
485
638
  s.lastAckClientId = String(ctx.clientId || '');
639
+ syncOldest(s);
486
640
  // holdCatchUp is pacing, not refusal: the caller is mid synchronized-output block and its
487
641
  // own held-emit retry calls onMirrorUpdated when the block closes; dirty stays set.
488
642
  if (!s.dirty || ctx.holdCatchUp) return false;
643
+ if (s.inFlight.length >= windowFrames || s.inFlightBytes >= windowBytes) return false;
489
644
  s.dirty = false;
490
645
  const clearScrollback = s.pendingClearScrollback;
491
646
  s.pendingClearScrollback = false;
492
- return emit(id, delivery, { bypassRate: true, clearScrollback });
647
+ return emit(id, delivery, { bypassRate: true, clearScrollback, echoedThroughSeq: Number(session.latestEchoedThroughSeq || 0) });
493
648
  },
494
649
 
495
650
  // ALWAYS served for a known delivery. An unknown delivery is attached (subject to the same
496
- // capacity cap any other attach honors), then served -- never refused. Gate 2 budget: ≤20
497
- // lines / 2 ifs / 2 returns.
651
+ // capacity cap any other attach honors), then served -- never refused. WP-2 (D-6): a request
652
+ // naming the client's own baseline seq is a NO-OP when this delivery already has a KEYFRAME in
653
+ // flight whose seq is ABOVE that baseline -- that keyframe IS the answer, so forcing another
654
+ // would double-send. Any other shape (no haveSeq, a delta in flight, an older-or-equal
655
+ // baseline, an unknown delivery) is served exactly as before. Gate 2 budget: ≤20 lines /
656
+ // 3 ifs / 3 returns.
498
657
  onKeyframeReq(id, ctx) {
499
658
  ctx = ctx || {};
500
659
  if (!ctx.clientId) return keyframeAllDeliveries(id, ctx);
@@ -509,8 +668,13 @@ function createFrameEmitter(deps) {
509
668
  // double-send. A blank cold attach ships nothing, so fall through and force one below.
510
669
  // A worker bootstrap reservation for this client (reserveBootstrap) attaches without a
511
670
  // delivery -- the bootstrap's base IS its first keyframe; nothing to force here.
512
- if (!delivery || delivery.state.inFlightSeq) return true;
671
+ if (!delivery || delivery.state.inFlight.length > 0) return true;
513
672
  }
673
+ // §5 D-6: a KEYFRAME anywhere in the window whose seq is above the client's baseline already
674
+ // answers this request (the client will apply it and move its baseline), so re-serving would
675
+ // double-send. Any other shape (no haveSeq, deltas only, an older-or-equal baseline) is served.
676
+ if (Number.isSafeInteger(ctx.haveSeq) && ctx.haveSeq >= 0
677
+ && delivery.state.inFlight.some((e) => e.kind === 'keyframe' && Number(e.seq) > ctx.haveSeq)) return true;
514
678
  clearInFlightOnly(delivery.state);
515
679
  return emit(id, delivery, {
516
680
  force: true, requestToken: ctx.requestToken,
@@ -541,33 +705,59 @@ function createFrameEmitter(deps) {
541
705
  if (!delivery) return false;
542
706
  resetDeliveryBaseline(delivery.state);
543
707
  if (ctx.deferIfBlank && gridIsBlankAtHome(extractGrid(id) || EMPTY_GRID)) return false;
544
- return emit(id, delivery, { force: true });
708
+ return emit(id, delivery, { force: true, echoedThroughSeq: Number(session.latestEchoedThroughSeq || 0) });
545
709
  },
546
710
 
547
- // Lost-ack watchdog: a frame in flight past stallMs is treated as lost. Clear the in-flight
548
- // slot (does NOT advance ackedGrid -- the apply was never confirmed) and force a fresh
549
- // keyframe of the LATEST grid. A session with no viewers (opts.hasViewers false) is not a lost
550
- // frame: nothing is re-sent to it (primary 2026-09-28: 581 resends to a hidden tab); the slot is
551
- // cleared with a keyframe owed, and regaining a viewer forces it. Gate 2 budget: ≤20 lines / 4 ifs / 2 returns.
711
+ // Lost-ack watchdog (§5 D-5b): the OLDEST unacked entry past its stall is treated as lost.
712
+ // Clear the WHOLE window (does NOT advance ackedGrid -- no apply was ever confirmed) and force a
713
+ // fresh keyframe of the LATEST grid under a NEW seq (Karn: no seq is ever re-sent). A
714
+ // session with no viewers (opts.hasViewers false) is not a lost frame: nothing is re-sent to it
715
+ // (primary 2026-09-28: 581 resends to a hidden tab); the window is cleared with a keyframe owed,
716
+ // and regaining a viewer forces it. Gate 2 budget: ≤24 lines / 4 ifs / 2 returns.
717
+ // WP-0 (D-4c, docs/remote-relay-ack-rate-limit-typing-delay-2026-10-28.html §5 D-4c, §9 S-9):
718
+ // every recovery is reported to `opts.onRecovered(id, {inFlightKind, inFlightAgeMs, stallMs,
719
+ // hidden})` — diagnostics only, read BEFORE the in-flight slot is cleared.
720
+ // WP-2 (D-5, §9 S-9): the stall is now PER DELIVERY (`stallMsFor`, sized from that delivery's
721
+ // own measured ack RTT); `opts.stallMs` is the ceiling and `opts.floorMs` the floor (default
722
+ // 250 ms when absent). The reported `stallMs` is the per-delivery value actually used.
723
+ // WP-2 fix-1 (RFC 6298 §5.5 timer backoff): a resend mints a NEW seq, so the late ack for the
724
+ // old seq misses the guard and samples nothing (Karn) — the estimate cannot grow on its own, and
725
+ // a large keyframe on a slow relay would otherwise be re-emitted on the floor's cadence forever.
726
+ // Back the timer off ×2 per consecutive unacked resend (`sweepResends`, incremented below and
727
+ // reset to 0 by onAck), capped at the ceiling. An unsampled delivery is already at the ceiling,
728
+ // so the backoff only binds once sampled.
552
729
  sweepStalledInFlight(nowTs, opts) {
553
730
  const t = Number(nowTs);
554
731
  const stallMs = Number(opts && opts.stallMs);
555
732
  if (!Number.isFinite(t) || !Number.isFinite(stallMs) || stallMs <= 0) return 0;
733
+ const rawFloor = Number(opts && opts.floorMs);
734
+ const floorMs = Number.isFinite(rawFloor) ? rawFloor : 250;
556
735
  let recovered = 0;
557
736
  for (const [id, session] of sessions) {
558
737
  if (session.clients.size === 0) continue;
559
738
  const hidden = !!(opts && opts.hasViewers) && !opts.hasViewers(id);
560
739
  for (const delivery of session.clients.values()) {
561
740
  const s = delivery.state;
562
- if (!s.inFlightSeq || t - Number(s.inFlightAt || 0) <= stallMs) continue;
563
- s.inFlightSeq = 0;
564
- s.inFlightGrid = null;
741
+ const deliveryStallMs = Math.min(
742
+ stallMs,
743
+ stallMsFor(s, { floorMs, ceilingMs: stallMs }) * 2 ** Math.min(Number(s.sweepResends || 0), 6)
744
+ );
745
+ if (!s.inFlight.length || t - Number(s.inFlightAt || 0) <= deliveryStallMs) continue;
746
+ const inFlightKind = s.inFlightKind;
747
+ const inFlightAgeMs = t - Number(s.inFlightAt || 0);
748
+ s.inFlight = [];
749
+ s.inFlightBytes = 0;
565
750
  s.dirty = false;
566
751
  s.owedKeyframe = s.owedKeyframe || hidden;
567
- if (!hidden && emit(id, delivery, { force: true })) {
752
+ syncOldest(s);
753
+ const reEmitted = !hidden && emit(id, delivery, {
754
+ force: true, echoedThroughSeq: Number(session.latestEchoedThroughSeq || 0),
755
+ });
756
+ if (reEmitted) {
568
757
  s.sweepResends = Number(s.sweepResends || 0) + 1;
569
758
  recovered += 1;
570
759
  }
760
+ if (hidden || reEmitted) _noteRecovered(opts, id, { inFlightKind, inFlightAgeMs, stallMs: deliveryStallMs, hidden });
571
761
  }
572
762
  }
573
763
  return recovered;
@@ -595,6 +785,7 @@ function createFrameEmitter(deps) {
595
785
  socketGeneration: Number(delivery.socketGeneration || 0),
596
786
  inFlightSeq: s.inFlightSeq,
597
787
  inFlightKind: s.inFlightKind,
788
+ inFlightCount: s.inFlight.length,
598
789
  ackedSeq: s.ackedSeq,
599
790
  lastAckAgeMs,
600
791
  lastAckClientId: s.lastAckClientId || '',
@@ -606,9 +797,28 @@ function createFrameEmitter(deps) {
606
797
  return out;
607
798
  },
608
799
 
609
- // R-2 (0.9.33 shape): the fan-out reported this exact frame never left the wire (backpressure
610
- // skip). Clear in flight; a dropped KEYFRAME owes one, a dropped delta just leaves the
611
- // delivery dirty -- the next emit diffs losslessly against the unchanged ackedGrid.
800
+ // §6: read-only window telemetry for one delivery (null when unknown). oldestAgeMs is 0 for an
801
+ // empty window.
802
+ getWindowStats(id, clientId, socketGeneration) {
803
+ const session = sessions.get(id);
804
+ if (!session) return null;
805
+ const delivery = session.clients.get(deliveryKey(clientId, socketGeneration));
806
+ if (!delivery) return null;
807
+ const s = delivery.state;
808
+ return {
809
+ inFlightCount: s.inFlight.length,
810
+ inFlightBytes: Number(s.inFlightBytes || 0),
811
+ oldestAgeMs: s.inFlight.length ? Math.max(0, now() - Number(s.inFlightAt || now())) : 0,
812
+ windowFrames: windowFrames,
813
+ windowBytes: windowBytes,
814
+ };
815
+ },
816
+
817
+ // §5 D-5a: the fan-out reported this exact frame never left the wire (backpressure skip /
818
+ // restore hold). Drop every entry with seq ≥ the named one and keep the rest -- those still
819
+ // reach the client, in order -- then owe ONE keyframe whose scroll-out base is the newest kept
820
+ // grid (so rows the client already has are not re-donated). A seq not in the window touches
821
+ // nothing: the frame it names already left, or was itself cleared by a later event.
612
822
  noteUndeliverable(id, ctx) {
613
823
  ctx = ctx || {};
614
824
  const session = st(id);
@@ -616,16 +826,15 @@ function createFrameEmitter(deps) {
616
826
  const delivery = ctx.clientId ? session.clients.get(clientKey) : null;
617
827
  if (!delivery) return false;
618
828
  const s = delivery.state;
619
- // A skip notice names the seq it is about. A notice for a seq that is no longer the
620
- // in-flight one (already acked, already re-sent, or simply stale/reordered) is about an
621
- // OLDER frame -- it must never clear or otherwise touch whatever is in flight NOW.
622
829
  const noticeSeq = Number(ctx.seq || 0);
623
- if (noticeSeq && noticeSeq !== s.inFlightSeq) return false;
624
- const wasKeyframe = !!ctx.wasKeyframe || s.inFlightKind === 'keyframe';
625
- s.inFlightSeq = 0;
626
- s.inFlightGrid = null;
830
+ if (!s.inFlight.some((e) => e.seq === noticeSeq)) return false;
831
+ const kept = s.inFlight.filter((e) => e.seq < noticeSeq);
832
+ s.inFlight = kept;
833
+ s.inFlightBytes = kept.reduce((sum, e) => sum + Number(e.bytes || 0), 0);
834
+ s.resetBaseGrid = kept.length ? kept[kept.length - 1].grid : (s.ackedGrid || EMPTY_GRID);
835
+ s.owedKeyframe = true;
627
836
  s.dirty = true;
628
- if (wasKeyframe) s.owedKeyframe = true;
837
+ syncOldest(s);
629
838
  return true;
630
839
  },
631
840
 
@@ -705,6 +914,13 @@ function createFrameEmitter(deps) {
705
914
  state.ackedGrid = reservation.grid;
706
915
  state.ackedGridRevision = reservation.gridRevision;
707
916
  state.ackedSeq = reservation.baseSeq;
917
+ // WP-1 (D-1): the keyframe rule keys on sentSeq, not ackedSeq. A reservation IS a known
918
+ // receiver state (the client holds the bootstrap snapshot at this base), so the exit state
919
+ // must seed the SENT base too -- otherwise the first post-activation frame would be a
920
+ // spurious full keyframe instead of D-9's delta on the reservation base.
921
+ state.sentGrid = reservation.grid;
922
+ state.sentGridRevision = reservation.gridRevision;
923
+ state.sentSeq = reservation.baseSeq;
708
924
  state.surfaceEpoch = reservation.surfaceEpoch;
709
925
  state.surfaceIdentity = {
710
926
  rows: Number(reservation.grid.rows || 0), cols: Number(reservation.grid.cols || 0),
@@ -765,4 +981,7 @@ function createFrameEmitter(deps) {
765
981
  return emitter;
766
982
  }
767
983
 
768
- module.exports = { createFrameEmitter, EMPTY_GRID, gridsEqual, gridIsBlankAtHome };
984
+ module.exports = {
985
+ createFrameEmitter, EMPTY_GRID, gridsEqual, gridIsBlankAtHome, noteAckRtt, stallMsFor,
986
+ STATE_SYNC_WINDOW_FRAMES, STATE_SYNC_WINDOW_BYTES,
987
+ };