@cluesmith/codev 3.3.1 → 3.3.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 (248) hide show
  1. package/dashboard-dist/assets/{index-D3XaKpZW.js → index-CUIjS_Vb.js} +41 -41
  2. package/dashboard-dist/assets/index-CUIjS_Vb.js.map +1 -0
  3. package/dashboard-dist/assets/index-DnYLy5C_.css +32 -0
  4. package/dashboard-dist/index.html +2 -2
  5. package/dist/agent-farm/cli.d.ts.map +1 -1
  6. package/dist/agent-farm/cli.js +52 -1
  7. package/dist/agent-farm/cli.js.map +1 -1
  8. package/dist/agent-farm/commands/inbox.d.ts.map +1 -1
  9. package/dist/agent-farm/commands/inbox.js +67 -10
  10. package/dist/agent-farm/commands/inbox.js.map +1 -1
  11. package/dist/agent-farm/commands/interrupt.d.ts +4 -1
  12. package/dist/agent-farm/commands/interrupt.d.ts.map +1 -1
  13. package/dist/agent-farm/commands/interrupt.js +6 -3
  14. package/dist/agent-farm/commands/interrupt.js.map +1 -1
  15. package/dist/agent-farm/commands/reset/constants.d.ts +118 -0
  16. package/dist/agent-farm/commands/reset/constants.d.ts.map +1 -1
  17. package/dist/agent-farm/commands/reset/constants.js +118 -0
  18. package/dist/agent-farm/commands/reset/constants.js.map +1 -1
  19. package/dist/agent-farm/commands/reset/context.d.ts +18 -0
  20. package/dist/agent-farm/commands/reset/context.d.ts.map +1 -1
  21. package/dist/agent-farm/commands/reset/context.js +41 -0
  22. package/dist/agent-farm/commands/reset/context.js.map +1 -1
  23. package/dist/agent-farm/commands/reset/receipt.d.ts.map +1 -1
  24. package/dist/agent-farm/commands/reset/receipt.js +16 -5
  25. package/dist/agent-farm/commands/reset/receipt.js.map +1 -1
  26. package/dist/agent-farm/commands/reset/reorient.d.ts +1 -1
  27. package/dist/agent-farm/commands/reset/reorient.d.ts.map +1 -1
  28. package/dist/agent-farm/commands/reset/reorient.js +8 -1
  29. package/dist/agent-farm/commands/reset/reorient.js.map +1 -1
  30. package/dist/agent-farm/commands/reset/self.d.ts +335 -0
  31. package/dist/agent-farm/commands/reset/self.d.ts.map +1 -0
  32. package/dist/agent-farm/commands/reset/self.js +636 -0
  33. package/dist/agent-farm/commands/reset/self.js.map +1 -0
  34. package/dist/agent-farm/commands/reset.d.ts +4 -1
  35. package/dist/agent-farm/commands/reset.d.ts.map +1 -1
  36. package/dist/agent-farm/commands/reset.js +29 -21
  37. package/dist/agent-farm/commands/reset.js.map +1 -1
  38. package/dist/agent-farm/commands/self-refresh.d.ts +60 -0
  39. package/dist/agent-farm/commands/self-refresh.d.ts.map +1 -0
  40. package/dist/agent-farm/commands/self-refresh.js +506 -0
  41. package/dist/agent-farm/commands/self-refresh.js.map +1 -0
  42. package/dist/agent-farm/commands/send.d.ts +28 -0
  43. package/dist/agent-farm/commands/send.d.ts.map +1 -1
  44. package/dist/agent-farm/commands/send.js +90 -7
  45. package/dist/agent-farm/commands/send.js.map +1 -1
  46. package/dist/agent-farm/commands/spawn.d.ts +7 -0
  47. package/dist/agent-farm/commands/spawn.d.ts.map +1 -1
  48. package/dist/agent-farm/commands/spawn.js +13 -1
  49. package/dist/agent-farm/commands/spawn.js.map +1 -1
  50. package/dist/agent-farm/db/index.d.ts +3 -1
  51. package/dist/agent-farm/db/index.d.ts.map +1 -1
  52. package/dist/agent-farm/db/index.js +8 -443
  53. package/dist/agent-farm/db/index.js.map +1 -1
  54. package/dist/agent-farm/db/mailbox.d.ts +47 -7
  55. package/dist/agent-farm/db/mailbox.d.ts.map +1 -1
  56. package/dist/agent-farm/db/mailbox.js +56 -12
  57. package/dist/agent-farm/db/mailbox.js.map +1 -1
  58. package/dist/agent-farm/db/migrations.d.ts +57 -0
  59. package/dist/agent-farm/db/migrations.d.ts.map +1 -0
  60. package/dist/agent-farm/db/migrations.js +530 -0
  61. package/dist/agent-farm/db/migrations.js.map +1 -0
  62. package/dist/agent-farm/db/schema.d.ts +1 -1
  63. package/dist/agent-farm/db/schema.d.ts.map +1 -1
  64. package/dist/agent-farm/db/schema.js +1 -0
  65. package/dist/agent-farm/db/schema.js.map +1 -1
  66. package/dist/agent-farm/db/types.d.ts +22 -0
  67. package/dist/agent-farm/db/types.d.ts.map +1 -1
  68. package/dist/agent-farm/db/types.js.map +1 -1
  69. package/dist/agent-farm/lib/tower-client.d.ts +12 -0
  70. package/dist/agent-farm/lib/tower-client.d.ts.map +1 -1
  71. package/dist/agent-farm/lib/tower-client.js +12 -0
  72. package/dist/agent-farm/lib/tower-client.js.map +1 -1
  73. package/dist/agent-farm/lib/tunnel-client.d.ts.map +1 -1
  74. package/dist/agent-farm/lib/tunnel-client.js +43 -14
  75. package/dist/agent-farm/lib/tunnel-client.js.map +1 -1
  76. package/dist/agent-farm/servers/cron-delivery.d.ts +7 -1
  77. package/dist/agent-farm/servers/cron-delivery.d.ts.map +1 -1
  78. package/dist/agent-farm/servers/cron-delivery.js +2 -1
  79. package/dist/agent-farm/servers/cron-delivery.js.map +1 -1
  80. package/dist/agent-farm/servers/gate-profiles.d.ts +21 -0
  81. package/dist/agent-farm/servers/gate-profiles.d.ts.map +1 -1
  82. package/dist/agent-farm/servers/gate-profiles.js +36 -4
  83. package/dist/agent-farm/servers/gate-profiles.js.map +1 -1
  84. package/dist/agent-farm/servers/mailbox-delivery.d.ts +218 -15
  85. package/dist/agent-farm/servers/mailbox-delivery.d.ts.map +1 -1
  86. package/dist/agent-farm/servers/mailbox-delivery.js +259 -27
  87. package/dist/agent-farm/servers/mailbox-delivery.js.map +1 -1
  88. package/dist/agent-farm/servers/mailbox-wiring.d.ts +66 -11
  89. package/dist/agent-farm/servers/mailbox-wiring.d.ts.map +1 -1
  90. package/dist/agent-farm/servers/mailbox-wiring.js +202 -48
  91. package/dist/agent-farm/servers/mailbox-wiring.js.map +1 -1
  92. package/dist/agent-farm/servers/message-write.d.ts +58 -18
  93. package/dist/agent-farm/servers/message-write.d.ts.map +1 -1
  94. package/dist/agent-farm/servers/message-write.js +73 -28
  95. package/dist/agent-farm/servers/message-write.js.map +1 -1
  96. package/dist/agent-farm/servers/render-gate.d.ts +37 -1
  97. package/dist/agent-farm/servers/render-gate.d.ts.map +1 -1
  98. package/dist/agent-farm/servers/render-gate.js +71 -12
  99. package/dist/agent-farm/servers/render-gate.js.map +1 -1
  100. package/dist/agent-farm/servers/session-submit.d.ts +220 -27
  101. package/dist/agent-farm/servers/session-submit.d.ts.map +1 -1
  102. package/dist/agent-farm/servers/session-submit.js +333 -42
  103. package/dist/agent-farm/servers/session-submit.js.map +1 -1
  104. package/dist/agent-farm/servers/tower-cron.d.ts.map +1 -1
  105. package/dist/agent-farm/servers/tower-cron.js +3 -2
  106. package/dist/agent-farm/servers/tower-cron.js.map +1 -1
  107. package/dist/agent-farm/servers/tower-instances.d.ts.map +1 -1
  108. package/dist/agent-farm/servers/tower-instances.js +11 -3
  109. package/dist/agent-farm/servers/tower-instances.js.map +1 -1
  110. package/dist/agent-farm/servers/tower-routes.d.ts +32 -0
  111. package/dist/agent-farm/servers/tower-routes.d.ts.map +1 -1
  112. package/dist/agent-farm/servers/tower-routes.js +245 -36
  113. package/dist/agent-farm/servers/tower-routes.js.map +1 -1
  114. package/dist/agent-farm/servers/tower-server.js +15 -2
  115. package/dist/agent-farm/servers/tower-server.js.map +1 -1
  116. package/dist/agent-farm/servers/tower-terminals.d.ts +21 -0
  117. package/dist/agent-farm/servers/tower-terminals.d.ts.map +1 -1
  118. package/dist/agent-farm/servers/tower-terminals.js +53 -5
  119. package/dist/agent-farm/servers/tower-terminals.js.map +1 -1
  120. package/dist/agent-farm/servers/tower-tunnel.d.ts.map +1 -1
  121. package/dist/agent-farm/servers/tower-tunnel.js +14 -0
  122. package/dist/agent-farm/servers/tower-tunnel.js.map +1 -1
  123. package/dist/agent-farm/servers/tower-utils.d.ts +35 -0
  124. package/dist/agent-farm/servers/tower-utils.d.ts.map +1 -1
  125. package/dist/agent-farm/servers/tower-utils.js +39 -0
  126. package/dist/agent-farm/servers/tower-utils.js.map +1 -1
  127. package/dist/agent-farm/servers/tower-websocket.d.ts.map +1 -1
  128. package/dist/agent-farm/servers/tower-websocket.js +8 -1
  129. package/dist/agent-farm/servers/tower-websocket.js.map +1 -1
  130. package/dist/agent-farm/types.d.ts +36 -1
  131. package/dist/agent-farm/types.d.ts.map +1 -1
  132. package/dist/agent-farm/utils/message-format.d.ts +136 -4
  133. package/dist/agent-farm/utils/message-format.d.ts.map +1 -1
  134. package/dist/agent-farm/utils/message-format.js +212 -22
  135. package/dist/agent-farm/utils/message-format.js.map +1 -1
  136. package/dist/agent-farm/utils/server-utils.d.ts +8 -2
  137. package/dist/agent-farm/utils/server-utils.d.ts.map +1 -1
  138. package/dist/agent-farm/utils/server-utils.js +19 -2
  139. package/dist/agent-farm/utils/server-utils.js.map +1 -1
  140. package/dist/cli.d.ts.map +1 -1
  141. package/dist/cli.js +3 -1
  142. package/dist/cli.js.map +1 -1
  143. package/dist/commands/doctor.js +2 -2
  144. package/dist/commands/generate-image.d.ts +20 -1
  145. package/dist/commands/generate-image.d.ts.map +1 -1
  146. package/dist/commands/generate-image.js +188 -1
  147. package/dist/commands/generate-image.js.map +1 -1
  148. package/dist/commands/porch/context-refresh.d.ts +181 -0
  149. package/dist/commands/porch/context-refresh.d.ts.map +1 -0
  150. package/dist/commands/porch/context-refresh.js +270 -0
  151. package/dist/commands/porch/context-refresh.js.map +1 -0
  152. package/dist/commands/porch/index.d.ts +6 -0
  153. package/dist/commands/porch/index.d.ts.map +1 -1
  154. package/dist/commands/porch/index.js +46 -0
  155. package/dist/commands/porch/index.js.map +1 -1
  156. package/dist/commands/porch/next.d.ts +0 -9
  157. package/dist/commands/porch/next.d.ts.map +1 -1
  158. package/dist/commands/porch/next.js +133 -4
  159. package/dist/commands/porch/next.js.map +1 -1
  160. package/dist/commands/porch/prompts.d.ts.map +1 -1
  161. package/dist/commands/porch/prompts.js +18 -2
  162. package/dist/commands/porch/prompts.js.map +1 -1
  163. package/dist/commands/porch/protocol.d.ts.map +1 -1
  164. package/dist/commands/porch/protocol.js +102 -0
  165. package/dist/commands/porch/protocol.js.map +1 -1
  166. package/dist/commands/porch/types.d.ts +61 -0
  167. package/dist/commands/porch/types.d.ts.map +1 -1
  168. package/dist/lib/forge-contracts.d.ts +66 -5
  169. package/dist/lib/forge-contracts.d.ts.map +1 -1
  170. package/dist/lib/forge-contracts.js.map +1 -1
  171. package/dist/lib/forge.d.ts +1 -1
  172. package/dist/lib/forge.d.ts.map +1 -1
  173. package/dist/lib/forge.js +33 -11
  174. package/dist/lib/forge.js.map +1 -1
  175. package/dist/lib/self-refresh-invocation.d.ts +60 -0
  176. package/dist/lib/self-refresh-invocation.d.ts.map +1 -0
  177. package/dist/lib/self-refresh-invocation.js +64 -0
  178. package/dist/lib/self-refresh-invocation.js.map +1 -0
  179. package/dist/lib/test-env.d.ts +50 -0
  180. package/dist/lib/test-env.d.ts.map +1 -1
  181. package/dist/lib/test-env.js +76 -0
  182. package/dist/lib/test-env.js.map +1 -1
  183. package/dist/terminal/pty-manager.d.ts +10 -1
  184. package/dist/terminal/pty-manager.d.ts.map +1 -1
  185. package/dist/terminal/pty-manager.js +38 -9
  186. package/dist/terminal/pty-manager.js.map +1 -1
  187. package/dist/terminal/pty-session.d.ts +52 -4
  188. package/dist/terminal/pty-session.d.ts.map +1 -1
  189. package/dist/terminal/pty-session.js +157 -18
  190. package/dist/terminal/pty-session.js.map +1 -1
  191. package/dist/terminal/shellper-client.d.ts +73 -0
  192. package/dist/terminal/shellper-client.d.ts.map +1 -1
  193. package/dist/terminal/shellper-client.js +151 -0
  194. package/dist/terminal/shellper-client.js.map +1 -1
  195. package/dist/terminal/shellper-main.js +20 -3
  196. package/dist/terminal/shellper-main.js.map +1 -1
  197. package/dist/terminal/shellper-process.d.ts +2 -0
  198. package/dist/terminal/shellper-process.d.ts.map +1 -1
  199. package/dist/terminal/shellper-process.js +17 -1
  200. package/dist/terminal/shellper-process.js.map +1 -1
  201. package/dist/terminal/shellper-protocol.d.ts +28 -0
  202. package/dist/terminal/shellper-protocol.d.ts.map +1 -1
  203. package/dist/terminal/shellper-protocol.js.map +1 -1
  204. package/package.json +4 -4
  205. package/scripts/forge/gitea/_lib.sh +214 -0
  206. package/scripts/forge/gitea/issue-comment.sh +8 -1
  207. package/scripts/forge/gitea/issue-view.sh +95 -4
  208. package/scripts/forge/gitea/pr-create.sh +155 -0
  209. package/scripts/forge/gitea/pr-exists.sh +32 -4
  210. package/scripts/forge/gitea/pr-list.sh +40 -31
  211. package/scripts/forge/gitea/pr-view.sh +65 -4
  212. package/scripts/forge/gitea/recently-merged.sh +91 -21
  213. package/scripts/forge/gitea/user-identity.sh +30 -1
  214. package/scripts/forge/github/issue-view.sh +5 -2
  215. package/scripts/forge/github/pr-create.sh +47 -0
  216. package/scripts/forge/github/pr-search.sh +3 -1
  217. package/scripts/forge/gitlab/issue-view.sh +24 -4
  218. package/scripts/forge/gitlab/pr-create.sh +53 -0
  219. package/scripts/forge/gitlab/pr-search.sh +3 -1
  220. package/scripts/forge/linear/issue-view.sh +13 -2
  221. package/skeleton/.claude/skills/arch-save/SKILL.md +8 -2
  222. package/skeleton/.claude/skills/builder-refresh/SKILL.md +138 -0
  223. package/skeleton/.claude/skills/generate-image/SKILL.md +22 -1
  224. package/skeleton/.codex/skills/arch-save/SKILL.md +8 -2
  225. package/skeleton/.codex/skills/builder-refresh/SKILL.md +138 -0
  226. package/skeleton/.codex/skills/generate-image/SKILL.md +22 -1
  227. package/skeleton/protocol-schema.json +17 -0
  228. package/skeleton/protocols/air/prompts/pr.md +6 -1
  229. package/skeleton/protocols/air/protocol.json +1 -1
  230. package/skeleton/protocols/aspir/prompts/review.md +6 -1
  231. package/skeleton/protocols/aspir/protocol.json +5 -1
  232. package/skeleton/protocols/bugfix/prompts/pr.md +6 -1
  233. package/skeleton/protocols/bugfix/protocol.json +1 -1
  234. package/skeleton/protocols/bugfix/protocol.md +2 -1
  235. package/skeleton/protocols/experiment/protocol.json +1 -1
  236. package/skeleton/protocols/maintain/prompts/review.md +6 -1
  237. package/skeleton/protocols/maintain/protocol.json +1 -1
  238. package/skeleton/protocols/pir/prompts/review.md +10 -7
  239. package/skeleton/protocols/pir/protocol.json +1 -1
  240. package/skeleton/protocols/protocol-schema.json +17 -0
  241. package/skeleton/protocols/research/protocol.json +1 -1
  242. package/skeleton/protocols/spike/protocol.json +1 -1
  243. package/skeleton/protocols/spir/prompts/review.md +6 -1
  244. package/skeleton/protocols/spir/protocol.json +5 -1
  245. package/skeleton/resources/commands/agent-farm.md +1 -1
  246. package/templates/tower.html +16 -1
  247. package/dashboard-dist/assets/index-BZRTEMtH.css +0 -32
  248. package/dashboard-dist/assets/index-D3XaKpZW.js.map +0 -1
