@seat-mesh/daemon 0.1.26 → 0.1.29

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 (178) hide show
  1. package/dist/border/border-paint.d.ts +13 -0
  2. package/dist/border/border-paint.d.ts.map +1 -0
  3. package/dist/border/border-paint.js +230 -0
  4. package/dist/border/border-paint.js.map +1 -0
  5. package/dist/checkback/checkback-fire.d.ts +8 -0
  6. package/dist/checkback/checkback-fire.d.ts.map +1 -0
  7. package/dist/checkback/checkback-fire.js +52 -0
  8. package/dist/checkback/checkback-fire.js.map +1 -0
  9. package/dist/checkback/checkback-fire.test.d.ts +2 -0
  10. package/dist/checkback/checkback-fire.test.d.ts.map +1 -0
  11. package/dist/checkback/checkback-fire.test.js +36 -0
  12. package/dist/checkback/checkback-fire.test.js.map +1 -0
  13. package/dist/connectivity/cc-limit-retry.d.ts +11 -0
  14. package/dist/connectivity/cc-limit-retry.d.ts.map +1 -0
  15. package/dist/connectivity/cc-limit-retry.js +73 -0
  16. package/dist/connectivity/cc-limit-retry.js.map +1 -0
  17. package/dist/connectivity/connectivity-recovery.d.ts +88 -0
  18. package/dist/connectivity/connectivity-recovery.d.ts.map +1 -0
  19. package/dist/connectivity/connectivity-recovery.js +529 -0
  20. package/dist/connectivity/connectivity-recovery.js.map +1 -0
  21. package/dist/connectivity/connectivity-recovery.test.d.ts +2 -0
  22. package/dist/connectivity/connectivity-recovery.test.d.ts.map +1 -0
  23. package/dist/connectivity/connectivity-recovery.test.js +170 -0
  24. package/dist/connectivity/connectivity-recovery.test.js.map +1 -0
  25. package/dist/connectivity/oc-resume-ack.d.ts +32 -0
  26. package/dist/connectivity/oc-resume-ack.d.ts.map +1 -0
  27. package/dist/connectivity/oc-resume-ack.js +89 -0
  28. package/dist/connectivity/oc-resume-ack.js.map +1 -0
  29. package/dist/connectivity/oc-resume-ack.test.d.ts +2 -0
  30. package/dist/connectivity/oc-resume-ack.test.d.ts.map +1 -0
  31. package/dist/connectivity/oc-resume-ack.test.js +23 -0
  32. package/dist/connectivity/oc-resume-ack.test.js.map +1 -0
  33. package/dist/connectivity/oc-resume.d.ts +25 -0
  34. package/dist/connectivity/oc-resume.d.ts.map +1 -0
  35. package/dist/connectivity/oc-resume.js +84 -0
  36. package/dist/connectivity/oc-resume.js.map +1 -0
  37. package/dist/inbox/delivery-hold.d.ts +11 -0
  38. package/dist/inbox/delivery-hold.d.ts.map +1 -0
  39. package/dist/inbox/delivery-hold.js +34 -0
  40. package/dist/inbox/delivery-hold.js.map +1 -0
  41. package/dist/inbox/delivery-hold.test.d.ts +2 -0
  42. package/dist/inbox/delivery-hold.test.d.ts.map +1 -0
  43. package/dist/inbox/delivery-hold.test.js +40 -0
  44. package/dist/inbox/delivery-hold.test.js.map +1 -0
  45. package/dist/inbox/inbox-overload.d.ts +19 -0
  46. package/dist/inbox/inbox-overload.d.ts.map +1 -0
  47. package/dist/inbox/inbox-overload.js +45 -0
  48. package/dist/inbox/inbox-overload.js.map +1 -0
  49. package/dist/inbox/inbox-overload.test.d.ts +2 -0
  50. package/dist/inbox/inbox-overload.test.d.ts.map +1 -0
  51. package/dist/inbox/inbox-overload.test.js +43 -0
  52. package/dist/inbox/inbox-overload.test.js.map +1 -0
  53. package/dist/inbox/pane-ops-drain.d.ts +14 -0
  54. package/dist/inbox/pane-ops-drain.d.ts.map +1 -0
  55. package/dist/inbox/pane-ops-drain.js +53 -0
  56. package/dist/inbox/pane-ops-drain.js.map +1 -0
  57. package/dist/index.d.ts +2 -2
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +2 -2
  60. package/dist/index.js.map +1 -1
  61. package/dist/inject/compose-gate.d.ts +23 -0
  62. package/dist/inject/compose-gate.d.ts.map +1 -0
  63. package/dist/inject/compose-gate.js +113 -0
  64. package/dist/inject/compose-gate.js.map +1 -0
  65. package/dist/inject/compose-gate.test.d.ts +2 -0
  66. package/dist/inject/compose-gate.test.d.ts.map +1 -0
  67. package/dist/inject/compose-gate.test.js +35 -0
  68. package/dist/inject/compose-gate.test.js.map +1 -0
  69. package/dist/inject/inject-delivery.d.ts +39 -0
  70. package/dist/inject/inject-delivery.d.ts.map +1 -0
  71. package/dist/inject/inject-delivery.js +171 -0
  72. package/dist/inject/inject-delivery.js.map +1 -0
  73. package/dist/inject/inject-delivery.test.d.ts +2 -0
  74. package/dist/inject/inject-delivery.test.d.ts.map +1 -0
  75. package/dist/inject/inject-delivery.test.js +33 -0
  76. package/dist/inject/inject-delivery.test.js.map +1 -0
  77. package/dist/jsonl-store.d.ts.map +1 -1
  78. package/dist/jsonl-store.js +4 -0
  79. package/dist/jsonl-store.js.map +1 -1
  80. package/dist/mesh-inbox-server.js +13 -13
  81. package/dist/mesh-inbox-server.js.map +1 -1
  82. package/dist/mesh-orchestrator.d.ts.map +1 -1
  83. package/dist/mesh-orchestrator.js +1 -0
  84. package/dist/mesh-orchestrator.js.map +1 -1
  85. package/dist/notify/notify-act-ui.d.ts +7 -0
  86. package/dist/notify/notify-act-ui.d.ts.map +1 -0
  87. package/dist/notify/notify-act-ui.js +59 -0
  88. package/dist/notify/notify-act-ui.js.map +1 -0
  89. package/dist/notify/notify-act.d.ts +45 -0
  90. package/dist/notify/notify-act.d.ts.map +1 -0
  91. package/dist/notify/notify-act.js +133 -0
  92. package/dist/notify/notify-act.js.map +1 -0
  93. package/dist/notify/notify-act.test.d.ts +2 -0
  94. package/dist/notify/notify-act.test.d.ts.map +1 -0
  95. package/dist/notify/notify-act.test.js +29 -0
  96. package/dist/notify/notify-act.test.js.map +1 -0
  97. package/dist/orchestrator/mesh-orchestrator.d.ts +32 -0
  98. package/dist/orchestrator/mesh-orchestrator.d.ts.map +1 -0
  99. package/dist/orchestrator/mesh-orchestrator.js +642 -0
  100. package/dist/orchestrator/mesh-orchestrator.js.map +1 -0
  101. package/dist/orchestrator/orchestrator.d.ts +17 -0
  102. package/dist/orchestrator/orchestrator.d.ts.map +1 -0
  103. package/dist/orchestrator/orchestrator.js +11 -0
  104. package/dist/orchestrator/orchestrator.js.map +1 -0
  105. package/dist/orchestrator/workers.d.ts +11 -0
  106. package/dist/orchestrator/workers.d.ts.map +1 -0
  107. package/dist/orchestrator/workers.js +12 -0
  108. package/dist/orchestrator/workers.js.map +1 -0
  109. package/dist/peer/peer-backlog.d.ts +18 -0
  110. package/dist/peer/peer-backlog.d.ts.map +1 -0
  111. package/dist/peer/peer-backlog.js +288 -0
  112. package/dist/peer/peer-backlog.js.map +1 -0
  113. package/dist/peer/peer-backlog.test.d.ts +2 -0
  114. package/dist/peer/peer-backlog.test.d.ts.map +1 -0
  115. package/dist/peer/peer-backlog.test.js +38 -0
  116. package/dist/peer/peer-backlog.test.js.map +1 -0
  117. package/dist/peer/peer-comms-checkback.d.ts +5 -0
  118. package/dist/peer/peer-comms-checkback.d.ts.map +1 -0
  119. package/dist/peer/peer-comms-checkback.js +68 -0
  120. package/dist/peer/peer-comms-checkback.js.map +1 -0
  121. package/dist/peer/peer-pending.d.ts +9 -0
  122. package/dist/peer/peer-pending.d.ts.map +1 -0
  123. package/dist/peer/peer-pending.js +19 -0
  124. package/dist/peer/peer-pending.js.map +1 -0
  125. package/dist/peer/peer-pending.test.d.ts +2 -0
  126. package/dist/peer/peer-pending.test.d.ts.map +1 -0
  127. package/dist/peer/peer-pending.test.js +76 -0
  128. package/dist/peer/peer-pending.test.js.map +1 -0
  129. package/dist/peer/peer-skip.d.ts +20 -0
  130. package/dist/peer/peer-skip.d.ts.map +1 -0
  131. package/dist/peer/peer-skip.js +56 -0
  132. package/dist/peer/peer-skip.js.map +1 -0
  133. package/dist/peer/peer-skip.test.d.ts +2 -0
  134. package/dist/peer/peer-skip.test.d.ts.map +1 -0
  135. package/dist/peer/peer-skip.test.js +63 -0
  136. package/dist/peer/peer-skip.test.js.map +1 -0
  137. package/dist/peer/peer-target-resolve.d.ts +8 -0
  138. package/dist/peer/peer-target-resolve.d.ts.map +1 -0
  139. package/dist/peer/peer-target-resolve.js +13 -0
  140. package/dist/peer/peer-target-resolve.js.map +1 -0
  141. package/dist/peer-backlog.d.ts.map +1 -1
  142. package/dist/peer-backlog.js +25 -0
  143. package/dist/peer-backlog.js.map +1 -1
  144. package/dist/peer-pending.test.js +17 -0
  145. package/dist/peer-pending.test.js.map +1 -1
  146. package/dist/queue/bullmq-runtime.d.ts +19 -0
  147. package/dist/queue/bullmq-runtime.d.ts.map +1 -0
  148. package/dist/queue/bullmq-runtime.js +78 -0
  149. package/dist/queue/bullmq-runtime.js.map +1 -0
  150. package/dist/state/ppa-state.d.ts +32 -0
  151. package/dist/state/ppa-state.d.ts.map +1 -0
  152. package/dist/state/ppa-state.js +63 -0
  153. package/dist/state/ppa-state.js.map +1 -0
  154. package/dist/store/create-queue-store.d.ts +8 -0
  155. package/dist/store/create-queue-store.d.ts.map +1 -0
  156. package/dist/store/create-queue-store.js +19 -0
  157. package/dist/store/create-queue-store.js.map +1 -0
  158. package/dist/store/jsonl-dedupe.test.d.ts +2 -0
  159. package/dist/store/jsonl-dedupe.test.d.ts.map +1 -0
  160. package/dist/store/jsonl-dedupe.test.js +62 -0
  161. package/dist/store/jsonl-dedupe.test.js.map +1 -0
  162. package/dist/store/jsonl-store.checkback.test.d.ts +2 -0
  163. package/dist/store/jsonl-store.checkback.test.d.ts.map +1 -0
  164. package/dist/store/jsonl-store.checkback.test.js +55 -0
  165. package/dist/store/jsonl-store.checkback.test.js.map +1 -0
  166. package/dist/store/jsonl-store.d.ts +129 -0
  167. package/dist/store/jsonl-store.d.ts.map +1 -0
  168. package/dist/store/jsonl-store.js +316 -0
  169. package/dist/store/jsonl-store.js.map +1 -0
  170. package/dist/store/sqlite-store.d.ts +52 -0
  171. package/dist/store/sqlite-store.d.ts.map +1 -0
  172. package/dist/store/sqlite-store.js +456 -0
  173. package/dist/store/sqlite-store.js.map +1 -0
  174. package/dist/store/sqlite-store.test.d.ts +2 -0
  175. package/dist/store/sqlite-store.test.d.ts.map +1 -0
  176. package/dist/store/sqlite-store.test.js +76 -0
  177. package/dist/store/sqlite-store.test.js.map +1 -0
  178. package/package.json +4 -4
