@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,45 @@
1
+ import { countPeerPendingForPane } from "../peer/peer-pending.js";
2
+ /** Pending inject pressure (peer queue + armed checkbacks on this pane). */
3
+ export const INBOX_OVERLOAD_THRESHOLD = 25;
4
+ export const INBOX_OVERLOAD_COOLDOWN_MS = 10 * 60 * 1000;
5
+ const paneCooldownUntil = new Map();
6
+ export function resetInboxOverloadStateForTests() {
7
+ paneCooldownUntil.clear();
8
+ }
9
+ export function countInboxTriggersForPane(store, paneId) {
10
+ // Checkbacks are scheduled polls — counting them caused overload self-lock (cb wedge).
11
+ return countPeerPendingForPane(store, paneId);
12
+ }
13
+ export function overloadCooldownRemainingMs(paneId, nowMs = Date.now()) {
14
+ const until = paneCooldownUntil.get(paneId) ?? 0;
15
+ return Math.max(0, until - nowMs);
16
+ }
17
+ export function overloadWarnMessage(count) {
18
+ const mins = Math.round(INBOX_OVERLOAD_COOLDOWN_MS / 60_000);
19
+ return (`[mesh-inbox] OVERLOAD: ${count} pending inbox triggers on this pane — ` +
20
+ `you may be overloaded or spammed. Daemon pauses injects here for ${mins} minutes.`);
21
+ }
22
+ /** Rising edge at >= threshold starts 10m cooldown; all injects held until it expires. */
23
+ export function evaluateInboxOverload(store, paneId, nowMs = Date.now()) {
24
+ const count = countInboxTriggersForPane(store, paneId);
25
+ const remaining = overloadCooldownRemainingMs(paneId, nowMs);
26
+ if (remaining > 0) {
27
+ return {
28
+ hold: true,
29
+ reason: `held:overload-cooldown:${Math.ceil(remaining / 1000)}s`,
30
+ count,
31
+ };
32
+ }
33
+ if (count >= INBOX_OVERLOAD_THRESHOLD) {
34
+ paneCooldownUntil.set(paneId, nowMs + INBOX_OVERLOAD_COOLDOWN_MS);
35
+ return {
36
+ hold: true,
37
+ reason: "held:overload-cooldown",
38
+ count,
39
+ warn: true,
40
+ warnMessage: overloadWarnMessage(count),
41
+ };
42
+ }
43
+ return { hold: false, count };
44
+ }
45
+ //# sourceMappingURL=inbox-overload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbox-overload.js","sourceRoot":"","sources":["../../src/inbox/inbox-overload.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAElE,4EAA4E;AAC5E,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAE3C,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAEzD,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAkB,CAAC;AAEpD,MAAM,UAAU,+BAA+B;IAC7C,iBAAiB,CAAC,KAAK,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,KAAiB,EAAE,MAAc;IACzE,uFAAuF;IACvF,OAAO,uBAAuB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,MAAc,EAAE,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE;IAC5E,MAAM,KAAK,GAAG,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACjD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,0BAA0B,GAAG,MAAM,CAAC,CAAC;IAC7D,OAAO,CACL,0BAA0B,KAAK,yCAAyC;QACxE,oEAAoE,IAAI,WAAW,CACpF,CAAC;AACJ,CAAC;AAWD,0FAA0F;AAC1F,MAAM,UAAU,qBAAqB,CACnC,KAAiB,EACjB,MAAc,EACd,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE;IAElB,MAAM,KAAK,GAAG,yBAAyB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,2BAA2B,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC7D,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;QAClB,OAAO;YACL,IAAI,EAAE,IAAI;YACV,MAAM,EAAE,0BAA0B,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG;YAChE,KAAK;SACN,CAAC;IACJ,CAAC;IAED,IAAI,KAAK,IAAI,wBAAwB,EAAE,CAAC;QACtC,iBAAiB,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,GAAG,0BAA0B,CAAC,CAAC;QAClE,OAAO;YACL,IAAI,EAAE,IAAI;YACV,MAAM,EAAE,wBAAwB;YAChC,KAAK;YACL,IAAI,EAAE,IAAI;YACV,WAAW,EAAE,mBAAmB,CAAC,KAAK,CAAC;SACxC,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAChC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=inbox-overload.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbox-overload.test.d.ts","sourceRoot":"","sources":["../../src/inbox/inbox-overload.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,43 @@
1
+ import { describe, expect, it, beforeEach } from "vitest";
2
+ import { INBOX_OVERLOAD_COOLDOWN_MS, INBOX_OVERLOAD_THRESHOLD, countInboxTriggersForPane, evaluateInboxOverload, overloadCooldownRemainingMs, resetInboxOverloadStateForTests, } from "./inbox-overload.js";
3
+ function mockStore(peer, checkbacks) {
4
+ return {
5
+ readPeer: () => peer,
6
+ readCheckbacks: () => checkbacks,
7
+ };
8
+ }
9
+ describe("inbox overload", () => {
10
+ beforeEach(() => resetInboxOverloadStateForTests());
11
+ it("counts unsent peer only (not armed checkbacks)", () => {
12
+ const store = mockStore([{ targetPane: "%1", sent: false }], [{ status: "active", ownerPane: "%1" }]);
13
+ expect(countInboxTriggersForPane(store, "%1")).toBe(1);
14
+ });
15
+ it("starts cooldown and warns at threshold", () => {
16
+ const peers = Array.from({ length: INBOX_OVERLOAD_THRESHOLD }, (_, i) => ({
17
+ targetPane: "%9",
18
+ sent: false,
19
+ id: `p${i}`,
20
+ }));
21
+ const store = mockStore(peers, []);
22
+ const t0 = 1_000_000;
23
+ const r = evaluateInboxOverload(store, "%9", t0);
24
+ expect(r.hold).toBe(true);
25
+ expect(r.warn).toBe(true);
26
+ expect(r.warnMessage).toMatch(/OVERLOAD/);
27
+ expect(overloadCooldownRemainingMs("%9", t0 + 1000)).toBe(INBOX_OVERLOAD_COOLDOWN_MS - 1000);
28
+ });
29
+ it("holds during cooldown even if count drops", () => {
30
+ const peers = Array.from({ length: INBOX_OVERLOAD_THRESHOLD }, (_, i) => ({
31
+ targetPane: "%9",
32
+ sent: false,
33
+ id: `p${i}`,
34
+ }));
35
+ const store = mockStore(peers, []);
36
+ const t0 = 2_000_000;
37
+ evaluateInboxOverload(store, "%9", t0);
38
+ const r = evaluateInboxOverload(mockStore([], []), "%9", t0 + 60_000);
39
+ expect(r.hold).toBe(true);
40
+ expect(r.warn).toBeUndefined();
41
+ });
42
+ });
43
+ //# sourceMappingURL=inbox-overload.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbox-overload.test.js","sourceRoot":"","sources":["../../src/inbox/inbox-overload.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { LoadedProfile, PaneOpRow, ProviderRegistry } from "@seat-mesh/core";
2
+ import type { QueueStore } from "../store/create-queue-store.js";
3
+ export interface PaneOpsDrainCtx {
4
+ loaded: LoadedProfile;
5
+ registry: ProviderRegistry;
6
+ store: QueueStore;
7
+ log: (line: string) => void;
8
+ isBusy: () => boolean;
9
+ setBusy: (v: boolean) => void;
10
+ }
11
+ export declare function drainPaneOpsOnce(ctx: PaneOpsDrainCtx): boolean;
12
+ export declare function enqueuePaneOp(store: QueueStore, kind: PaneOpRow["kind"], who: string, summary: string, payload: Record<string, unknown>): PaneOpRow;
13
+ export declare function queueAheadCount(store: QueueStore): number;
14
+ //# sourceMappingURL=pane-ops-drain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pane-ops-drain.d.ts","sourceRoot":"","sources":["../../src/inbox/pane-ops-drain.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAElF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAEjE,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,KAAK,EAAE,UAAU,CAAC;IAClB,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,MAAM,EAAE,MAAM,OAAO,CAAC;IACtB,OAAO,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CAC/B;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAiC9D;AAED,wBAAgB,aAAa,CAC3B,KAAK,EAAE,UAAU,EACjB,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,EACvB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,SAAS,CAYX;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEzD"}
@@ -0,0 +1,53 @@
1
+ import { executePaneOp, saveMeshSession } from "@seat-mesh/tmux";
2
+ export function drainPaneOpsOnce(ctx) {
3
+ if (ctx.isBusy())
4
+ return false;
5
+ const rows = ctx.store.readPaneOps();
6
+ const row = rows.find((r) => r.status === "pending");
7
+ if (!row)
8
+ return false;
9
+ ctx.setBusy(true);
10
+ row.status = "running";
11
+ ctx.store.updatePaneOp(row);
12
+ ctx.log(`PANE-OP start ${row.id.slice(0, 8)} ${row.kind} who=${row.who} — ${row.summary}`);
13
+ const result = executePaneOp(ctx.loaded, row);
14
+ row.finishedAt = new Date().toISOString();
15
+ if (result.ok) {
16
+ row.status = "done";
17
+ ctx.log(`PANE-OP done ${row.id.slice(0, 8)} ${row.kind}`);
18
+ }
19
+ else {
20
+ row.status = "failed";
21
+ row.error = result.error;
22
+ ctx.log(`PANE-OP fail ${row.id.slice(0, 8)} ${row.kind}: ${result.error ?? "?"}`);
23
+ }
24
+ ctx.store.updatePaneOp(row);
25
+ if (result.ok) {
26
+ try {
27
+ const saved = saveMeshSession(ctx.loaded, ctx.registry);
28
+ ctx.log(`PANE-OP saved ${saved}`);
29
+ }
30
+ catch (e) {
31
+ ctx.log(`PANE-OP save warn: ${e.message}`);
32
+ }
33
+ }
34
+ ctx.setBusy(false);
35
+ return true;
36
+ }
37
+ export function enqueuePaneOp(store, kind, who, summary, payload) {
38
+ const row = {
39
+ id: crypto.randomUUID(),
40
+ at: new Date().toISOString(),
41
+ kind,
42
+ who,
43
+ summary,
44
+ payload,
45
+ status: "pending",
46
+ };
47
+ store.appendPaneOp(row);
48
+ return row;
49
+ }
50
+ export function queueAheadCount(store) {
51
+ return store.readPaneOps().filter((r) => r.status === "pending" || r.status === "running").length;
52
+ }
53
+ //# sourceMappingURL=pane-ops-drain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pane-ops-drain.js","sourceRoot":"","sources":["../../src/inbox/pane-ops-drain.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export * from "./orchestrator.js";
2
- export * from "./workers.js";
1
+ export * from "./orchestrator/orchestrator.js";
2
+ export * from "./orchestrator/workers.js";
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gCAAgC,CAAC;AAC/C,cAAc,2BAA2B,CAAC"}
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export * from "./orchestrator.js";
2
- export * from "./workers.js";
1
+ export * from "./orchestrator/orchestrator.js";
2
+ export * from "./orchestrator/workers.js";
3
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gCAAgC,CAAC;AAC/C,cAAc,2BAA2B,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { ComposerState } from "@seat-mesh/core";
2
+ /** Post-generate / empty-composer settle (manager + secretary only). */
3
+ export declare const COORD_IDLE_SETTLE_MS: number;
4
+ /** TEMP bypass: profile daemon.skipTypingGate or MESH_INBOX_SKIP_TYPING_GATE=1 */
5
+ export declare function configureInboxTypingGate(opts: {
6
+ skip?: boolean;
7
+ }): void;
8
+ export declare function inboxSkipTypingGate(): boolean;
9
+ export type CoordGatePhase = "idle" | "wait-busy" | "wait-typing" | "wait-settle" | "wait-not-ready" | "plain_shell";
10
+ export interface CoordGateResult {
11
+ phase: CoordGatePhase;
12
+ canDeliver: boolean;
13
+ settleInSec?: number;
14
+ draftFp?: string;
15
+ }
16
+ /** Reset gate clocks (tests). */
17
+ export declare function resetCoordGateState(paneId?: string): void;
18
+ /**
19
+ * Manager/secretary inject gate: never paste while generating or typing;
20
+ * after generate ends, wait full COORD_IDLE_SETTLE_MS before idle inject.
21
+ */
22
+ export declare function classifyCoordDelivery(paneId: string, state: ComposerState, captureTail: string, providerId: string, nowMs?: number): CoordGateResult;
23
+ //# sourceMappingURL=compose-gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose-gate.d.ts","sourceRoot":"","sources":["../../src/inject/compose-gate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGrD,wEAAwE;AACxE,eAAO,MAAM,oBAAoB,QAAwD,CAAC;AAI1F,kFAAkF;AAClF,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAEvE;AAED,wBAAgB,mBAAmB,IAAI,OAAO,CAI7C;AAED,MAAM,MAAM,cAAc,GACtB,MAAM,GACN,WAAW,GACX,aAAa,GACb,aAAa,GACb,gBAAgB,GAChB,aAAa,CAAC;AAElB,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,cAAc,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAmBD,iCAAiC;AACjC,wBAAgB,mBAAmB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAGzD;AA4BD;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,aAAa,EACpB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,KAAK,SAAa,GACjB,eAAe,CAwDjB"}
@@ -0,0 +1,113 @@
1
+ import { coordComposerDraft } from "@seat-mesh/providers";
2
+ /** Post-generate / empty-composer settle (manager + secretary only). */
3
+ export const COORD_IDLE_SETTLE_MS = Number(process.env.MESH_INBOX_IDLE_SETTLE_MS ?? 1500);
4
+ let profileSkipTypingGate = false;
5
+ /** TEMP bypass: profile daemon.skipTypingGate or MESH_INBOX_SKIP_TYPING_GATE=1 */
6
+ export function configureInboxTypingGate(opts) {
7
+ profileSkipTypingGate = opts.skip === true;
8
+ }
9
+ export function inboxSkipTypingGate() {
10
+ if (profileSkipTypingGate)
11
+ return true;
12
+ const v = process.env.MESH_INBOX_SKIP_TYPING_GATE;
13
+ return v === "1" || v === "true";
14
+ }
15
+ const gateByPane = new Map();
16
+ function gateState(paneId) {
17
+ let s = gateByPane.get(paneId);
18
+ if (!s) {
19
+ s = { wasBusy: false, lastBusyEndedAt: 0, idleReadySince: 0 };
20
+ gateByPane.set(paneId, s);
21
+ }
22
+ return s;
23
+ }
24
+ /** Reset gate clocks (tests). */
25
+ export function resetCoordGateState(paneId) {
26
+ if (paneId)
27
+ gateByPane.delete(paneId);
28
+ else
29
+ gateByPane.clear();
30
+ }
31
+ function composerIdleReady(state, captureTail, providerId) {
32
+ if (state.phase === "plain_shell" || state.phase === "limit")
33
+ return false;
34
+ if (state.phase === "busy" || state.phase === "typing")
35
+ return false;
36
+ const draft = state.draftFingerprint?.trim() ||
37
+ coordComposerDraft(stripMeshForDraft(captureTail), providerId);
38
+ if (draft)
39
+ return false;
40
+ return state.phase === "empty" || state.phase === "afk";
41
+ }
42
+ /** Drop mesh-owned chrome before draft sniff (checkback box uses → [mesh-inbox]). */
43
+ function stripMeshForDraft(captureTail) {
44
+ return captureTail
45
+ .split("\n")
46
+ .filter((line) => {
47
+ const t = line.trim();
48
+ if (!t)
49
+ return true;
50
+ if (/\[mesh-inbox/i.test(t))
51
+ return false;
52
+ if (/^intent=/i.test(t))
53
+ return false;
54
+ if (/^Check:/i.test(t))
55
+ return false;
56
+ if (/\bOC-LIMIT:/i.test(t))
57
+ return false;
58
+ return true;
59
+ })
60
+ .join("\n");
61
+ }
62
+ /**
63
+ * Manager/secretary inject gate: never paste while generating or typing;
64
+ * after generate ends, wait full COORD_IDLE_SETTLE_MS before idle inject.
65
+ */
66
+ export function classifyCoordDelivery(paneId, state, captureTail, providerId, nowMs = Date.now()) {
67
+ const st = gateState(paneId);
68
+ if (state.phase === "plain_shell") {
69
+ return { phase: "plain_shell", canDeliver: false };
70
+ }
71
+ if (state.phase === "limit") {
72
+ return { phase: "wait-not-ready", canDeliver: false };
73
+ }
74
+ if (state.phase === "busy") {
75
+ st.wasBusy = true;
76
+ st.idleReadySince = 0;
77
+ return { phase: "wait-busy", canDeliver: false };
78
+ }
79
+ if (st.wasBusy) {
80
+ st.wasBusy = false;
81
+ st.lastBusyEndedAt = nowMs;
82
+ st.idleReadySince = 0;
83
+ }
84
+ const draftFp = state.draftFingerprint?.trim() ||
85
+ coordComposerDraft(stripMeshForDraft(captureTail), providerId) ||
86
+ undefined;
87
+ const holdTyping = !inboxSkipTypingGate() && (state.phase === "typing" || Boolean(draftFp));
88
+ if (holdTyping) {
89
+ st.idleReadySince = 0;
90
+ return { phase: "wait-typing", canDeliver: false, draftFp };
91
+ }
92
+ if (!composerIdleReady(state, captureTail, providerId)) {
93
+ st.idleReadySince = 0;
94
+ return { phase: "wait-not-ready", canDeliver: false };
95
+ }
96
+ if (!st.idleReadySince)
97
+ st.idleReadySince = nowMs;
98
+ const settleSec = COORD_IDLE_SETTLE_MS / 1000;
99
+ const emptySettled = (nowMs - st.idleReadySince) / 1000;
100
+ const busySettled = st.lastBusyEndedAt
101
+ ? (nowMs - st.lastBusyEndedAt) / 1000
102
+ : settleSec;
103
+ const settled = Math.min(emptySettled, busySettled);
104
+ if (settled < settleSec) {
105
+ return {
106
+ phase: "wait-settle",
107
+ canDeliver: false,
108
+ settleInSec: Math.max(0, Math.ceil(settleSec - settled)),
109
+ };
110
+ }
111
+ return { phase: "idle", canDeliver: true };
112
+ }
113
+ //# sourceMappingURL=compose-gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose-gate.js","sourceRoot":"","sources":["../../src/inject/compose-gate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=compose-gate.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose-gate.test.d.ts","sourceRoot":"","sources":["../../src/inject/compose-gate.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,35 @@
1
+ import { describe, expect, it, beforeEach } from "vitest";
2
+ import { classifyCoordDelivery, COORD_IDLE_SETTLE_MS, resetCoordGateState, } from "./compose-gate.js";
3
+ const PANE = "%99";
4
+ describe("classifyCoordDelivery", () => {
5
+ beforeEach(() => resetCoordGateState(PANE));
6
+ it("holds while busy (generating)", () => {
7
+ const r = classifyCoordDelivery(PANE, { phase: "busy", busyLabel: "Thinking" }, "", "opencode", 1_000_000);
8
+ expect(r.canDeliver).toBe(false);
9
+ expect(r.phase).toBe("wait-busy");
10
+ });
11
+ it("holds while typing / draft", () => {
12
+ const r = classifyCoordDelivery(PANE, { phase: "typing", draftFingerprint: "fix the inbox" }, "", "cursor-agent", 1_000_000);
13
+ expect(r.canDeliver).toBe(false);
14
+ expect(r.phase).toBe("wait-typing");
15
+ });
16
+ it("waits settle after busy ends", () => {
17
+ const t0 = 1_000_000;
18
+ classifyCoordDelivery(PANE, { phase: "busy" }, "", "opencode", t0);
19
+ const r = classifyCoordDelivery(PANE, { phase: "empty" }, "ctrl+p commands\nAsk anything", "opencode", t0 + 1000);
20
+ expect(r.canDeliver).toBe(false);
21
+ expect(r.phase).toBe("wait-settle");
22
+ expect(r.settleInSec).toBeGreaterThan(0);
23
+ });
24
+ it("delivers after full settle window", () => {
25
+ const t0 = 2_000_000;
26
+ const tEdge = t0 + 100;
27
+ classifyCoordDelivery(PANE, { phase: "busy" }, "", "opencode", t0);
28
+ // Rising edge: first poll after generate stops starts both settle clocks.
29
+ classifyCoordDelivery(PANE, { phase: "empty" }, "ctrl+p commands", "opencode", tEdge);
30
+ const r = classifyCoordDelivery(PANE, { phase: "empty" }, "ctrl+p commands", "opencode", tEdge + COORD_IDLE_SETTLE_MS + 100);
31
+ expect(r.canDeliver).toBe(true);
32
+ expect(r.phase).toBe("idle");
33
+ });
34
+ });
35
+ //# sourceMappingURL=compose-gate.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose-gate.test.js","sourceRoot":"","sources":["../../src/inject/compose-gate.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import type { ComposerState, LoadedProfile, ProviderRegistry } from "@seat-mesh/core";
2
+ import { type MeshInboxIntent } from "@seat-mesh/core";
3
+ /** Soft post-check: injected text visible in scrollback (best-effort; steer may hide). */
4
+ export declare function verifyInjectVisible(paneId: string, message: string): boolean;
5
+ /** When may the daemon paste into this pane? */
6
+ export declare function canDeliverNow(state: ComposerState, captureTail: string, providerId: string): boolean;
7
+ /** Follow-up UI detector only — never a delivery bypass (steals the next user turn). */
8
+ export declare function isCursorFollowUpSteer(state: ComposerState, captureTail: string, providerId: string): boolean;
9
+ /** Only these words may paste onto a busy/typing pane (not force/roomPing/ACK). */
10
+ export declare function isExplicitHubOverride(message: string): boolean;
11
+ export type DeliverResult = {
12
+ ok: true;
13
+ providerId: string;
14
+ mode: "idle" | "steer";
15
+ verified: boolean;
16
+ } | {
17
+ ok: false;
18
+ reason: string;
19
+ };
20
+ export interface DeliverOptions {
21
+ /** Skip post-inject scrollback verify (checkback renew path). */
22
+ skipVerify?: boolean;
23
+ /** ACK/FYI class — deliver when busy; hub stays rank-1 (PEER-BACKLOG-SPEC). */
24
+ lightweight?: boolean;
25
+ /** Room thin-ping — bypass manager/secretary coord idle-settle gate. */
26
+ roomPing?: boolean;
27
+ /** Passive STATUS / supervise tick — skip compose-gate (operator: force-send to secretary). */
28
+ force?: boolean;
29
+ /** Machine intent for coord filtering (checkback-verify, continue, …). */
30
+ intent?: MeshInboxIntent;
31
+ /** Resolves layout.base.humanCoTyped for the co-typed-pane gate (FQ-inject-co-typed-pane). */
32
+ loaded?: LoadedProfile;
33
+ /** Workspace root (orchestrator context; no desktop toast on co-typed hold). */
34
+ workspace?: string;
35
+ }
36
+ /** operator standing: every daemon paste is tagged so coord panes can filter (draft-preserve, STATUS). */
37
+ export declare function stampDaemonInject(message: string, intent?: MeshInboxIntent): string;
38
+ export declare function deliverToPane(paneId: string, message: string, registry: ProviderRegistry, opts?: DeliverOptions): DeliverResult;
39
+ //# sourceMappingURL=inject-delivery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inject-delivery.d.ts","sourceRoot":"","sources":["../../src/inject/inject-delivery.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACtF,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,iBAAiB,CAAC;AAczB,0FAA0F;AAC1F,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAU5E;AAED,gDAAgD;AAChD,wBAAgB,aAAa,CAC3B,KAAK,EAAE,aAAa,EACpB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GACjB,OAAO,CAgBT;AAmBD,wFAAwF;AACxF,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,aAAa,EACpB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GACjB,OAAO,CAKT;AAED,mFAAmF;AACnF,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GAC3E;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAElC,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+FAA+F;IAC/F,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,8FAA8F;IAC9F,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,gFAAgF;IAChF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,0GAA0G;AAC1G,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,MAAM,CAUnF;AAED,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,gBAAgB,EAC1B,IAAI,GAAE,cAAmB,GACxB,aAAa,CAgGf"}
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Sole daemon inject path: registry.detect -> provider.injectPlan -> injectToPane.
3
+ */
4
+ import { spawnSync } from "node:child_process";
5
+ import { formatMeshInboxStamp, isCoordKind, isHumanCoTypedColumn, MESH_INBOX_ROOM_TAG, MESH_INBOX_TAG, stripReplyPeerFooter, } from "@seat-mesh/core";
6
+ import { capturePaneSnapshot, injectToPane, paneMetaForPane, } from "@seat-mesh/tmux";
7
+ import { classifyCoordDelivery, inboxSkipTypingGate } from "./compose-gate.js";
8
+ import { isAckClassPeer } from "../peer/peer-backlog.js";
9
+ function sleepMs(ms) {
10
+ if (ms <= 0)
11
+ return;
12
+ spawnSync("sleep", [String(ms / 1000)]);
13
+ }
14
+ /** Soft post-check: injected text visible in scrollback (best-effort; steer may hide). */
15
+ export function verifyInjectVisible(paneId, message) {
16
+ sleepMs(350);
17
+ const snap = capturePaneSnapshot(paneId);
18
+ if (!snap)
19
+ return false;
20
+ const tail = snap.captureTail;
21
+ const body = message.trim();
22
+ if (!body)
23
+ return false;
24
+ const head = body.slice(0, 48);
25
+ const tailSlice = body.length > 48 ? body.slice(-48) : body;
26
+ return tail.includes(head) || tail.includes(tailSlice);
27
+ }
28
+ /** When may the daemon paste into this pane? */
29
+ export function canDeliverNow(state, captureTail, providerId) {
30
+ if (state.phase === "plain_shell" || state.phase === "limit")
31
+ return false;
32
+ if (state.phase === "empty" || state.phase === "afk")
33
+ return true;
34
+ if (providerId === "cursor-agent" || providerId === "agent") {
35
+ // Follow-up box is NOT a delivery lane. Steer-paste there becomes the
36
+ // next user turn and the agent drops the in-flight instruction.
37
+ return false;
38
+ }
39
+ if (providerId === "opencode") {
40
+ // empty/afk already returned true above; remaining phases are busy/typing.
41
+ return false;
42
+ }
43
+ return false;
44
+ }
45
+ function isCoordPane(paneId) {
46
+ const meta = paneMetaForPane(paneId);
47
+ return Boolean(meta?.role && isCoordKind(meta.role));
48
+ }
49
+ /**
50
+ * Human-co-typed coord pane (FQ-inject-co-typed-pane, profile humanCoTyped) — a
51
+ * human directly types in this same pane as the CLI, so even a "thin" room
52
+ * ping must never bypass the busy/typing gate the way it does for pure
53
+ * agent-to-agent coord panes (that bypass was the observed footer-bleed).
54
+ */
55
+ function isHumanCoTypedPane(paneId, loaded) {
56
+ const meta = paneMetaForPane(paneId);
57
+ if (!meta?.role)
58
+ return false;
59
+ return isHumanCoTypedColumn(meta.role, loaded?.profile.layout);
60
+ }
61
+ /** Follow-up UI detector only — never a delivery bypass (steals the next user turn). */
62
+ export function isCursorFollowUpSteer(state, captureTail, providerId) {
63
+ if (providerId === "claude")
64
+ return false;
65
+ if (providerId !== "cursor-agent" && providerId !== "agent")
66
+ return false;
67
+ if (state.phase === "busy" && state.busyLabel === "follow-up")
68
+ return true;
69
+ return /Add a follow-up|ctrl\+c to stop/.test(captureTail);
70
+ }
71
+ /** Only these words may paste onto a busy/typing pane (not force/roomPing/ACK). */
72
+ export function isExplicitHubOverride(message) {
73
+ return /\bPRIORITY\b|\bSTOP other work\b/i.test(message);
74
+ }
75
+ /** operator standing: every daemon paste is tagged so coord panes can filter (draft-preserve, STATUS). */
76
+ export function stampDaemonInject(message, intent) {
77
+ let body = message;
78
+ if (intent && intent !== "assign") {
79
+ body = stripReplyPeerFooter(body);
80
+ }
81
+ const t = body.trimStart();
82
+ if (t.startsWith(MESH_INBOX_TAG) || t.startsWith(MESH_INBOX_ROOM_TAG)) {
83
+ return formatMeshInboxStamp(body, intent);
84
+ }
85
+ return formatMeshInboxStamp(`${MESH_INBOX_TAG} ${t}`, intent);
86
+ }
87
+ export function deliverToPane(paneId, message, registry, opts = {}) {
88
+ message = stampDaemonInject(message, opts.intent);
89
+ const snap = capturePaneSnapshot(paneId);
90
+ if (!snap)
91
+ return { ok: false, reason: "no_snapshot" };
92
+ const prov = registry.detect(snap);
93
+ if (!prov)
94
+ return { ok: false, reason: "held:no_provider" };
95
+ const state = prov.composerState(snap);
96
+ // Empty seat / rate-limit wall — never paste into zsh. Queue until a real CLI loads.
97
+ // Lightweight / roomPing used to skip canDeliverNow and dump [mesh-inbox] into shells.
98
+ if (state.phase === "plain_shell" || state.phase === "limit") {
99
+ return { ok: false, reason: `held:${state.phase}` };
100
+ }
101
+ const coord = isCoordPane(paneId);
102
+ const coTyped = coord && isHumanCoTypedPane(paneId, opts.loaded);
103
+ // Hard floor: busy/typing never gets a substance paste. ACK/FYI may land in
104
+ // Cursor follow-up (same rule as peer --direct) so secretary sees ACKs while
105
+ // generating — backlog alone looked like "never sent".
106
+ const typingHold = state.phase === "typing" && !inboxSkipTypingGate();
107
+ const busyHold = state.phase === "busy";
108
+ const followUpOpen = state.busyLabel === "follow-up" ||
109
+ /Add a follow-up|ctrl\+c to stop/.test(snap.captureTail);
110
+ const ackFollowUp = isAckClassPeer(message) &&
111
+ followUpOpen &&
112
+ (prov.id === "cursor-agent" || prov.id === "agent");
113
+ if ((busyHold || typingHold) && !ackFollowUp) {
114
+ if (coTyped || !isExplicitHubOverride(message)) {
115
+ const phase = busyHold ? "busy" : "typing";
116
+ return {
117
+ ok: false,
118
+ reason: coTyped ? `held:cotyped:${phase}` : `held:${phase}`,
119
+ };
120
+ }
121
+ }
122
+ // Co-typed panes never get the thin-room-ping bypass either — a "status" ping
123
+ // pasted mid-keystroke is exactly the tty-interleaving bug this gate stops.
124
+ const roomPingBypass = opts.roomPing === true && !coTyped;
125
+ const ackFollowUpBypass = ackFollowUp && !coTyped;
126
+ if (!opts.force && coord && !roomPingBypass && !ackFollowUpBypass) {
127
+ const gate = classifyCoordDelivery(paneId, state, snap.captureTail, prov.id);
128
+ if (!gate.canDeliver) {
129
+ const extra = gate.settleInSec != null
130
+ ? `:settle ${gate.settleInSec}s`
131
+ : gate.draftFp
132
+ ? `:draft`
133
+ : "";
134
+ return { ok: false, reason: `held:coord:${gate.phase}${extra}` };
135
+ }
136
+ }
137
+ else if (!opts.force &&
138
+ !opts.lightweight &&
139
+ !roomPingBypass &&
140
+ !ackFollowUpBypass &&
141
+ !canDeliverNow(state, snap.captureTail, prov.id)) {
142
+ return { ok: false, reason: `held:${state.phase}${state.busyLabel ? `:${state.busyLabel}` : ""}` };
143
+ }
144
+ const steer = ackFollowUp;
145
+ // Co-typed: skip Enter only for non-inbox pastes (human may be mid-draft).
146
+ // Mesh-inbox / room pings MUST submit — otherwise they sit forever as a typing
147
+ // draft and block the pane (manager-2 stuck Verify:/peer footer).
148
+ const meshMail = message.includes("[mesh-inbox") ||
149
+ message.includes("[mesh-inbox-room]") ||
150
+ /\b\[sent:[^\]]+\]/.test(message);
151
+ const plan = {
152
+ ...prov.injectPlan(snap),
153
+ ...(coTyped && !meshMail ? { skipSubmit: true } : {}),
154
+ };
155
+ injectToPane(paneId, message, plan, prov.id, snap.captureTail, snap.captureTailAnsi);
156
+ const mode = steer ? "steer" : "idle";
157
+ // OpenCode TUI often hides pasted prompt in capture-pane tail (verify false negative).
158
+ // Claude: same — footer/redraw can hide paste briefly. Cursor-agent MUST verify
159
+ // except follow-up steer (paste sits under follow-ups; scrollback may lag).
160
+ const verified = opts.skipVerify ||
161
+ prov.id === "opencode" ||
162
+ prov.id === "claude" ||
163
+ mode === "steer" ||
164
+ verifyInjectVisible(paneId, message);
165
+ // Paste already ran — claiming failure re-drains and duplicates in the pane.
166
+ if (!verified) {
167
+ return { ok: true, providerId: prov.id, mode, verified: false };
168
+ }
169
+ return { ok: true, providerId: prov.id, mode, verified };
170
+ }
171
+ //# sourceMappingURL=inject-delivery.js.map