@@ -11,22 +11,22 @@
11
11
  * be unit-tested without a live Tower, and lets `handleSend` and the drainer share
12
12
  * exactly one delivery path (and one per-agent write serializer).
13
13
  */
14
- import { readFileSync, existsSync, readdirSync } from 'node:fs';
15
14
  import { homedir } from 'node:os';
16
15
  import { loadConfig } from '../../lib/config.js';
17
16
  import { terminalDeliverySignals } from '../../terminal/pty-session.js';
18
17
  import { getWorkspaceTerminals, getTerminalManager } from './tower-terminals.js';
19
18
  import { broadcastMessage, resolveAgentInRegistry, isResolveError } from './tower-messages.js';
20
- import { writeMessagePaced } from './message-write.js';
21
- import { classifyBuffer } from './render-gate.js';
19
+ import { submitMessagePaced } from './message-write.js';
20
+ import { bufferLines, classifyBuffer } from './render-gate.js';
22
21
  import { resolveProfile } from './gate-profiles.js';
23
- import { harnessFromLaunchScript } from '../commands/reset/context.js';
22
+ import { buildContextFsPort, harnessFromLaunchScript, } from '../commands/reset/context.js';
24
23
  import { getGlobalDb } from '../db/index.js';
25
24
  import { getArchitectByName } from '../state.js';