@@ -0,0 +1,170 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import fs from "node:fs";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import { clearOcLimitBannerForPane, maybeEndRateLimitEpisode, newConnectivityRecoveryState, shouldChainRotateUntilAfterSmart, shouldNotifyProxyDownStuck, smartRestartCooldownLeftSec, updateIpifyProbeStreak, updatePaneConnectStreak, updateRateLimitEpisode, } from "./connectivity-recovery.js";
6
+ describe("updateIpifyProbeStreak (debounce shallow ipify failures)", () => {
7
+ it("does not confirm down on the first failure", () => {
8
+ const state = newConnectivityRecoveryState();
9
+ const r = updateIpifyProbeStreak(state, false, 3);
10
+ expect(r.confirmedDown).toBe(false);
11
+ expect(r.streak).toBe(1);
12
+ });
13
+ it("confirms down only after threshold consecutive failures", () => {
14
+ const state = newConnectivityRecoveryState();
15
+ updateIpifyProbeStreak(state, false, 3);
16
+ updateIpifyProbeStreak(state, false, 3);
17
+ const r = updateIpifyProbeStreak(state, false, 3);
18
+ expect(r.confirmedDown).toBe(true);
19
+ expect(r.streak).toBe(3);
20
+ });
21
+ it("resets streak when carrier is ok again", () => {
22
+ const state = newConnectivityRecoveryState();
23
+ updateIpifyProbeStreak(state, false, 3);
24
+ updateIpifyProbeStreak(state, true, 3);
25
+ expect(state.ipifyFailStreak).toBe(0);
26
+ const r = updateIpifyProbeStreak(state, false, 3);
27
+ expect(r.confirmedDown).toBe(false);
28
+ expect(r.streak).toBe(1);
29
+ });
30
+ });
31
+ describe("updatePaneConnectStreak (PROXY-DOWN scrollback debounce)", () => {
32
+ it("does not confirm connect on first observation", () => {
33
+ const m = new Map();
34
+ const r = updatePaneConnectStreak(m, "%1", true, 15);
35
+ expect(r.confirmed).toBe(false);
36
+ expect(r.streak).toBe(1);
37
+ });
38
+ it("confirms only after threshold consecutive observations", () => {
39
+ const m = new Map();
40
+ for (let i = 0; i < 14; i++) {
41
+ updatePaneConnectStreak(m, "%1", true, 15);
42
+ }
43
+ const r = updatePaneConnectStreak(m, "%1", true, 15);
44
+ expect(r.confirmed).toBe(true);
45
+ expect(r.streak).toBe(15);
46
+ });
47
+ it("resets when the pane no longer shows connect errors", () => {
48
+ const m = new Map();
49
+ updatePaneConnectStreak(m, "%1", true, 15);
50
+ updatePaneConnectStreak(m, "%1", false, 15);
51
+ expect(m.has("%1")).toBe(false);
52
+ });
53
+ });
54
+ describe("updateRateLimitEpisode (OC-LIMIT rising-edge/episode)", () => {
55
+ it("starts an episode on the first rate-limited pane", () => {
56
+ const state = newConnectivityRecoveryState();
57
+ const r = updateRateLimitEpisode(state, true, 1_000);
58
+ expect(r.action).toBe("start");
59
+ expect(state.rateLimitEpisodeActive).toBe(true);
60
+ expect(state.lastRateLimitSeenAt).toBe(1_000);
61
+ });
62
+ it("does not re-trigger while the episode is already active (no re-arm loop)", () => {
63
+ const state = newConnectivityRecoveryState();
64
+ updateRateLimitEpisode(state, true, 1_000);
65
+ const r = updateRateLimitEpisode(state, true, 2_000);
66
+ expect(r.action).toBe("continue");
67
+ expect(state.lastRateLimitSeenAt).toBe(2_000);
68
+ });
69
+ it("does not clear immediately when limited panes disappear (flicker grace)", () => {
70
+ const state = newConnectivityRecoveryState();
71
+ updateRateLimitEpisode(state, true, 1_000);
72
+ const r = updateRateLimitEpisode(state, false, 1_500, 120_000);
73
+ expect(r.action).toBe("none");
74
+ expect(state.rateLimitEpisodeActive).toBe(true);
75
+ });
76
+ it("clears the episode once the grace period has elapsed with no limited panes", () => {
77
+ const state = newConnectivityRecoveryState();
78
+ updateRateLimitEpisode(state, true, 1_000);
79
+ const r = updateRateLimitEpisode(state, false, 1_000 + 120_001, 120_000);
80
+ expect(r.action).toBe("clear");
81
+ expect(state.rateLimitEpisodeActive).toBe(false);
82
+ });
83
+ it("newConnectivityRecoveryState includes rateLimitRecoveryStarted false", () => {
84
+ expect(newConnectivityRecoveryState().rateLimitRecoveryStarted).toBe(false);
85
+ });
86
+ it("is a no-op when never armed and still no limit", () => {
87
+ const state = newConnectivityRecoveryState();
88
+ const r = updateRateLimitEpisode(state, false, 1_000);
89
+ expect(r.action).toBe("none");
90
+ });
91
+ });
92
+ describe("shouldChainRotateUntilAfterSmart (Proxy-SMART -> rotate-until chaining)", () => {
93
+ it("chains when Proxy-SMART skipped on cooldown (exit 2)", () => {
94
+ expect(shouldChainRotateUntilAfterSmart({ exitCode: 2, ipBefore: "1.2.3.4", ipAfter: "1.2.3.4" })).toBe(true);
95
+ });
96
+ it("chains when the carrier IP failed to resolve after SMART", () => {
97
+ expect(shouldChainRotateUntilAfterSmart({ exitCode: 0, ipBefore: "1.2.3.4", ipAfter: null })).toBe(true);
98
+ });
99
+ it("chains when the carrier IP is unchanged (SMART no-op)", () => {
100
+ expect(shouldChainRotateUntilAfterSmart({ exitCode: 0, ipBefore: "1.2.3.4", ipAfter: "1.2.3.4" })).toBe(true);
101
+ });
102
+ it("chains when SMART exited non-zero for any other reason", () => {
103
+ expect(shouldChainRotateUntilAfterSmart({ exitCode: 1, ipBefore: "1.2.3.4", ipAfter: "5.6.7.8" })).toBe(true);
104
+ });
105
+ it("does NOT chain when SMART succeeded and rotated the carrier IP", () => {
106
+ expect(shouldChainRotateUntilAfterSmart({ exitCode: 0, ipBefore: "1.2.3.4", ipAfter: "5.6.7.8" })).toBe(false);
107
+ });
108
+ });
109
+ describe("shouldNotifyProxyDownStuck (PROXY-DOWN silence fix)", () => {
110
+ it("does not notify before an episode has started", () => {
111
+ const state = newConnectivityRecoveryState();
112
+ expect(shouldNotifyProxyDownStuck(state, 1_000, 120_000)).toBe(false);
113
+ });
114
+ it("does not notify before the threshold elapses", () => {
115
+ const state = newConnectivityRecoveryState();
116
+ state.proxyDownEpisodeStartAt = 1_000;
117
+ expect(shouldNotifyProxyDownStuck(state, 1_000 + 119_999, 120_000)).toBe(false);
118
+ });
119
+ it("notifies once the threshold elapses", () => {
120
+ const state = newConnectivityRecoveryState();
121
+ state.proxyDownEpisodeStartAt = 1_000;
122
+ expect(shouldNotifyProxyDownStuck(state, 1_000 + 120_000, 120_000)).toBe(true);
123
+ });
124
+ it("never re-fires once already notified for this episode", () => {
125
+ const state = newConnectivityRecoveryState();
126
+ state.proxyDownEpisodeStartAt = 1_000;
127
+ state.proxyDownStuckNotified = true;
128
+ expect(shouldNotifyProxyDownStuck(state, 1_000 + 999_999, 120_000)).toBe(false);
129
+ });
130
+ });
131
+ describe("clearOcLimitBannerForPane", () => {
132
+ it("removes pane from ocLimited and ends episode when cache empty", () => {
133
+ const state = newConnectivityRecoveryState();
134
+ state.ocLimited.add("%9");
135
+ state.rateLimitEpisodeActive = true;
136
+ state.rateLimitRecoveryStarted = true;
137
+ expect(clearOcLimitBannerForPane(state, "%9")).toBe(true);
138
+ expect(state.ocLimited.has("%9")).toBe(false);
139
+ maybeEndRateLimitEpisode(state);
140
+ expect(state.rateLimitEpisodeActive).toBe(false);
141
+ expect(state.rateLimitRecoveryStarted).toBe(false);
142
+ });
143
+ });
144
+ describe("smartRestartCooldownLeftSec (harness-parity stamp file)", () => {
145
+ const tmpStamp = path.join(os.tmpdir(), `sm-test-smart-restart-${process.pid}.last`);
146
+ it("returns 0 when the stamp file does not exist", () => {
147
+ expect(smartRestartCooldownLeftSec(tmpStamp, 1800, 1_000_000)).toBe(0);
148
+ });
149
+ it("returns seconds left when within the cooldown window", () => {
150
+ const nowSec = 1_000_000;
151
+ fs.writeFileSync(tmpStamp, String(nowSec - 100));
152
+ try {
153
+ expect(smartRestartCooldownLeftSec(tmpStamp, 1800, nowSec * 1000)).toBe(1700);
154
+ }
155
+ finally {
156
+ fs.rmSync(tmpStamp, { force: true });
157
+ }
158
+ });
159
+ it("returns 0 once the cooldown window has fully elapsed", () => {
160
+ const nowSec = 1_000_000;
161
+ fs.writeFileSync(tmpStamp, String(nowSec - 1800));
162
+ try {
163
+ expect(smartRestartCooldownLeftSec(tmpStamp, 1800, nowSec * 1000)).toBe(0);
164
+ }
165
+ finally {
166
+ fs.rmSync(tmpStamp, { force: true });
167
+ }
168
+ });
169
+ });
170
+ //# sourceMappingURL=connectivity-recovery.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connectivity-recovery.test.js","sourceRoot":"","sources":["../../src/connectivity/connectivity-recovery.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { ProviderRegistry } from "@seat-mesh/core";
2
+ export interface ResumeAckWave {
3
+ paneIds: Set<string>;
4
+ acked: Set<string>;
5
+ reason: string;
6
+ startedAt: number;
7
+ timeoutNotified: boolean;
8
+ }
9
+ export declare function currentResumeAckWave(): ResumeAckWave | null;
10
+ /** Test-only: reset module state between cases. */
11
+ export declare function resetResumeAckWave(): void;
12
+ /**
13
+ * Pure decision: given a wave's ack progress, what should the daemon do next?
14
+ * Exported for unit testing without tmux/process spawning.
15
+ */
16
+ export declare function nextAckWaveAction(input: {
17
+ total: number;
18
+ ackedCount: number;
19
+ startedAt: number;
20
+ timeoutNotified: boolean;
21
+ }, nowMs?: number, timeoutMs?: number): "idle" | "all-acked" | "timeout" | "waiting";
22
+ /**
23
+ * Call right after a resume wave is sent — arms ack tracking for exactly those panes.
24
+ * A fresh wave replaces whatever was pending (the newest resume is the one that matters).
25
+ */
26
+ export declare function armResumeAckWave(paneIds: string[], reason: string): void;
27
+ /**
28
+ * Poll tick: check pending panes for proof they're actually working again (composer no
29
+ * longer shows `limit`), then notify operator once the wave fully confirms or times out.
30
+ */
31
+ export declare function pollResumeAcks(registry: ProviderRegistry, workspace: string, log: (line: string) => void, onPaneAcked?: (paneId: string) => void): void;
32
+ //# sourceMappingURL=oc-resume-ack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oc-resume-ack.d.ts","sourceRoot":"","sources":["../../src/connectivity/oc-resume-ack.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAOxD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACrB,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAKD,wBAAgB,oBAAoB,IAAI,aAAa,GAAG,IAAI,CAE3D;AAED,mDAAmD;AACnD,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,OAAO,CAAA;CAAE,EACzF,KAAK,GAAE,MAAmB,EAC1B,SAAS,GAAE,MAAuB,GACjC,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,CAK9C;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CASxE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,gBAAgB,EAC1B,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EAC3B,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GACrC,IAAI,CAwDN"}
@@ -0,0 +1,89 @@
1
+ import { capturePaneSnapshot } from "@seat-mesh/tmux";
2
+ import { notifyConnectivityStatus, RESUME_ACK_HOWTO } from "./oc-resume.js";
3
+ /** How long to wait for a resumed pane to prove it's working again before flagging it stuck. */
4
+ const ACK_TIMEOUT_MS = 5 * 60_000;
5
+ /** Module-level: at most one resume wave is tracked for ack at a time (a new wave replaces it). */
6
+ let activeWave = null;
7
+ export function currentResumeAckWave() {
8
+ return activeWave;
9
+ }
10
+ /** Test-only: reset module state between cases. */
11
+ export function resetResumeAckWave() {
12
+ activeWave = null;
13
+ }
14
+ /**
15
+ * Pure decision: given a wave's ack progress, what should the daemon do next?
16
+ * Exported for unit testing without tmux/process spawning.
17
+ */
18
+ export function nextAckWaveAction(input, nowMs = Date.now(), timeoutMs = ACK_TIMEOUT_MS) {
19
+ if (input.total <= 0)
20
+ return "idle";
21
+ if (input.ackedCount >= input.total)
22
+ return "all-acked";
23
+ if (!input.timeoutNotified && nowMs - input.startedAt >= timeoutMs)
24
+ return "timeout";
25
+ return "waiting";
26
+ }
27
+ /**
28
+ * Call right after a resume wave is sent — arms ack tracking for exactly those panes.
29
+ * A fresh wave replaces whatever was pending (the newest resume is the one that matters).
30
+ */
31
+ export function armResumeAckWave(paneIds, reason) {
32
+ if (!paneIds.length)
33
+ return;
34
+ activeWave = {
35
+ paneIds: new Set(paneIds),
36
+ acked: new Set(),
37
+ reason,
38
+ startedAt: Date.now(),
39
+ timeoutNotified: false,
40
+ };
41
+ }
42
+ /**
43
+ * Poll tick: check pending panes for proof they're actually working again (composer no
44
+ * longer shows `limit`), then notify operator once the wave fully confirms or times out.
45
+ */
46
+ export function pollResumeAcks(registry, workspace, log, onPaneAcked) {
47
+ const wave = activeWave;
48
+ if (!wave)
49
+ return;
50
+ for (const paneId of wave.paneIds) {
51
+ if (wave.acked.has(paneId))
52
+ continue;
53
+ const snap = capturePaneSnapshot(paneId);
54
+ if (!snap) {
55
+ wave.acked.add(paneId);
56
+ continue;
57
+ }
58
+ const prov = registry.detect(snap);
59
+ if (prov?.id !== "opencode") {
60
+ wave.acked.add(paneId);
61
+ continue;
62
+ }
63
+ if (prov.composerState(snap).phase !== "limit") {
64
+ wave.acked.add(paneId);
65
+ log(`OC-RESUME ack ${paneId} confirmed working — clearing OC-LIMIT banner`);
66
+ onPaneAcked?.(paneId);
67
+ }
68
+ }
69
+ const action = nextAckWaveAction({
70
+ total: wave.paneIds.size,
71
+ ackedCount: wave.acked.size,
72
+ startedAt: wave.startedAt,
73
+ timeoutNotified: wave.timeoutNotified,
74
+ });
75
+ if (action === "all-acked") {
76
+ log(`OC-RESUME all acked (${wave.acked.size}/${wave.paneIds.size}) reason=${wave.reason}`);
77
+ notifyConnectivityStatus(workspace, "OC resume", `All ${wave.paneIds.size} resumed OC panes acked — limit screens cleared (${wave.reason}).`, "No action needed.", "complete");
78
+ activeWave = null;
79
+ return;
80
+ }
81
+ if (action === "timeout") {
82
+ wave.timeoutNotified = true;
83
+ const stuck = wave.paneIds.size - wave.acked.size;
84
+ const ageSec = Math.round((Date.now() - wave.startedAt) / 1000);
85
+ log(`OC-RESUME ack timeout: ${stuck}/${wave.paneIds.size} unconfirmed after ${ageSec}s`);
86
+ notifyConnectivityStatus(workspace, "OC resume", `${stuck}/${wave.paneIds.size} resumed panes still not acked after ${ageSec}s (${wave.reason}).`, `${RESUME_ACK_HOWTO} Stuck panes: open pane, confirm limit text gone or press Enter once on resume.`, "incomplete");
87
+ }
88
+ }
89
+ //# sourceMappingURL=oc-resume-ack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oc-resume-ack.js","sourceRoot":"","sources":["../../src/connectivity/oc-resume-ack.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=oc-resume-ack.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oc-resume-ack.test.d.ts","sourceRoot":"","sources":["../../src/connectivity/oc-resume-ack.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,23 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { nextAckWaveAction } from "./oc-resume-ack.js";
3
+ describe("nextAckWaveAction (OC-RESUME ack-confirmation wave)", () => {
4
+ it("is idle when there is nothing to track", () => {
5
+ expect(nextAckWaveAction({ total: 0, ackedCount: 0, startedAt: 0, timeoutNotified: false }, 1_000, 300_000)).toBe("idle");
6
+ });
7
+ it("waits while some panes are still unconfirmed and under the timeout", () => {
8
+ expect(nextAckWaveAction({ total: 3, ackedCount: 1, startedAt: 1_000, timeoutNotified: false }, 1_000 + 60_000, 300_000)).toBe("waiting");
9
+ });
10
+ it("reports all-acked once every pane has confirmed, regardless of elapsed time", () => {
11
+ expect(nextAckWaveAction({ total: 3, ackedCount: 3, startedAt: 1_000, timeoutNotified: false }, 1_000 + 999_999, 300_000)).toBe("all-acked");
12
+ });
13
+ it("reports timeout once the threshold elapses with stragglers left", () => {
14
+ expect(nextAckWaveAction({ total: 3, ackedCount: 1, startedAt: 1_000, timeoutNotified: false }, 1_000 + 300_000, 300_000)).toBe("timeout");
15
+ });
16
+ it("never re-fires timeout once already notified", () => {
17
+ expect(nextAckWaveAction({ total: 3, ackedCount: 1, startedAt: 1_000, timeoutNotified: true }, 1_000 + 999_999, 300_000)).toBe("waiting");
18
+ });
19
+ it("prefers all-acked over timeout when both conditions technically hold", () => {
20
+ expect(nextAckWaveAction({ total: 3, ackedCount: 3, startedAt: 1_000, timeoutNotified: false }, 1_000 + 300_000, 300_000)).toBe("all-acked");
21
+ });
22
+ });
23
+ //# sourceMappingURL=oc-resume-ack.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oc-resume-ack.test.js","sourceRoot":"","sources":["../../src/connectivity/oc-resume-ack.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,QAAQ,CAAC,qDAAqD,EAAE,GAAG,EAAE;IACnE,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,CACJ,iBAAiB,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,eAAe,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,CACrG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACjB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,CACJ,iBAAiB,CACf,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,EACrE,KAAK,GAAG,MAAM,EACd,OAAO,CACR,CACF,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6EAA6E,EAAE,GAAG,EAAE;QACrF,MAAM,CACJ,iBAAiB,CACf,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,EACrE,KAAK,GAAG,OAAO,EACf,OAAO,CACR,CACF,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACtB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,MAAM,CACJ,iBAAiB,CACf,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,EACrE,KAAK,GAAG,OAAO,EACf,OAAO,CACR,CACF,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,CACJ,iBAAiB,CACf,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,EACpE,KAAK,GAAG,OAAO,EACf,OAAO,CACR,CACF,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,MAAM,CACJ,iBAAiB,CACf,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,EACrE,KAAK,GAAG,OAAO,EACf,OAAO,CACR,CACF,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACtB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,25 @@
1
+ import type { ProviderRegistry } from "@seat-mesh/core";
2
+ import { INBOX_NOTIFY_SLOT, type InboxNotifyPhase } from "@seat-mesh/tmux";
3
+ export { INBOX_NOTIFY_SLOT };
4
+ export type { InboxNotifyPhase };
5
+ /** Shown on resume-sent / ack toasts so operator knows ack is inbox-automatic, not a manual command. */
6
+ export declare const RESUME_ACK_HOWTO: string;
7
+ export declare function notifyConnectivityStatus(workspace: string, topic: string, sessionAbout: string, check: string, phase?: InboxNotifyPhase): void;
8
+ /** @deprecated Use resume wave notify with carrier meta instead. */
9
+ export declare function notifyProxyCarrierIp(workspace: string, fromIp: string | null, toIp: string, reason: string): void;
10
+ export declare function resumeOneOpenCodePane(paneId: string, registry: ProviderRegistry): {
11
+ ok: boolean;
12
+ cmd?: string;
13
+ reason?: string;
14
+ };
15
+ export declare function resumeAllOpenCodePanes(paneIds: string[], registry: ProviderRegistry, log?: (line: string) => void): {
16
+ sent: number;
17
+ total: number;
18
+ sentPaneIds: string[];
19
+ };
20
+ export interface ResumeWaveMeta {
21
+ fromIp?: string | null;
22
+ toIp?: string | null;
23
+ }
24
+ export declare function notifyResumeWave(workspace: string, reason: string, sent: number, total: number, meta?: ResumeWaveMeta): void;
25
+ //# sourceMappingURL=oc-resume.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oc-resume.d.ts","sourceRoot":"","sources":["../../src/connectivity/oc-resume.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAExD,OAAO,EAIL,iBAAiB,EAEjB,KAAK,gBAAgB,EACtB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAC7B,YAAY,EAAE,gBAAgB,EAAE,CAAC;AAEjC,wGAAwG;AACxG,eAAO,MAAM,gBAAgB,QAE+E,CAAC;AAE7G,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,KAAK,GAAE,gBAA6B,GACnC,IAAI,CAEN;AAED,oEAAoE;AACpE,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,IAAI,CAWN;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,gBAAgB,GACzB;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAchD;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EAAE,EACjB,QAAQ,EAAE,gBAAgB,EAC1B,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAC3B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,EAAE,CAAA;CAAE,CAiBxD;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,cAAc,GACpB,IAAI,CAwBN"}
@@ -0,0 +1,84 @@
1
+ import { formatOpenCodeResumeCommand } from "@seat-mesh/providers";
2
+ import { capturePaneSnapshot, injectToPane, withPaneInputEnabled, INBOX_NOTIFY_SLOT, runInboxDesktopNotifySync, } from "@seat-mesh/tmux";
3
+ export { INBOX_NOTIFY_SLOT };
4
+ /** Shown on resume-sent / ack toasts so operator knows ack is inbox-automatic, not a manual command. */
5
+ export const RESUME_ACK_HOWTO = "Ack: automatic — when the OC composer is back (limit screen gone), inbox clears the OC-LIMIT border on that pane. " +
6
+ "Complete toast = all borders cleared. Incomplete after 5m = eyeball stuck panes. Nothing for you to run.";
7
+ export function notifyConnectivityStatus(workspace, topic, sessionAbout, check, phase = "starting") {
8
+ runInboxDesktopNotifySync(workspace, { topic, phase, sessionAbout, check });
9
+ }
10
+ /** @deprecated Use resume wave notify with carrier meta instead. */
11
+ export function notifyProxyCarrierIp(workspace, fromIp, toIp, reason) {
12
+ const sessionAbout = fromIp && fromIp !== toIp
13
+ ? `Proxy ${reason}: carrier ${fromIp} -> ${toIp}.`
14
+ : `Proxy ${reason}: carrier ${toIp}.`;
15
+ runInboxDesktopNotifySync(workspace, {
16
+ phase: "sent",
17
+ topic: "Proxy rotate",
18
+ sessionAbout,
19
+ check: "Waiting for OC panes to confirm resume...",
20
+ });
21
+ }
22
+ export function resumeOneOpenCodePane(paneId, registry) {
23
+ const snap = capturePaneSnapshot(paneId);
24
+ if (!snap)
25
+ return { ok: false };
26
+ const prov = registry.detect(snap);
27
+ if (prov?.id !== "opencode")
28
+ return { ok: false };
29
+ const cmd = formatOpenCodeResumeCommand(snap);
30
+ if (!cmd)
31
+ return { ok: false, reason: "no-ses-id" };
32
+ const plan = prov.injectPlan(snap);
33
+ let ok = false;
34
+ withPaneInputEnabled(paneId, () => {
35
+ injectToPane(paneId, cmd, plan, prov.id, snap.captureTail, snap.captureTailAnsi);
36
+ ok = true;
37
+ });
38
+ return ok ? { ok: true, cmd } : { ok: false, reason: "inject-failed" };
39
+ }
40
+ export function resumeAllOpenCodePanes(paneIds, registry, log) {
41
+ let sent = 0;
42
+ let total = 0;
43
+ const sentPaneIds = [];
44
+ for (const paneId of paneIds) {
45
+ const snap = capturePaneSnapshot(paneId);
46
+ if (!snap)
47
+ continue;
48
+ if (registry.detect(snap)?.id !== "opencode")
49
+ continue;
50
+ total += 1;
51
+ const r = resumeOneOpenCodePane(paneId, registry);
52
+ if (r.ok) {
53
+ sent += 1;
54
+ sentPaneIds.push(paneId);
55
+ log?.(`OC-RESUME ${paneId} ${r.cmd ?? "resume"}`);
56
+ }
57
+ }
58
+ return { sent, total, sentPaneIds };
59
+ }
60
+ export function notifyResumeWave(workspace, reason, sent, total, meta) {
61
+ const ipLine = meta?.toIp && meta.fromIp !== meta.toIp
62
+ ? `Carrier ${meta.fromIp ?? "?"} -> ${meta.toIp}. `
63
+ : meta?.toIp
64
+ ? `Carrier ${meta.toIp}. `
65
+ : "";
66
+ if (sent > 0) {
67
+ runInboxDesktopNotifySync(workspace, {
68
+ phase: "sent",
69
+ topic: "OC resume",
70
+ sessionAbout: `${ipLine}Resume pasted to ${sent}/${total} OpenCode panes (${reason}).`,
71
+ check: RESUME_ACK_HOWTO,
72
+ });
73
+ return;
74
+ }
75
+ if (total > 0) {
76
+ runInboxDesktopNotifySync(workspace, {
77
+ phase: "incomplete",
78
+ topic: "OC resume",
79
+ sessionAbout: `${ipLine}Found ${total} OC panes but resume was not delivered (${reason}).`,
80
+ check: "Check OC panes manually — may be busy or keyboard-locked.",
81
+ });
82
+ }
83
+ }
84
+ //# sourceMappingURL=oc-resume.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oc-resume.js","sourceRoot":"","sources":["../../src/connectivity/oc-resume.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { MeshOrchestratorCtx } from "../orchestrator/mesh-orchestrator.js";
2
+ export interface DeliveryHoldResult {
3
+ hold: boolean;
4
+ reason?: string;
5
+ }
6
+ /** Gate peer/inbox inject: OC limit, proxy-down (OC only), context-not-ready (post-replace). */
7
+ export declare function deliveryHoldForPane(ctx: MeshOrchestratorCtx, targetPane: string, opts?: {
8
+ isColdStart?: boolean;
9
+ allowCheckbackComms?: boolean;
10
+ }): DeliveryHoldResult;
11
+ //# sourceMappingURL=delivery-hold.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-hold.d.ts","sourceRoot":"","sources":["../../src/inbox/delivery-hold.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAEhF,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAQD,gGAAgG;AAChG,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,mBAAmB,EACxB,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAAO,GAClE,kBAAkB,CAwBpB"}
@@ -0,0 +1,34 @@
1
+ import { capturePaneSnapshot, hasDeliveredColdStartPeer, hasPendingColdStartPeer, isPaneContextReady, } from "@seat-mesh/tmux";
2
+ function isOpenCodePane(registry, paneId) {
3
+ const snap = capturePaneSnapshot(paneId);
4
+ if (!snap)
5
+ return false;
6
+ return registry.detect(snap)?.id === "opencode";
7
+ }
8
+ /** Gate peer/inbox inject: OC limit, proxy-down (OC only), context-not-ready (post-replace). */
9
+ export function deliveryHoldForPane(ctx, targetPane, opts = {}) {
10
+ if (ctx.ocLimitedPaneIds.has(targetPane)) {
11
+ return { hold: true, reason: "held:limit" };
12
+ }
13
+ if (ctx.proxyDownActive && isOpenCodePane(ctx.registry, targetPane)) {
14
+ return { hold: true, reason: "held:proxy-down" };
15
+ }
16
+ if (!opts.isColdStart) {
17
+ const pending = hasPendingColdStartPeer(ctx.loaded, targetPane);
18
+ const ready = isPaneContextReady(ctx.loaded, targetPane);
19
+ if (!ready && pending) {
20
+ if (opts.allowCheckbackComms &&
21
+ hasDeliveredColdStartPeer(ctx.loaded, targetPane)) {
22
+ // Duplicate FRESH SUMMON queued — Check:/room verify must not wedge forever.
23
+ }
24
+ else {
25
+ return { hold: true, reason: "held:context-pending" };
26
+ }
27
+ }
28
+ else if (!ready) {
29
+ return { hold: true, reason: "held:context-pending" };
30
+ }
31
+ }
32
+ return { hold: false };
33
+ }
34
+ //# sourceMappingURL=delivery-hold.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-hold.js","sourceRoot":"","sources":["../../src/inbox/delivery-hold.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AASzB,SAAS,cAAc,CAAC,QAA0B,EAAE,MAAc;IAChE,MAAM,IAAI,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACzC,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACxB,OAAO,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,UAAU,CAAC;AAClD,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,mBAAmB,CACjC,GAAwB,EACxB,UAAkB,EAClB,OAAiE,EAAE;IAEnE,IAAI,GAAG,CAAC,gBAAgB,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;QACzC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;IAC9C,CAAC;IACD,IAAI,GAAG,CAAC,eAAe,IAAI,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,CAAC;QACpE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC;IACnD,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,uBAAuB,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAChE,MAAM,KAAK,GAAG,kBAAkB,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACzD,IAAI,CAAC,KAAK,IAAI,OAAO,EAAE,CAAC;YACtB,IACE,IAAI,CAAC,mBAAmB;gBACxB,yBAAyB,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,EACjD,CAAC;gBACD,6EAA6E;YAC/E,CAAC;iBAAM,CAAC;gBACN,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC;YACxD,CAAC;QACH,CAAC;aAAM,IAAI,CAAC,KAAK,EAAE,CAAC;YAClB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC;QACxD,CAAC;IACH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACzB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=delivery-hold.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-hold.test.d.ts","sourceRoot":"","sources":["../../src/inbox/delivery-hold.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,40 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { deliveryHoldForPane } from "./delivery-hold.js";
3
+ function stubCtx(workspace, opts = {}) {
4
+ return {
5
+ loaded: {
6
+ workspace,
7
+ profileDir: workspace,
8
+ profilePath: "",
9
+ profile: {
10
+ seats: { root: "seats" },
11
+ data: { root: "runtime" },
12
+ state: { meshAgentsJson: "mesh-agents.json", agentsJson: "agents.json" },
13
+ roles: { dir: "roles" },
14
+ },
15
+ workspaceId: "test01",
16
+ sessionName: "mesh-test01",
17
+ },
18
+ registry: { detect: () => null },
19
+ store: {},
20
+ session: "mesh",
21
+ baseWindow: "base",
22
+ workersWindow: "workers",
23
+ minisWindow: "minis",
24
+ log: () => { },
25
+ ocLimitedPaneIds: opts.ocLimited ?? new Set(),
26
+ proxyDownActive: opts.proxyDown ?? false,
27
+ };
28
+ }
29
+ describe("deliveryHoldForPane", () => {
30
+ it("holds non-cold-start when OC limit active on pane", () => {
31
+ const ctx = stubCtx("/tmp/x", { ocLimited: new Set(["%1"]) });
32
+ expect(deliveryHoldForPane(ctx, "%1", { isColdStart: false }).reason).toBe("held:limit");
33
+ expect(deliveryHoldForPane(ctx, "%1", { isColdStart: true }).hold).toBe(true);
34
+ });
35
+ it("passes when pane not limited and no context gate", () => {
36
+ const ctx = stubCtx("/tmp/x");
37
+ expect(deliveryHoldForPane(ctx, "%9", { isColdStart: false }).hold).toBe(false);
38
+ });
39
+ });
40
+ //# sourceMappingURL=delivery-hold.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-hold.test.js","sourceRoot":"","sources":["../../src/inbox/delivery-hold.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAGzD,SAAS,OAAO,CACd,SAAiB,EACjB,OAAyD,EAAE;IAE3D,OAAO;QACL,MAAM,EAAE;YACN,SAAS;YACT,UAAU,EAAE,SAAS;YACrB,WAAW,EAAE,EAAE;YACf,OAAO,EAAE;gBACP,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;gBACxB,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;gBACzB,KAAK,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,UAAU,EAAE,aAAa,EAAE;gBACxE,KAAK,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE;aACI;YAC7B,WAAW,EAAE,QAAQ;YACrB,WAAW,EAAE,aAAa;SACH;QACzB,QAAQ,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,EAAiC;QAC/D,KAAK,EAAE,EAAkC;QACzC,OAAO,EAAE,MAAM;QACf,UAAU,EAAE,MAAM;QAClB,aAAa,EAAE,SAAS;QACxB,WAAW,EAAE,OAAO;QACpB,GAAG,EAAE,GAAG,EAAE,GAAE,CAAC;QACb,gBAAgB,EAAE,IAAI,CAAC,SAAS,IAAI,IAAI,GAAG,EAAE;QAC7C,eAAe,EAAE,IAAI,CAAC,SAAS,IAAI,KAAK;KACzC,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;QAC9D,MAAM,CAAC,mBAAmB,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACzF,MAAM,CAAC,mBAAmB,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC9B,MAAM,CAAC,mBAAmB,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { QueueStore } from "../store/create-queue-store.js";
2
+ /** Pending inject pressure (peer queue + armed checkbacks on this pane). */
3
+ export declare const INBOX_OVERLOAD_THRESHOLD = 25;
4
+ export declare const INBOX_OVERLOAD_COOLDOWN_MS: number;
5
+ export declare function resetInboxOverloadStateForTests(): void;
6
+ export declare function countInboxTriggersForPane(store: QueueStore, paneId: string): number;
7
+ export declare function overloadCooldownRemainingMs(paneId: string, nowMs?: number): number;
8
+ export declare function overloadWarnMessage(count: number): string;
9
+ export interface InboxOverloadEval {
10
+ hold: boolean;
11
+ reason?: string;
12
+ count: number;
13
+ /** Deliver once when entering cooldown (use force inject). */
14
+ warn?: boolean;
15
+ warnMessage?: string;
16
+ }
17
+ /** Rising edge at >= threshold starts 10m cooldown; all injects held until it expires. */
18
+ export declare function evaluateInboxOverload(store: QueueStore, paneId: string, nowMs?: number): InboxOverloadEval;
19
+ //# sourceMappingURL=inbox-overload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbox-overload.d.ts","sourceRoot":"","sources":["../../src/inbox/inbox-overload.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAGjE,4EAA4E;AAC5E,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAE3C,eAAO,MAAM,0BAA0B,QAAiB,CAAC;AAIzD,wBAAgB,+BAA+B,IAAI,IAAI,CAEtD;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAGnF;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,SAAa,GAAG,MAAM,CAGtF;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMzD;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,0FAA0F;AAC1F,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,MAAM,EACd,KAAK,SAAa,GACjB,iBAAiB,CAuBnB"}