26
25
  import { formatBuilderMessage } from '../utils/message-format.js';
26
+ import { formatVerdict } from '@cluesmith/codev-sdk/hold-verdict';
27
27
  import { supersede as supersedeMailbox, dismissHeldWithKey, NOTICE_SUPERSEDE_PREFIX } from '../db/mailbox.js';
28
28
  import path from 'node:path';
29
- import { MailboxDrainer, } from './mailbox-delivery.js';
29
+ import { MailboxDrainer, normalizeForEcho, } from './mailbox-delivery.js';
30
30
  /**
31
31
  * "Recent output" window for the liveness diagnostic (Spec 1313, Phase 7 — spec line
32
32
  * 91). A `no-profile` streak only raises the loud log/broadcast when the session emitted
@@ -42,31 +42,13 @@ export function setMailboxBroadcaster(fn) {
42
42
  mailboxBroadcaster = fn;
43
43
  }
44
44
  /**
45
- * A node-fs adapter for {@link harnessFromLaunchScript}. Only `.read` is exercised
46
- * by that function, but `exists`/`listDirs` are implemented faithfully so the port
47
- * is honest and reusable rather than a lying stub.
45
+ * The shared node-fs adapter for {@link ContextFsPort}.
46
+ *
47
+ * Was a hand-rolled copy — one of three identical ones. A stub in any copy
48
+ * silently nulls the porch context for that path, and a regression test can only
49
+ * observe the copy it imports, so the implementations are now one.
48
50
  */
49
- const NODE_FS_PORT = {
50
- exists: (p) => existsSync(p),
51
- read: (p) => {
52
- try {
53
- return readFileSync(p, 'utf-8');
54
- }
55
- catch {
56
- return null;
57
- }
58
- },
59
- listDirs: (p) => {
60
- try {
61
- return readdirSync(p, { withFileTypes: true })
62
- .filter((d) => d.isDirectory())
63
- .map((d) => d.name);
64
- }
65
- catch {
66
- return null;
67
- }
68
- },
69
- };
51
+ const NODE_FS_PORT = buildContextFsPort();
70
52
  /**
71
53
  * The live, writable {@link PtySession} for an agent in a workspace, or `null`
72
54
  * when there is no usable live PTY — unknown agent, an exited session (the
@@ -122,16 +104,25 @@ export function resolveAgentForSession(sessionId) {
122
104
  * (fail-safe by construction: an unknown agent is held and surfaced, never guessed
123
105
  * — this is what correctly trips on wrapper/boot/relaunch screens too).
124
106
  *
125
- * Stale-identity note (Spec 1313): `session.command` is now sourced from the
126
- * persisted `terminal_sessions.command` on reconnect. If it ever goes stale (a
127
- * user re-points `shell.architect` at a different harness and the shellper later
128
- * auto-restarts into it while the row still names the old one), this can resolve
129
- * the WRONG profile — but it fails CLOSED today, not misdelivered: CLAUDE_PROFILE
130
- * and CODEX_PROFILE are behaviourally identical (same marker + region patterns),
131
- * and any cross-family mismatch (e.g. agy's `> ` marker) fails the composer-marker
132
- * test → not clean → held. That safety is a property of the current profile TABLE,
133
- * not of this design; the day codex/claude markers diverge, stale identity becomes
134
- * a live bug and the authoritative fix is WELCOME-frame hydration (see review).
107
+ * Identity precedence (PIR #1475): `session.command` is AUTHORITATIVE where it can
108
+ * be — it reads through to the identity the attached shellper states in its WELCOME
109
+ * frame, i.e. the argv the process that owns the PTY actually spawned, refreshed
110
+ * across reconnects and SPAWN relaunches. Only when no shellper identity is
111
+ * available (a local node-pty session, a pre-#1475 shellper still running from
112
+ * before an upgrade, or a payload that failed validation) does it fall back to the
113
+ * Spec 1313 chain: the persisted `terminal_sessions.command`, then the legacy
114
+ * self-heal from config. So the stale-row hazard this comment used to describe — a
115
+ * user re-points `shell.architect` at a different harness while the row still names
116
+ * the old one — no longer decides the profile for a shellper-backed session; the
117
+ * running process does.
118
+ *
119
+ * The fallback tier keeps its original safety property, and it is worth knowing why
120
+ * it is thin: a stale command fails CLOSED rather than misdelivering only because
121
+ * CLAUDE_PROFILE and CODEX_PROFILE are behaviourally identical (same marker + region
122
+ * patterns) and any cross-family mismatch (e.g. agy's `> ` marker) fails the
123
+ * composer-marker test → not clean → held. That is a property of the current profile
124
+ * TABLE, not of the design. It matters less now that the authoritative tier exists,
125
+ * but it is still what protects the fallback the day codex/claude markers diverge.
135
126
  */
136
127
  export function resolveProfileForSession(session) {
137
128
  const direct = resolveProfile({ command: session.command, args: session.launchArgs });
@@ -164,6 +155,88 @@ export async function classifyAgentScreen(session, profile) {
164
155
  const { term, cols, rows } = await screen.read();
165
156
  return classifyBuffer(term, cols, rows, profile);
166
157
  }
158
+ /**
159
+ * How long {@link watchEchoOnScreen}'s verification waits for a delivered message's header to
160
+ * show up, and how often it re-reads while waiting (Issue #1573).
161
+ *
162
+ * Measured 2026-09-01 against live claude and codex PTYs: the header is on screen from the
163
+ * first sample after the write completes (the composer echoes it as it is typed, before the
164
+ * Enter that submits it), and remains present at every sample out to +5 s. The budget is
165
+ * therefore slack for a loaded machine, not the expected cost — the common case returns on the
166
+ * first read with no added latency. It is bounded because the `afx send` request path awaits
167
+ * this before answering the sender.
168
+ *
169
+ * Issue #1584: the delivery path calls `verify()` at most TWICE (a second window for a slow
170
+ * renderer, no bytes written), so this constant is half the worst-case wait a sender sees —
171
+ * ~1.2 s. Raising it raises that, and the answer is no longer a retry decision: an unconfirmed
172
+ * delivery is recorded as delivered-unverified, never re-written.
173
+ */
174
+ const ECHO_VERIFY_TIMEOUT_MS = 600;
175
+ const ECHO_VERIFY_POLL_MS = 50;
176
+ /**
177
+ * How many times `needle` appears in the session's rendered mirror right now.
178
+ *
179
+ * A COUNT rather than a boolean because presence alone is not evidence (CMAP round 1 — codex):
180
+ * a previous delivery attempt's echo sits in the same scrollback, so "the header is on screen"
181
+ * would certify a retry whose bytes the composer swallowed. Comparing against a pre-write
182
+ * sample is what ties the evidence to the write that is being judged.
183
+ *
184
+ * Reads the SAME `SessionScreen` the render gate classifies, so verification and gating can
185
+ * never disagree about what the terminal shows, and scans its full retained buffer rather than
186
+ * the viewport — a long message scrolls its own header into scrollback while it types.
187
+ */
188
+ async function countEchoOnScreen(screen, needle) {
189
+ const { term } = await screen.read();
190
+ const text = normalizeForEcho(bufferLines(term).join('\n'));
191
+ let count = 0;
192
+ for (let at = text.indexOf(needle); at !== -1; at = text.indexOf(needle, at + needle.length))
193
+ count++;
194
+ return count;
195
+ }
196
+ /**
197
+ * Open an echo watch on a session (Issue #1573) — the live binding for
198
+ * {@link DeliveryPorts.watchEcho}.
199
+ *
200
+ * Samples the terminal BEFORE the write, then `verify()` polls until the needle appears MORE
201
+ * often than it did in that sample. New evidence, not mere presence.
202
+ *
203
+ * A session with no mirror has produced no output and therefore cannot echo anything, so its
204
+ * watch verifies `false` rather than passing.
205
+ *
206
+ * Known residuals — these are why a negative is "could not confirm", not "not delivered". Issue
207
+ * #1584: they are also why a negative must NOT trigger a redelivery. Each recurs for the same
208
+ * message on every attempt, so holding-and-rewriting on one of them is a loop that cannot
209
+ * converge — #1583 saw a message re-injected dozens of times on exactly the second one. The
210
+ * caller now commits the delivery and reports it unverified instead. None is designed around
211
+ * here; #1578 tracks smarter verification:
212
+ * - a harness on the ALTERNATE screen buffer has no scrollback, so a message longer than one
213
+ * viewport can scroll its header out of reach and never confirm. The agy profile boots into
214
+ * the alternate buffer and was not measurable here (unauthenticated).
215
+ * - a very long write can evict the pre-write copy from the 1000-line mirror, so the count
216
+ * comes back equal rather than greater and a genuine delivery reads as unconfirmed.
217
+ * - an unconfirmed delivery re-reads and re-normalizes the retained buffer once per poll
218
+ * while the `afx send` request waits. Bounded by the timeout (and by the delivery path's
219
+ * two windows, ~1.2 s total), and off the happy path entirely — the measured case confirms
220
+ * on the first read.
221
+ */
222
+ export async function watchEchoOnScreen(session, needle) {
223
+ const screen = session.gateScreen;
224
+ if (!screen)
225
+ return { verify: () => Promise.resolve(false) };
226
+ const before = await countEchoOnScreen(screen, needle);
227
+ return {
228
+ verify: async () => {
229
+ const deadline = Date.now() + ECHO_VERIFY_TIMEOUT_MS;
230
+ for (;;) {
231
+ if (await countEchoOnScreen(screen, needle) > before)
232
+ return true;
233
+ if (Date.now() >= deadline)
234
+ return false;
235
+ await new Promise((resolve) => setTimeout(resolve, ECHO_VERIFY_POLL_MS));
236
+ }
237
+ },
238
+ };
239
+ }
167
240
  /** Convert a delivered-message frame to the WebSocket bus shape and broadcast it. */
168
241
  function broadcastDelivered(frame) {
169
242
  broadcastMessage({
@@ -186,14 +259,25 @@ export function makeDeliveryPorts(log) {
186
259
  getSessionForAgent: (ws, agent) => resolveLiveSessionForAgent(ws, agent),
187
260
  resolveProfile: (session) => resolveProfileForSession(session),
188
261
  classify: (session, profile) => classifyAgentScreen(session, profile),
189
- writeMessage: (session, msg, noEnter) => writeMessagePaced(session, msg, noEnter),
262
+ // Issue #1365: the write edge takes the session's per-terminal submission lock as a
263
+ // LEAF inside the per-agent serializer, so a gated delivery and a concurrent
264
+ // `--interrupt`/`--escape` can no longer interleave. The precheck is the delivery
265
+ // module's, re-run inside that lock.
266
+ writeMessage: (session, msg, noEnter, precheck) => submitMessagePaced(session, msg, noEnter, precheck),
267
+ // Issue #1573: the only end-to-end evidence that the bytes reached the terminal — opened
268
+ // before the write. Issue #1584: consulted AFTER the row is marked delivered, because the
269
+ // commit is what makes a completed write un-repeatable; this only decides what we report.
270
+ watchEcho: (session, needle) => watchEchoOnScreen(session, needle),
190
271
  broadcast: (frame) => broadcastDelivered(frame),
191
272
  onHeldStateChange: () => broadcastHeldStateChange(),
192
273
  onEscalation: (info) => broadcastEscalation(info),
193
274
  onLiveness: (info) => surfaceLiveness(info, log),
275
+ // Issue #1584: an unconfirmed delivery is committed, not retried, so this notice is the
276
+ // only human-facing trace for a cron/backstop send with no sender waiting on a response.
277
+ onUnverifiedDelivery: (info) => surfaceUnverifiedDelivery(info),
194
278
  escalateHeldToOwner: (info) => escalateHeldToOwner(info, log),
195
279
  clearHeldOwnerNotice: (ws, agent) => clearHeldOwnerNotice(ws, agent),
196
- log: (m) => log('INFO', m),
280
+ log: (m, level) => log(level ?? 'INFO', m),
197
281
  now: () => Date.now(),
198
282
  };
199
283
  }
@@ -203,13 +287,58 @@ const NOTICE_SENDER = 'af-mailbox';
203
287
  function noticeSupersedeKey(toAgent) {
204
288
  return `${NOTICE_SUPERSEDE_PREFIX}${toAgent}`;
205
289
  }
206
- /** Human-readable notice body (metadata only — never the starved messages' contents). */
207
- function formatOwnerNoticeBody(info) {
290
+ /**
291
+ * Human-readable notice body (metadata only — never the starved messages' contents).
292
+ *
293
+ * TWO notices, not one (Issue #1482). The old single body said "its composer never classifies
294
+ * as a ready prompt" and offered `afx interrupt` for every hold, which is wrong advice in the
295
+ * commonest case: when the detail is `user-text` a human is sitting at that composer with a
296
+ * draft, and interrupting them is the last thing the owner should do. The gate has always
297
+ * known which case it is; now the row carries it, so the notice can say it.
298
+ *
299
+ * The `streak` — how many consecutive gate checks re-confirmed the same verdict — is what
300
+ * separates "held ~7m" (which could be one unlucky sample) from "held ~7m, re-confirmed across
301
+ * 41 checks" (which cannot be).
302
+ *
303
+ * Exported for unit testing. This text is operator-facing INSTRUCTIONS during an incident, and
304
+ * it went un-asserted long enough to ship a remedy line naming `afx interrupt` at a composer a
305
+ * human was actively typing in. Prose that tells someone what to do to a live terminal is
306
+ * behaviour, and gets tested like behaviour.
307
+ */
308
+ export function formatOwnerNoticeBody(info) {
208
309
  const mins = Math.max(1, Math.round(info.ageMs / 60_000));
209
310
  const plural = info.heldCount === 1 ? 'message' : 'messages';
210
- return (`Mailbox delivery is STUCK for builder '${info.toAgent}' @ ${path.basename(info.workspacePath)}. ` +
211
- `${info.heldCount} ${plural} held ~${mins}m (reason: ${info.reason ?? 'held'}) — its composer never classifies as a ready prompt, ` +
212
- `so nothing is being delivered (cron nudges included). ` +
311
+ const confirmed = info.streak > 1 ? `, re-confirmed across ${info.streak} consecutive gate checks` : '';
312
+ const head = `Mailbox delivery is STUCK for builder '${info.toAgent}' @ ${path.basename(info.workspacePath)}. ` +
313
+ `${info.heldCount} ${plural} held ~${mins}m (${formatVerdict(info.reason, info.detail)}${confirmed}).`;
314
+ if (info.detail === 'user-text') {
315
+ // The SAFE hold: the classifier positively identified a draft or menu in the composer.
316
+ //
317
+ // This branch names NO command that touches the terminal, deliberately — not even hedged
318
+ // with "only if you are sure". An operator reading a notice headed "delivery is STUCK"
319
+ // treats the remedy line as the instruction, and the person at that composer is mid-thought
320
+ // by definition of this verdict. The #1583 loop was aggravated by exactly that: an operator
321
+ // followed an `afx interrupt` suggestion out of this notice. A hedge is not a safeguard
322
+ // when the surrounding text reads as an incident.
323
+ return (`${head} Its composer has been OCCUPIED that whole time — a draft or an open menu is on ` +
324
+ `the line, which usually means a human is working there, and delivery resumes by itself ` +
325
+ `the moment the line clears. ` +
326
+ `Remedy: usually none — let it clear. 'afx inbox' inspects the queue (metadata only, ` +
327
+ `never bodies) if you want to see what is waiting, and talking to whoever is at that ` +
328
+ `terminal is the only other thing worth doing.`);
329
+ }
330
+ if (info.detail || info.reason === 'no-profile') {
331
+ // The DEFECT class: the gate could not verify the composer at all, so nothing will clear
332
+ // this without intervention.
333
+ return (`${head} The render gate CANNOT VERIFY that composer — this is not a busy human, it is a ` +
334
+ `classifier that cannot find a bounded composer region, so the mail will never deliver on ` +
335
+ `its own. Usual causes: a drifted TUI profile, a torn/mid-repaint frame, or Tower's ` +
336
+ `terminal dimensions diverging from the real PTY (Issue #1482). ` +
337
+ `Remedy: 'afx inbox' to inspect; resizing the viewer forces a repaint; ` +
338
+ `'afx interrupt ${info.toAgent}' clears a stuck composer.`);
339
+ }
340
+ return (`${head} Its composer never classifies as a ready prompt, so nothing is being delivered ` +
341
+ `(cron nudges included). ` +
213
342
  `Remedy: run 'afx inbox' to inspect; 'afx interrupt ${info.toAgent}' clears a stuck composer.`);
214
343
  }
215
344
  /**
@@ -244,7 +373,7 @@ function escalateHeldToOwner(info, log) {
244
373
  workspacePath: info.workspacePath,
245
374
  toAgent: owner.agent,
246
375
  body,
247
- formattedMessage: formatBuilderMessage(NOTICE_SENDER, body),
376
+ formattedMessage: formatBuilderMessage(NOTICE_SENDER, owner.agent, body),
248
377
  fromAgent: NOTICE_SENDER,
249
378
  fromWorkspace: info.workspacePath,
250
379
  });
@@ -252,7 +381,8 @@ function escalateHeldToOwner(info, log) {
252
381
  // Deliver the notice promptly through the SAME gate (it holds if the architect is busy).
253
382
  void ensureDrainer().scheduleDrain(owner.workspacePath, owner.agent);
254
383
  log('WARN', `[mailbox] STARVATION notice → ${owner.agent} about ${info.toAgent} @ ${path.basename(info.workspacePath)} ` +
255
- `(${info.heldCount} held ~${Math.round(info.ageMs / 1000)}s, reason ${info.reason ?? 'held'})`);
384
+ `(${info.heldCount} held ~${Math.round(info.ageMs / 1000)}s, ${formatVerdict(info.reason, info.detail)}` +
385
+ `${info.streak > 1 ? `, streak ${info.streak}` : ''})`);
256
386
  return true;
257
387
  }
258
388
  /**
@@ -291,6 +421,10 @@ function broadcastEscalation(info) {
291
421
  mailboxId: info.mailboxId,
292
422
  ageMs: info.ageMs,
293
423
  reason: info.reason,
424
+ // Issue #1482: a client showing only `busy` cannot tell an occupied composer from one the
425
+ // gate could not read. The wire is additive — an older client that ignores the field is
426
+ // unaffected — but the TYPE is required, so this producer cannot forget it.
427
+ detail: info.detail,
294
428
  };
295
429
  mailboxBroadcaster?.({
296
430
  type: 'mailbox-escalation',
@@ -324,6 +458,26 @@ function surfaceLiveness(info, log) {
324
458
  workspace: info.workspacePath,
325
459
  });
326
460
  }
461
+ /**
462
+ * Surface an unconfirmed delivery (Issue #1584) on the generic `notification` SSE channel that
463
+ * {@link surfaceLiveness} already uses — human title/body, no message body.
464
+ *
465
+ * Deliberately NOT the `mailbox-escalation` event: that one means "held past the escalation
466
+ * age", and saying that about a row we just delivered would be false. The wording here states
467
+ * exactly what is and is not known — the bytes went out, the screen never showed them, and it
468
+ * will not be sent again.
469
+ */
470
+ function surfaceUnverifiedDelivery(info) {
471
+ const where = `${info.toAgent} @ ${path.basename(info.workspacePath)}`;
472
+ mailboxBroadcaster?.({
473
+ type: 'notification',
474
+ title: 'Mailbox: delivered but not confirmed on screen',
475
+ body: `${where} — the message was written to terminal ${info.terminalId.slice(0, 8)}… and every byte was ` +
476
+ `accepted, but its header never appeared on that screen. It is recorded as delivered and will NOT ` +
477
+ `be sent again (mailbox id ${info.mailboxId.slice(0, 8)}…). Check the agent's transcript.`,
478
+ workspace: info.workspacePath,
479
+ });
480
+ }
327
481
  // The single backstop drainer instance (replaces the retired SendBuffer). Created
328
482
  // lazily so it picks up the configured retention window (below) at first use.
329
483
  let drainer;
@@ -1 +1 @@
1
- {"version":3,"file":"mailbox-wiring.js","sourceRoot":"","sources":["../../../src/agent-farm/servers/mailbox-wiring.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mailbox-wiring.js","sourceRoot":"","sources":["../../../src/agent-farm/servers/mailbox-wiring.ts"],"names":[],"mappings":"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"}
@@ -4,12 +4,13 @@
4
4
  * Extracted to a shared module to avoid circular imports between
5
5
  * tower-routes.ts and tower-cron.ts.
6
6
  */
7
+ import { type SubmitClock } from './session-submit.js';
7
8
  /** Minimal writable session interface — avoids coupling to PtySession. */
8
9
  export interface WritableSession {
9
10
  /**
10
11
  * Write input to the underlying PTY. Returns `false` when the write was dropped
11
12
  * (#1198: a shellper-backed session whose socket has died still reports status
12
- * 'running', yet its writes silently no-op). {@link writeMessagePaced} threads this
13
+ * 'running', yet its writes silently no-op). {@link submitMessagePaced} threads this
13
14
  * boolean so a mailbox delivery whose bytes never reached the terminal is held, not
14
15
  * marked delivered (Spec 1313 integration review — the silent-loss finding).
15
16
  */
@@ -53,24 +54,63 @@ export declare function writeEscapeToSession(session: WritableSession, noEnter:
53
54
  */
54
55
  export declare function writeMessageToSession(session: WritableSession, message: string, noEnter: boolean, delayOffset?: number): number;
55
56
  /**
56
- * Paced write of a message (text + trailing Enter unless `noEnter`) that reports
57
- * whether every byte reached the PTY. Resolves `true` when the whole submit landed,
58
- * `false` when ANY scheduled write was dropped (#1198: a shellper socket that died
59
- * mid-pace). This is the delivery layer's authoritative success signal — a mailbox
60
- * delivery holds a row whose bytes never made it instead of marking it delivered
61
- * (Spec 1313 integration review — the silent-loss finding).
57
+ * Outcome of a {@link submitMessagePaced} attempt. Generic in the caller's own abort
58
+ * vocabulary so this module stays free of mailbox concepts — the delivery layer
59
+ * instantiates `A` with its hold reasons.
60
+ */
61
+ export type PacedSubmitResult<A> =
62
+ /** The whole submit — text and, unless `noEnter`, the trailing Enter — reached the PTY. */
63
+ {
64
+ status: 'written';
65
+ }
66
+ /** #1198: a scheduled write was dropped mid-pace (the shellper socket died). */
67
+ | {
68
+ status: 'dropped';
69
+ }
70
+ /**
71
+ * The bytes went out, but an operator submission bypassed the lock while they did
72
+ * (the ceiling-expired degraded path), so this submit cannot be trusted to have
73
+ * landed intact.
74
+ */
75
+ | {
76
+ status: 'preempted';
77
+ }
78
+ /** Another submission held the terminal. NOTHING was written; the caller may retry later. */
79
+ | {
80
+ status: 'contended';
81
+ }
82
+ /** The caller's in-lock precheck refused. NOTHING was written. */
83
+ | {
84
+ status: 'aborted';
85
+ abort: A;
86
+ };
87
+ /**
88
+ * Paced write of a message (text + trailing Enter unless `noEnter`) performed as ONE
89
+ * submission on the session's per-terminal lock (Issue #1365).
90
+ *
91
+ * This is the mailbox delivery path's write edge. Before #1365 it wrote directly, under
92
+ * the per-agent serializer only, so a gated delivery could interleave with a concurrent
93
+ * `--interrupt`/`--escape` on the same terminal: a `^C` or ESC landing between the text
94
+ * and its Enter cleared or truncated the composer while every byte still reported
95
+ * success, and the row was marked `delivered` for a message the agent never saw whole.
96
+ * Taking the same lock those paths take is what makes that impossible.
97
+ *
98
+ * Two properties are load-bearing and easy to lose in a refactor:
62
99
  *
63
- * `writeMessageToSession` fires the text, any subsequent lines, and the trailing
64
- * Enter across `setTimeout` gaps (10–130ms+), and a t=0 `writable` precheck cannot
65
- * see a socket that dies *during* that sequence. So wrap the session and record
66
- * whether any of those writes returned false. The returned promise resolves at the
67
- * final scheduled offset (`doneMs`); `writeMessageToSession` registers the Enter's
68
- * `setTimeout` at that same offset *before* this resolve is scheduled, so the Enter
69
- * executes first and its result is observed by resolution time.
100
+ * - **`precheck` runs INSIDE the lock**, immediately before the first byte. Acquiring
101
+ * the lock without it would merely move the race: a delivery that classified a clean
102
+ * screen, then waited behind another submission, would write onto the screen that
103
+ * submission just changed. Returning non-null aborts with nothing written.
104
+ * - **Contention is declined, not queued** (see {@link trySubmitToSession}). The gated
105
+ * delivery path must never block, because the drainer walks agents sequentially.
70
106
  *
71
- * Awaiting the promise is also what makes the per-agent write serializer's
72
- * completion-chaining real — the next delivery cannot begin until this submit
73
- * (Enter included) is entirely on the wire.
107
+ * The completion semantics callers depend on are unchanged from the pre-#1365
108
+ * `writeMessagePaced`: the returned promise resolves only after the trailing Enter has
109
+ * been written. `writeMessageToSession` registers the Enter's `setTimeout` before
110
+ * `submitToSession` schedules its own equal-offset sleep, so the Enter still executes
111
+ * first — which is what makes the per-agent serializer's completion-chaining real.
74
112
  */
75
- export declare function writeMessagePaced(session: WritableSession, message: string, noEnter: boolean): Promise<boolean>;
113
+ export declare function submitMessagePaced<A>(session: WritableSession & {
114
+ id: string;
115
+ }, message: string, noEnter: boolean, precheck: () => A | null, clock?: SubmitClock): Promise<PacedSubmitResult<A>>;
76
116
  //# sourceMappingURL=message-write.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"message-write.d.ts","sourceRoot":"","sources":["../../../src/agent-farm/servers/message-write.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,0EAA0E;AAC1E,MAAM,WAAW,eAAe;IAC9B;;;;;;OAMG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CAC9B;AAUD,iEAAiE;AACjE,eAAO,MAAM,GAAG,WAAS,CAAC;AAE1B;;;GAGG;AACH,eAAO,MAAM,qBAAqB,KAAwB,CAAC;AAE3D;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAKvF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,SAAI,GAC3E,MAAM,CAqCR;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAC1D,OAAO,CAAC,OAAO,CAAC,CAWlB"}
1
+ {"version":3,"file":"message-write.d.ts","sourceRoot":"","sources":["../../../src/agent-farm/servers/message-write.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAqC,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAE1F,0EAA0E;AAC1E,MAAM,WAAW,eAAe;IAC9B;;;;;;OAMG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CAC9B;AAUD,iEAAiE;AACjE,eAAO,MAAM,GAAG,WAAS,CAAC;AAE1B;;;GAGG;AACH,eAAO,MAAM,qBAAqB,KAAwB,CAAC;AAE3D;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAKvF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,SAAI,GAC3E,MAAM,CAqCR;AAED;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC;AAC7B,2FAA2F;AACzF;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE;AACvB,gFAAgF;GAC9E;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE;AACvB;;;;GAIG;GACD;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE;AACzB,6FAA6F;GAC3F;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE;AACzB,kEAAkE;GAChE;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,CAAC;AAEpC;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EACxC,OAAO,EAAE,eAAe,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EACzC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,CAAC,GAAG,IAAI,EACxB,KAAK,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAkD/B"}
@@ -4,6 +4,7 @@
4
4
  * Extracted to a shared module to avoid circular imports between
5
5
  * tower-routes.ts and tower-cron.ts.
6
6
  */
7
+ import { trySubmitToSession, watchBypasses } from './session-submit.js';
7
8
  // Messages longer than this threshold are written line-by-line with delays
8
9
  // to prevent the receiving terminal from classifying the input as a paste
9
10
  // and swallowing the final Enter.
@@ -91,36 +92,80 @@ export function writeMessageToSession(session, message, noEnter, delayOffset = 0
91
92
  return lastLineTime;
92
93
  }
93
94
  /**
94
- * Paced write of a message (text + trailing Enter unless `noEnter`) that reports
95
- * whether every byte reached the PTY. Resolves `true` when the whole submit landed,
96
- * `false` when ANY scheduled write was dropped (#1198: a shellper socket that died
97
- * mid-pace). This is the delivery layer's authoritative success signal — a mailbox
98
- * delivery holds a row whose bytes never made it instead of marking it delivered
99
- * (Spec 1313 integration review — the silent-loss finding).
95
+ * Paced write of a message (text + trailing Enter unless `noEnter`) performed as ONE
96
+ * submission on the session's per-terminal lock (Issue #1365).
100
97
  *
101
- * `writeMessageToSession` fires the text, any subsequent lines, and the trailing
102
- * Enter across `setTimeout` gaps (10–130ms+), and a t=0 `writable` precheck cannot
103
- * see a socket that dies *during* that sequence. So wrap the session and record
104
- * whether any of those writes returned false. The returned promise resolves at the
105
- * final scheduled offset (`doneMs`); `writeMessageToSession` registers the Enter's
106
- * `setTimeout` at that same offset *before* this resolve is scheduled, so the Enter
107
- * executes first and its result is observed by resolution time.
98
+ * This is the mailbox delivery path's write edge. Before #1365 it wrote directly, under
99
+ * the per-agent serializer only, so a gated delivery could interleave with a concurrent
100
+ * `--interrupt`/`--escape` on the same terminal: a `^C` or ESC landing between the text
101
+ * and its Enter cleared or truncated the composer while every byte still reported
102
+ * success, and the row was marked `delivered` for a message the agent never saw whole.
103
+ * Taking the same lock those paths take is what makes that impossible.
108
104
  *
109
- * Awaiting the promise is also what makes the per-agent write serializer's
110
- * completion-chaining real — the next delivery cannot begin until this submit
111
- * (Enter included) is entirely on the wire.
105
+ * Two properties are load-bearing and easy to lose in a refactor:
106
+ *
107
+ * - **`precheck` runs INSIDE the lock**, immediately before the first byte. Acquiring
108
+ * the lock without it would merely move the race: a delivery that classified a clean
109
+ * screen, then waited behind another submission, would write onto the screen that
110
+ * submission just changed. Returning non-null aborts with nothing written.
111
+ * - **Contention is declined, not queued** (see {@link trySubmitToSession}). The gated
112
+ * delivery path must never block, because the drainer walks agents sequentially.
113
+ *
114
+ * The completion semantics callers depend on are unchanged from the pre-#1365
115
+ * `writeMessagePaced`: the returned promise resolves only after the trailing Enter has
116
+ * been written. `writeMessageToSession` registers the Enter's `setTimeout` before
117
+ * `submitToSession` schedules its own equal-offset sleep, so the Enter still executes
118
+ * first — which is what makes the per-agent serializer's completion-chaining real.
112
119
  */
113
- export function writeMessagePaced(session, message, noEnter) {
114
- let delivered = true;
115
- const tracked = {
116
- write: (data) => {
117
- const ok = session.write(data);
118
- if (!ok)
119
- delivered = false;
120
- return ok;
121
- },
122
- };
123
- const doneMs = writeMessageToSession(tracked, message, noEnter);
124
- return new Promise((resolve) => setTimeout(() => resolve(delivered), doneMs));
120
+ export async function submitMessagePaced(session, message, noEnter, precheck, clock) {
121
+ // Fail LOUD on a missing id rather than keying the lock on `undefined`. Sessions reach
122
+ // this through structurally-typed ports, so a double without an id compiles fine and
123
+ // would silently collapse every per-terminal lock into one global lock — serialization
124
+ // that looks present and is not. A throw here surfaces as a held row (the delivery path
125
+ // never marks a row delivered on a throw), which is the safe failure.
126
+ if (typeof session.id !== 'string' || session.id === '') {
127
+ throw new Error('submitMessagePaced: session.id must be a non-empty string (the per-terminal lock key)');
128
+ }
129
+ // The one thing the lock cannot stop is an operator submission whose wait ceiling expired
130
+ // and wrote anyway. Watch the session's degraded-write counter across our own submission:
131
+ // a bump means a `^C`/ESC bypassed us mid-write, so the composer may have been cleared or
132
+ // truncated under our bytes. Cheaper and more direct than re-classifying the screen — and it
133
+ // is the difference between re-holding the row and falsely reporting a delivery, which is
134
+ // the whole point of Issue #1365. The watch also pins the counter against eviction for
135
+ // exactly as long as we need to compare it; `finally` is what keeps that pin from leaking.
136
+ const bypasses = watchBypasses(session.id);
137
+ try {
138
+ let delivered = true;
139
+ let abort = null;
140
+ const tracked = {
141
+ write: (data) => {
142
+ const ok = session.write(data);
143
+ if (!ok)
144
+ delivered = false;
145
+ return ok;
146
+ },
147
+ };
148
+ const ran = await trySubmitToSession(session.id, () => {
149
+ abort = precheck();
150
+ if (abort !== null)
151
+ return 0; // refused in-lock: not one byte goes out
152
+ return writeMessageToSession(tracked, message, noEnter);
153
+ }, clock);
154
+ if (!ran)
155
+ return { status: 'contended' };
156
+ // Read through a cast: both flags are assigned inside the callback above, which
157
+ // TypeScript's flow analysis does not track back to this scope.
158
+ const refused = abort;
159
+ if (refused !== null)
160
+ return { status: 'aborted', abort: refused };
161
+ if (!delivered)
162
+ return { status: 'dropped' };
163
+ if (bypasses.raced())
164
+ return { status: 'preempted' };
165
+ return { status: 'written' };
166
+ }
167
+ finally {
168
+ bypasses.release();
169
+ }
125
170
  }
126
171
  //# sourceMappingURL=message-write.js.map