@team-agent/installer 0.2.10 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (326) hide show
  1. package/Cargo.lock +744 -0
  2. package/Cargo.toml +34 -0
  3. package/crates/team-agent/Cargo.toml +33 -0
  4. package/crates/team-agent/src/cli/adapters.rs +1343 -0
  5. package/crates/team-agent/src/cli/diagnose.rs +554 -0
  6. package/crates/team-agent/src/cli/emit.rs +1077 -0
  7. package/crates/team-agent/src/cli/helpers.rs +88 -0
  8. package/crates/team-agent/src/cli/leader.rs +216 -0
  9. package/crates/team-agent/src/cli/mod.rs +1141 -0
  10. package/crates/team-agent/src/cli/profile.rs +306 -0
  11. package/crates/team-agent/src/cli/send.rs +215 -0
  12. package/crates/team-agent/src/cli/status.rs +179 -0
  13. package/crates/team-agent/src/cli/status_port.rs +502 -0
  14. package/crates/team-agent/src/cli/tests/base.rs +616 -0
  15. package/crates/team-agent/src/cli/tests/compile.rs +96 -0
  16. package/crates/team-agent/src/cli/tests/divergence.rs +509 -0
  17. package/crates/team-agent/src/cli/tests/lane_c.rs +333 -0
  18. package/crates/team-agent/src/cli/tests/leader_watch.rs +395 -0
  19. package/crates/team-agent/src/cli/tests/main_preserved.rs +675 -0
  20. package/crates/team-agent/src/cli/tests/missing_subcommands.rs +390 -0
  21. package/crates/team-agent/src/cli/tests/mod.rs +97 -0
  22. package/crates/team-agent/src/cli/tests/peer_allow.rs +137 -0
  23. package/crates/team-agent/src/cli/tests/repair_state_byte_lock.rs +302 -0
  24. package/crates/team-agent/src/cli/tests/run_delegation.rs +305 -0
  25. package/crates/team-agent/src/cli/tests/status_send.rs +385 -0
  26. package/crates/team-agent/src/cli/tests/verb_profile.rs +182 -0
  27. package/crates/team-agent/src/cli/tests/verb_settle.rs +236 -0
  28. package/crates/team-agent/src/cli/tests/verb_validate.rs +184 -0
  29. package/crates/team-agent/src/cli/types.rs +605 -0
  30. package/crates/team-agent/src/compiler/tests.rs +701 -0
  31. package/crates/team-agent/src/compiler.rs +489 -0
  32. package/crates/team-agent/src/coordinator/backoff.rs +153 -0
  33. package/crates/team-agent/src/coordinator/health.rs +436 -0
  34. package/crates/team-agent/src/coordinator/mod.rs +80 -0
  35. package/crates/team-agent/src/coordinator/orphan.rs +179 -0
  36. package/crates/team-agent/src/coordinator/tests/abnormal.rs +255 -0
  37. package/crates/team-agent/src/coordinator/tests/basics.rs +262 -0
  38. package/crates/team-agent/src/coordinator/tests/daemon.rs +323 -0
  39. package/crates/team-agent/src/coordinator/tests/health_sync.rs +263 -0
  40. package/crates/team-agent/src/coordinator/tests/main_preserved.rs +136 -0
  41. package/crates/team-agent/src/coordinator/tests/mod.rs +310 -0
  42. package/crates/team-agent/src/coordinator/tests/spine.rs +261 -0
  43. package/crates/team-agent/src/coordinator/tests/takeover.rs +227 -0
  44. package/crates/team-agent/src/coordinator/tests/tick_core.rs +256 -0
  45. package/crates/team-agent/src/coordinator/tests/watch.rs +167 -0
  46. package/crates/team-agent/src/coordinator/tick.rs +2032 -0
  47. package/crates/team-agent/src/coordinator/types.rs +584 -0
  48. package/crates/team-agent/src/db/migration.rs +716 -0
  49. package/crates/team-agent/src/db/mod.rs +23 -0
  50. package/crates/team-agent/src/db/schema.rs +378 -0
  51. package/crates/team-agent/src/event_log.rs +375 -0
  52. package/crates/team-agent/src/fake_worker.rs +253 -0
  53. package/crates/team-agent/src/leader/helpers.rs +190 -0
  54. package/crates/team-agent/src/leader/inject.rs +33 -0
  55. package/crates/team-agent/src/leader/lease.rs +1063 -0
  56. package/crates/team-agent/src/leader/mod.rs +99 -0
  57. package/crates/team-agent/src/leader/owner_bind.rs +292 -0
  58. package/crates/team-agent/src/leader/rediscover/tests.rs +525 -0
  59. package/crates/team-agent/src/leader/rediscover.rs +1099 -0
  60. package/crates/team-agent/src/leader/start.rs +273 -0
  61. package/crates/team-agent/src/leader/takeover.rs +235 -0
  62. package/crates/team-agent/src/leader/tests/basics.rs +183 -0
  63. package/crates/team-agent/src/leader/tests/byte_findings.rs +234 -0
  64. package/crates/team-agent/src/leader/tests/identity.rs +206 -0
  65. package/crates/team-agent/src/leader/tests/idle.rs +271 -0
  66. package/crates/team-agent/src/leader/tests/lease_api.rs +225 -0
  67. package/crates/team-agent/src/leader/tests/lease_claim.rs +253 -0
  68. package/crates/team-agent/src/leader/tests/mod.rs +125 -0
  69. package/crates/team-agent/src/leader/tests/rediscover.rs +351 -0
  70. package/crates/team-agent/src/leader/tests/wake_start_owner.rs +204 -0
  71. package/crates/team-agent/src/leader/types.rs +487 -0
  72. package/crates/team-agent/src/lib.rs +85 -0
  73. package/crates/team-agent/src/lifecycle/display.rs +228 -0
  74. package/crates/team-agent/src/lifecycle/helpers.rs +112 -0
  75. package/crates/team-agent/src/lifecycle/launch/plan.rs +227 -0
  76. package/crates/team-agent/src/lifecycle/launch.rs +1833 -0
  77. package/crates/team-agent/src/lifecycle/mod.rs +62 -0
  78. package/crates/team-agent/src/lifecycle/restart/agent.rs +533 -0
  79. package/crates/team-agent/src/lifecycle/restart/common.rs +517 -0
  80. package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +41 -0
  81. package/crates/team-agent/src/lifecycle/restart/rebuild.rs +268 -0
  82. package/crates/team-agent/src/lifecycle/restart/remove.rs +780 -0
  83. package/crates/team-agent/src/lifecycle/restart/selection.rs +208 -0
  84. package/crates/team-agent/src/lifecycle/restart/team_state.rs +242 -0
  85. package/crates/team-agent/src/lifecycle/restart.rs +76 -0
  86. package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +455 -0
  87. package/crates/team-agent/src/lifecycle/tests/core.rs +989 -0
  88. package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +583 -0
  89. package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +933 -0
  90. package/crates/team-agent/src/lifecycle/tests/main_preserved.rs +265 -0
  91. package/crates/team-agent/src/lifecycle/tests.rs +27 -0
  92. package/crates/team-agent/src/lifecycle/types.rs +685 -0
  93. package/crates/team-agent/src/main.rs +41 -0
  94. package/crates/team-agent/src/mcp_server/helpers.rs +228 -0
  95. package/crates/team-agent/src/mcp_server/mod.rs +183 -0
  96. package/crates/team-agent/src/mcp_server/normalize.rs +312 -0
  97. package/crates/team-agent/src/mcp_server/tests/golden.rs +283 -0
  98. package/crates/team-agent/src/mcp_server/tests/normalize.rs +244 -0
  99. package/crates/team-agent/src/mcp_server/tests/scoped.rs +189 -0
  100. package/crates/team-agent/src/mcp_server/tests/send.rs +222 -0
  101. package/crates/team-agent/src/mcp_server/tests/tools.rs +158 -0
  102. package/crates/team-agent/src/mcp_server/tests/wire.rs +159 -0
  103. package/crates/team-agent/src/mcp_server/tests.rs +38 -0
  104. package/crates/team-agent/src/mcp_server/tools.rs +603 -0
  105. package/crates/team-agent/src/mcp_server/types.rs +421 -0
  106. package/crates/team-agent/src/mcp_server/wire.rs +388 -0
  107. package/crates/team-agent/src/message_store.rs +767 -0
  108. package/crates/team-agent/src/messaging/activity.rs +433 -0
  109. package/crates/team-agent/src/messaging/delivery.rs +542 -0
  110. package/crates/team-agent/src/messaging/helpers.rs +209 -0
  111. package/crates/team-agent/src/messaging/leader_receiver.rs +340 -0
  112. package/crates/team-agent/src/messaging/mod.rs +147 -0
  113. package/crates/team-agent/src/messaging/peers.rs +32 -0
  114. package/crates/team-agent/src/messaging/results.rs +537 -0
  115. package/crates/team-agent/src/messaging/scheduler.rs +344 -0
  116. package/crates/team-agent/src/messaging/selftest.rs +100 -0
  117. package/crates/team-agent/src/messaging/send.rs +582 -0
  118. package/crates/team-agent/src/messaging/tests/basic.rs +357 -0
  119. package/crates/team-agent/src/messaging/tests/main_preserved.rs +122 -0
  120. package/crates/team-agent/src/messaging/tests/mod.rs +293 -0
  121. package/crates/team-agent/src/messaging/tests/runtime.rs +1422 -0
  122. package/crates/team-agent/src/messaging/tests/spine.rs +437 -0
  123. package/crates/team-agent/src/messaging/trust.rs +192 -0
  124. package/crates/team-agent/src/messaging/types.rs +355 -0
  125. package/crates/team-agent/src/messaging/watchers.rs +591 -0
  126. package/crates/team-agent/src/model/enums.rs +311 -0
  127. package/crates/team-agent/src/model/errors.rs +17 -0
  128. package/crates/team-agent/src/model/ids.rs +155 -0
  129. package/crates/team-agent/src/model/mod.rs +22 -0
  130. package/crates/team-agent/src/model/paths.rs +228 -0
  131. package/crates/team-agent/src/model/permissions.rs +567 -0
  132. package/crates/team-agent/src/model/routing.rs +340 -0
  133. package/crates/team-agent/src/model/spec.rs +680 -0
  134. package/crates/team-agent/src/model/task_graph.rs +380 -0
  135. package/crates/team-agent/src/model/testdata/fuzz.golden.yaml +43 -0
  136. package/crates/team-agent/src/model/testdata/fuzz.yaml +43 -0
  137. package/crates/team-agent/src/model/testdata/spec_invalid_a.yaml +207 -0
  138. package/crates/team-agent/src/model/testdata/team.spec.golden.yaml +206 -0
  139. package/crates/team-agent/src/model/testdata/team.spec.yaml +206 -0
  140. package/crates/team-agent/src/model/yaml/tests.rs +288 -0
  141. package/crates/team-agent/src/model/yaml.rs +800 -0
  142. package/crates/team-agent/src/packaging/install.rs +305 -0
  143. package/crates/team-agent/src/packaging/migrate.rs +30 -0
  144. package/crates/team-agent/src/packaging/mod.rs +82 -0
  145. package/crates/team-agent/src/packaging/repair.rs +24 -0
  146. package/crates/team-agent/src/packaging/tests.rs +829 -0
  147. package/crates/team-agent/src/packaging/types.rs +369 -0
  148. package/crates/team-agent/src/provider/adapter.rs +801 -0
  149. package/crates/team-agent/src/provider/approvals/mod.rs +2 -0
  150. package/crates/team-agent/src/provider/approvals/parsing.rs +452 -0
  151. package/crates/team-agent/src/provider/approvals/runtime_prompts.rs +163 -0
  152. package/crates/team-agent/src/provider/classify.rs +456 -0
  153. package/crates/team-agent/src/provider/faults.rs +136 -0
  154. package/crates/team-agent/src/provider/helpers.rs +41 -0
  155. package/crates/team-agent/src/provider/mod.rs +53 -0
  156. package/crates/team-agent/src/provider/startup_prompt.rs +423 -0
  157. package/crates/team-agent/src/provider/tests/adapter.rs +239 -0
  158. package/crates/team-agent/src/provider/tests/classify.rs +240 -0
  159. package/crates/team-agent/src/provider/tests/faults.rs +120 -0
  160. package/crates/team-agent/src/provider/tests/idle.rs +208 -0
  161. package/crates/team-agent/src/provider/tests/wire.rs +213 -0
  162. package/crates/team-agent/src/provider/tests.rs +31 -0
  163. package/crates/team-agent/src/provider/types.rs +424 -0
  164. package/crates/team-agent/src/state/identity.rs +656 -0
  165. package/crates/team-agent/src/state/mod.rs +58 -0
  166. package/crates/team-agent/src/state/owner_gate.rs +423 -0
  167. package/crates/team-agent/src/state/persist.rs +712 -0
  168. package/crates/team-agent/src/state/projection.rs +657 -0
  169. package/crates/team-agent/src/state/selector.rs +105 -0
  170. package/crates/team-agent/src/state/testdata/state-rich.canonical.json +133 -0
  171. package/crates/team-agent/src/tmux_backend/tests.rs +586 -0
  172. package/crates/team-agent/src/tmux_backend.rs +758 -0
  173. package/crates/team-agent/src/transport/test_support.rs +252 -0
  174. package/crates/team-agent/src/transport/tests/behavior.rs +327 -0
  175. package/crates/team-agent/src/transport/tests/mod.rs +199 -0
  176. package/crates/team-agent/src/transport/tests/wire.rs +527 -0
  177. package/crates/team-agent/src/transport.rs +774 -0
  178. package/npm/install.mjs +90 -106
  179. package/package.json +15 -13
  180. package/crates/team-agent-core/Cargo.toml +0 -12
  181. package/crates/team-agent-core/src/lib.rs +0 -332
  182. package/crates/team-agent-core/src/main.rs +0 -152
  183. package/pyproject.toml +0 -18
  184. package/scripts/install.py +0 -88
  185. package/scripts/run_regression_tests.py +0 -83
  186. package/src/team_agent/__init__.py +0 -3
  187. package/src/team_agent/__main__.py +0 -5
  188. package/src/team_agent/_legacy_pane_discovery.py +0 -186
  189. package/src/team_agent/abnormal_track.py +0 -253
  190. package/src/team_agent/approvals/__init__.py +0 -65
  191. package/src/team_agent/approvals/constants.py +0 -6
  192. package/src/team_agent/approvals/parsing.py +0 -176
  193. package/src/team_agent/approvals/runtime_prompts.py +0 -171
  194. package/src/team_agent/approvals/status.py +0 -176
  195. package/src/team_agent/cli/__init__.py +0 -137
  196. package/src/team_agent/cli/commands.py +0 -481
  197. package/src/team_agent/cli/e2e.py +0 -202
  198. package/src/team_agent/cli/helpers.py +0 -226
  199. package/src/team_agent/cli/parser.py +0 -540
  200. package/src/team_agent/compiler.py +0 -334
  201. package/src/team_agent/coordinator/__init__.py +0 -53
  202. package/src/team_agent/coordinator/__main__.py +0 -83
  203. package/src/team_agent/coordinator/lifecycle.py +0 -363
  204. package/src/team_agent/coordinator/metadata.py +0 -61
  205. package/src/team_agent/coordinator/paths.py +0 -17
  206. package/src/team_agent/diagnose/__init__.py +0 -48
  207. package/src/team_agent/diagnose/checks.py +0 -101
  208. package/src/team_agent/diagnose/comms.py +0 -213
  209. package/src/team_agent/diagnose/health.py +0 -241
  210. package/src/team_agent/diagnose/orphan_cleanup.py +0 -364
  211. package/src/team_agent/diagnose/preflight.py +0 -194
  212. package/src/team_agent/diagnose/quick_start.py +0 -324
  213. package/src/team_agent/display/__init__.py +0 -92
  214. package/src/team_agent/display/adaptive.py +0 -511
  215. package/src/team_agent/display/backend.py +0 -46
  216. package/src/team_agent/display/close.py +0 -154
  217. package/src/team_agent/display/ghostty.py +0 -77
  218. package/src/team_agent/display/rebuild.py +0 -102
  219. package/src/team_agent/display/tiling.py +0 -156
  220. package/src/team_agent/display/worker_window.py +0 -114
  221. package/src/team_agent/display/workspace.py +0 -382
  222. package/src/team_agent/errors.py +0 -10
  223. package/src/team_agent/events.py +0 -84
  224. package/src/team_agent/fake_worker.py +0 -80
  225. package/src/team_agent/idle_predicate.py +0 -200
  226. package/src/team_agent/idle_takeover.py +0 -59
  227. package/src/team_agent/idle_takeover_wiring.py +0 -111
  228. package/src/team_agent/launch/__init__.py +0 -41
  229. package/src/team_agent/launch/bootstrap.py +0 -85
  230. package/src/team_agent/launch/config.py +0 -106
  231. package/src/team_agent/launch/core.py +0 -301
  232. package/src/team_agent/launch/requirements.py +0 -57
  233. package/src/team_agent/leader/__init__.py +0 -926
  234. package/src/team_agent/leader_binding.py +0 -183
  235. package/src/team_agent/lifecycle/__init__.py +0 -5
  236. package/src/team_agent/lifecycle/agents.py +0 -278
  237. package/src/team_agent/lifecycle/operations.py +0 -411
  238. package/src/team_agent/lifecycle/paste_buffer_hygiene.py +0 -39
  239. package/src/team_agent/lifecycle/start.py +0 -363
  240. package/src/team_agent/mcp_server/__init__.py +0 -42
  241. package/src/team_agent/mcp_server/__main__.py +0 -7
  242. package/src/team_agent/mcp_server/contracts.py +0 -148
  243. package/src/team_agent/mcp_server/normalize.py +0 -257
  244. package/src/team_agent/mcp_server/server.py +0 -150
  245. package/src/team_agent/mcp_server/tools.py +0 -352
  246. package/src/team_agent/message_store/__init__.py +0 -23
  247. package/src/team_agent/message_store/agent_health.py +0 -113
  248. package/src/team_agent/message_store/core.py +0 -497
  249. package/src/team_agent/message_store/leader_notification_log.py +0 -198
  250. package/src/team_agent/message_store/result_watchers.py +0 -251
  251. package/src/team_agent/message_store/schema.py +0 -308
  252. package/src/team_agent/message_store/schema_migration.py +0 -448
  253. package/src/team_agent/messaging/__init__.py +0 -1
  254. package/src/team_agent/messaging/activity_detector.py +0 -254
  255. package/src/team_agent/messaging/delivery.py +0 -473
  256. package/src/team_agent/messaging/deps.py +0 -247
  257. package/src/team_agent/messaging/idle_alerts.py +0 -423
  258. package/src/team_agent/messaging/internal_delivery.py +0 -46
  259. package/src/team_agent/messaging/leader.py +0 -497
  260. package/src/team_agent/messaging/leader_api_errors.py +0 -216
  261. package/src/team_agent/messaging/leader_panes.py +0 -673
  262. package/src/team_agent/messaging/owner_bypass.py +0 -29
  263. package/src/team_agent/messaging/result_delivery.py +0 -539
  264. package/src/team_agent/messaging/results.py +0 -447
  265. package/src/team_agent/messaging/scheduler.py +0 -450
  266. package/src/team_agent/messaging/send.py +0 -532
  267. package/src/team_agent/messaging/session_drift.py +0 -94
  268. package/src/team_agent/messaging/tmux_io.py +0 -506
  269. package/src/team_agent/messaging/tmux_prompt.py +0 -338
  270. package/src/team_agent/messaging/trust_auto_answer.py +0 -52
  271. package/src/team_agent/orchestrator/__init__.py +0 -376
  272. package/src/team_agent/orchestrator/plan.py +0 -122
  273. package/src/team_agent/orchestrator/state.py +0 -128
  274. package/src/team_agent/paths.py +0 -45
  275. package/src/team_agent/permissions.py +0 -123
  276. package/src/team_agent/profiles/__init__.py +0 -82
  277. package/src/team_agent/profiles/constants.py +0 -19
  278. package/src/team_agent/profiles/core.py +0 -407
  279. package/src/team_agent/profiles/helpers.py +0 -69
  280. package/src/team_agent/profiles/provider_env.py +0 -188
  281. package/src/team_agent/profiles/smoke.py +0 -201
  282. package/src/team_agent/provider_cli/__init__.py +0 -43
  283. package/src/team_agent/provider_cli/adapter.py +0 -172
  284. package/src/team_agent/provider_cli/base.py +0 -48
  285. package/src/team_agent/provider_cli/claude.py +0 -457
  286. package/src/team_agent/provider_cli/codex.py +0 -336
  287. package/src/team_agent/provider_cli/copilot.py +0 -8
  288. package/src/team_agent/provider_cli/fake.py +0 -39
  289. package/src/team_agent/provider_cli/gemini.py +0 -95
  290. package/src/team_agent/provider_cli/opencode.py +0 -8
  291. package/src/team_agent/provider_cli/prompt.py +0 -62
  292. package/src/team_agent/provider_cli/registry.py +0 -18
  293. package/src/team_agent/provider_cli/unsupported.py +0 -32
  294. package/src/team_agent/provider_state/README.md +0 -78
  295. package/src/team_agent/provider_state/__init__.py +0 -86
  296. package/src/team_agent/provider_state/claude.py +0 -86
  297. package/src/team_agent/provider_state/codex.py +0 -84
  298. package/src/team_agent/provider_state/common.py +0 -207
  299. package/src/team_agent/provider_state/registry.py +0 -118
  300. package/src/team_agent/providers.py +0 -163
  301. package/src/team_agent/quality_gates.py +0 -104
  302. package/src/team_agent/restart/__init__.py +0 -34
  303. package/src/team_agent/restart/orchestration.py +0 -554
  304. package/src/team_agent/restart/selection.py +0 -89
  305. package/src/team_agent/restart/snapshot.py +0 -70
  306. package/src/team_agent/routing.py +0 -84
  307. package/src/team_agent/runtime.py +0 -1239
  308. package/src/team_agent/rust_core.py +0 -327
  309. package/src/team_agent/sessions/__init__.py +0 -25
  310. package/src/team_agent/sessions/capture.py +0 -143
  311. package/src/team_agent/sessions/inventory.py +0 -44
  312. package/src/team_agent/sessions/resume.py +0 -135
  313. package/src/team_agent/simple_yaml.py +0 -236
  314. package/src/team_agent/spec.py +0 -370
  315. package/src/team_agent/state.py +0 -602
  316. package/src/team_agent/status/__init__.py +0 -63
  317. package/src/team_agent/status/approvals.py +0 -52
  318. package/src/team_agent/status/compact.py +0 -158
  319. package/src/team_agent/status/constants.py +0 -18
  320. package/src/team_agent/status/inbox.py +0 -58
  321. package/src/team_agent/status/peek.py +0 -117
  322. package/src/team_agent/status/queries.py +0 -199
  323. package/src/team_agent/task_graph.py +0 -80
  324. package/src/team_agent/terminal.py +0 -57
  325. package/src/team_agent/wake.py +0 -58
  326. package/src/team_agent/watch/__init__.py +0 -145
@@ -1,506 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from team_agent.messaging.deps import (
4
- TMUX_PASTE_BYTES_PER_SECOND,
5
- TMUX_PASTE_MAX_READY_TIMEOUT,
6
- TMUX_PASTE_MIN_READY_TIMEOUT,
7
- TMUX_STDIN_BUFFER_THRESHOLD,
8
- TMUX_SUBMIT_BYTES_PER_SECOND,
9
- TMUX_SUBMIT_MAX_SETTLE_TIMEOUT,
10
- TMUX_SUBMIT_MIN_SETTLE_TIMEOUT,
11
- _capture_tmux_pane_text,
12
- _tmux_load_buffer_stdin as _runtime_tmux_load_buffer_stdin,
13
- _submit_worker_prompt,
14
- _wait_for_message_ready,
15
- re,
16
- run_cmd,
17
- subprocess,
18
- time,
19
- )
20
-
21
- from pathlib import Path
22
- from typing import Any
23
- from team_agent.messaging.tmux_prompt import detect_non_input_scrollback, non_input_scrollback_window
24
-
25
- def _tmux_inject_text(
26
- target: str,
27
- text: str,
28
- submit_key: str,
29
- buffer_name: str,
30
- attempts: int = 3,
31
- provider: str = "fake",
32
- *,
33
- bypass_non_input_gate: bool = False,
34
- ) -> dict[str, Any]:
35
- # Round-5 follow-up: empty-text Enter path (used by trust auto-answer to
36
- # accept Codex's default `1. Yes, continue` choice with a plain Enter).
37
- # tmux rejects set-buffer / paste-buffer of an empty string, so the
38
- # buffer-paste route would leave the trust prompt stuck. Issue
39
- # `send-keys -t <target> <submit_key>` directly and bypass the buffer
40
- # path entirely.
41
- if text == "":
42
- proc = run_cmd(["tmux", "send-keys", "-t", target, submit_key], timeout=10)
43
- if proc.returncode != 0:
44
- return {
45
- "ok": False,
46
- "stage": "send-keys",
47
- "error": proc.stderr.strip() or "tmux send-keys failed",
48
- "attempts": [
49
- {
50
- "attempt": 1,
51
- "submitted": False,
52
- "verification": "send_keys_failed",
53
- "submit_key": submit_key,
54
- }
55
- ],
56
- "verification": "send_keys_failed",
57
- }
58
- return {
59
- "ok": True,
60
- "stage": "submitted",
61
- "visible": True,
62
- "submitted": True,
63
- "verification": "empty_text_send_keys",
64
- "submit_verification": f"{submit_key}_sent_direct",
65
- "turn_verification": "not_required",
66
- "attempts": [
67
- {
68
- "attempt": 1,
69
- "submitted": True,
70
- "verification": "empty_text_send_keys",
71
- "submit_key": submit_key,
72
- }
73
- ],
74
- "submit_attempts": [
75
- {"attempt": 1, "submitted": True, "verification": "send_keys"}
76
- ],
77
- }
78
- token_match = re.search(r"\[team-agent-token:([^\]]+)\]", text)
79
- token = token_match.group(1) if token_match else ""
80
- attempt_log: list[dict[str, Any]] = []
81
- last_verification = "not_checked"
82
- ready_timeout = _tmux_paste_ready_timeout(text)
83
- submit_settle_timeout = _tmux_submit_settle_timeout(text)
84
- text_bytes = _tmux_text_size(text)
85
- for attempt in range(1, max(attempts, 1) + 1):
86
- prepared = (
87
- {"ok": True, "verification": "non_input_gate_bypassed"}
88
- if bypass_non_input_gate
89
- else _prepare_tmux_pane_for_input(target)
90
- )
91
- if not prepared["ok"]:
92
- attempt_log.append(_prepare_failure_attempt(attempt, prepared))
93
- return {
94
- "ok": False,
95
- "status": "failed",
96
- "stage": prepared["stage"],
97
- "reason": prepared.get("reason"),
98
- "error": prepared.get("error"),
99
- "attempts": attempt_log,
100
- "verification": prepared["verification"],
101
- "detected": prepared.get("detected"),
102
- "pane_id": prepared.get("pane_id"),
103
- "pane_mode": prepared.get("pane_mode"),
104
- "pane_capture_tail": prepared.get("pane_capture_tail"),
105
- }
106
- baseline = _capture_tmux_pane_text(target)
107
- if not baseline["ok"]:
108
- return {
109
- "ok": False,
110
- "stage": "pre-paste-capture",
111
- "error": baseline.get("error"),
112
- "attempts": attempt_log,
113
- "verification": "pre_paste_capture_failed",
114
- }
115
- baseline_capture = baseline["capture"]
116
- buffered = _tmux_set_buffer_text(buffer_name, text)
117
- if not buffered["ok"]:
118
- return {"ok": False, "stage": buffered["stage"], "error": buffered.get("error"), "attempts": attempt_log}
119
- proc = run_cmd(["tmux", "paste-buffer", "-t", target, "-b", buffer_name, "-p"], timeout=10)
120
- deleted = _tmux_delete_buffer(buffer_name)
121
- if proc.returncode != 0:
122
- return {
123
- "ok": False,
124
- "stage": "paste-buffer",
125
- "error": proc.stderr.strip(),
126
- "attempts": attempt_log,
127
- "buffer_deleted": deleted.get("ok"),
128
- "buffer_delete_error": deleted.get("error"),
129
- }
130
- time.sleep(0.25)
131
- if token:
132
- visible, verification, capture_text = _wait_for_message_ready(
133
- target,
134
- token,
135
- ready_timeout,
136
- expected_text=text,
137
- baseline_capture=baseline_capture,
138
- )
139
- else:
140
- visible, verification, capture_text = True, "no_token", ""
141
- last_verification = verification
142
- attempt_entry = {
143
- "attempt": attempt,
144
- "visible": visible,
145
- "verification": verification,
146
- "buffer_method": buffered.get("method"),
147
- "buffer_name": buffer_name,
148
- "buffer_deleted": deleted.get("ok"),
149
- "text_bytes": buffered.get("text_bytes"),
150
- "ready_timeout_sec": ready_timeout,
151
- }
152
- if deleted.get("error"):
153
- attempt_entry["buffer_delete_error"] = deleted.get("error")
154
- if prepared.get("recovered_from_mode"):
155
- attempt_entry["recovered_from_mode"] = True
156
- attempt_entry["recovered_from_pane_mode"] = prepared.get("pane_mode")
157
- if prepared.get("warning_event"):
158
- attempt_entry["warning_event"] = prepared["warning_event"]
159
- attempt_log.append(attempt_entry)
160
- if not visible:
161
- time.sleep(0.2)
162
- continue
163
- submit = _submit_worker_prompt(
164
- target,
165
- capture_text,
166
- submit_key=submit_key,
167
- settle_timeout=submit_settle_timeout,
168
- )
169
- if not submit["ok"]:
170
- return {
171
- "ok": False,
172
- "stage": submit.get("stage", "submit"),
173
- "error": submit.get("error"),
174
- "attempts": attempt_log,
175
- "verification": verification,
176
- "submit_verification": submit.get("verification"),
177
- "submit_attempts": submit.get("attempts"),
178
- }
179
- submit_verification = _leader_submit_verification(submit.get("verification"), verification, submit_key)
180
- # Gap 42: paste+submit success is authoritative for delivery. The post-submit
181
- # turn-boundary probe is observation metadata only, never a delivery gate — a
182
- # busy / compacting recipient that has not yet shown a new prompt marker is
183
- # still a successful delivery. Real paste/submit failures are caught and
184
- # returned above; this point is only reached after submit reported ok.
185
- turn_visible, turn_verification, turn_capture = _wait_for_leader_new_turn(
186
- target,
187
- text,
188
- token,
189
- provider=provider,
190
- timeout=2.0,
191
- )
192
- if not turn_visible:
193
- turn_verification = "not_yet_observed"
194
- return {
195
- "ok": True,
196
- "stage": "submitted",
197
- "visible": True,
198
- "submitted": True,
199
- "verification": verification,
200
- "submit_verification": submit_verification,
201
- "turn_verification": turn_verification,
202
- "attempts": attempt_log,
203
- "submit_attempts": submit.get("attempts"),
204
- }
205
- return {
206
- "ok": False,
207
- "stage": "visible-check",
208
- "error": f"visible token not found after {max(attempts, 1)} attempts: {last_verification}",
209
- "attempts": attempt_log,
210
- "verification": last_verification,
211
- }
212
-
213
-
214
- def _leader_submit_verification(submit_verification: str | None, verification: str, submit_key: str) -> str | None:
215
- if submit_verification != "enter_sent_without_placeholder_check":
216
- return submit_verification
217
- if verification == "capture_contains_token":
218
- return f"{submit_key}_sent_after_visible_token"
219
- if verification == "capture_contains_message_fragment":
220
- return f"{submit_key}_sent_after_visible_fragment"
221
- return submit_verification
222
-
223
-
224
- def _wait_for_leader_new_turn(
225
- target: str,
226
- expected_text: str,
227
- token: str,
228
- provider: str,
229
- timeout: float,
230
- ) -> tuple[bool, str, str]:
231
- deadline = time.monotonic() + max(timeout, 0.0)
232
- last = "not_checked"
233
- last_capture = ""
234
- while True:
235
- capture = _capture_tmux_pane_text(target)
236
- if capture["ok"]:
237
- capture_text = capture["capture"]
238
- last_capture = capture_text
239
- if _capture_has_leader_new_turn(capture_text, expected_text, token, provider):
240
- return True, "leader_new_turn_boundary_verified", capture_text
241
- last = "leader_new_turn_boundary_missing"
242
- else:
243
- last = f"capture_failed: {capture.get('error')}"
244
- if time.monotonic() >= deadline:
245
- return False, last, last_capture
246
- time.sleep(0.1)
247
-
248
-
249
- def _capture_has_leader_new_turn(capture_text: str, expected_text: str, token: str, provider: str) -> bool:
250
- if provider == "fake":
251
- return True
252
- lines = capture_text.splitlines()
253
- marker_indexes = [index for index, line in enumerate(lines) if re.match(r"^\s*[❯›>]\s*", line)]
254
- for index in marker_indexes:
255
- window = "\n".join(lines[index : index + 12])
256
- if token and token in window:
257
- return True
258
- if _leader_turn_contains_message_fragment(window, expected_text):
259
- return True
260
- return False
261
-
262
-
263
- def _leader_turn_contains_message_fragment(capture_text: str, expected_text: str) -> bool:
264
- haystack = re.sub(r"\s+", "", capture_text)
265
- for line in expected_text.splitlines():
266
- compact = re.sub(r"\s+", "", re.sub(r"\[team-agent-token:[^\]]+\]", "", line))
267
- if len(compact) >= 18 and compact in haystack:
268
- return True
269
- return False
270
-
271
-
272
- def _tmux_text_size(text: str) -> int:
273
- return len(text.encode("utf-8"))
274
-
275
-
276
- def _tmux_paste_ready_timeout(text: str) -> float:
277
- size = _tmux_text_size(text)
278
- return min(
279
- TMUX_PASTE_MAX_READY_TIMEOUT,
280
- max(TMUX_PASTE_MIN_READY_TIMEOUT, size / TMUX_PASTE_BYTES_PER_SECOND),
281
- )
282
-
283
-
284
- def _tmux_submit_settle_timeout(text: str) -> float:
285
- size = _tmux_text_size(text)
286
- return min(
287
- TMUX_SUBMIT_MAX_SETTLE_TIMEOUT,
288
- max(TMUX_SUBMIT_MIN_SETTLE_TIMEOUT, size / TMUX_SUBMIT_BYTES_PER_SECOND),
289
- )
290
-
291
-
292
- def _tmux_set_buffer_text(buffer_name: str, text: str) -> dict[str, Any]:
293
- size = _tmux_text_size(text)
294
- if size >= TMUX_STDIN_BUFFER_THRESHOLD:
295
- proc = _runtime_tmux_load_buffer_stdin(buffer_name, text)
296
- return {
297
- "ok": proc.returncode == 0,
298
- "stage": "load-buffer",
299
- "method": "stdin_load_buffer",
300
- "text_bytes": size,
301
- "error": proc.stderr.strip() if proc.returncode != 0 else None,
302
- }
303
- proc = run_cmd(["tmux", "set-buffer", "-b", buffer_name, text], timeout=10)
304
- return {
305
- "ok": proc.returncode == 0,
306
- "stage": "set-buffer",
307
- "method": "set_buffer_arg",
308
- "text_bytes": size,
309
- "error": proc.stderr.strip() if proc.returncode != 0 else None,
310
- }
311
-
312
-
313
- def _tmux_delete_buffer(buffer_name: str) -> dict[str, Any]:
314
- proc = run_cmd(["tmux", "delete-buffer", "-b", buffer_name], timeout=10)
315
- return {
316
- "ok": proc.returncode == 0,
317
- "stage": "delete-buffer",
318
- "error": proc.stderr.strip() if proc.returncode != 0 else None,
319
- }
320
-
321
-
322
- def _tmux_load_buffer_stdin(buffer_name: str, text: str) -> subprocess.CompletedProcess[str]:
323
- return subprocess.run(
324
- ["tmux", "load-buffer", "-b", buffer_name, "-"],
325
- input=text,
326
- text=True,
327
- capture_output=True,
328
- timeout=10,
329
- check=False,
330
- )
331
-
332
-
333
- def _prepare_tmux_pane_for_input(target: str) -> dict[str, Any]:
334
- mode_result = _pane_mode(target)
335
- if not mode_result["ok"]:
336
- return {
337
- "ok": False,
338
- "stage": "pane-mode-check",
339
- "verification": "pane_mode_check_failed",
340
- "error": mode_result.get("error") or "tmux pane mode check failed",
341
- }
342
- capture_result = _pane_capture_tail(target, lines=30)
343
- if not capture_result["ok"]:
344
- return {
345
- "ok": False,
346
- "stage": "pane-tail-capture",
347
- "verification": "pane_tail_capture_failed",
348
- "error": capture_result.get("error") or "tmux capture-pane failed",
349
- }
350
- pane_mode = _normalize_pane_mode(mode_result.get("pane_mode"))
351
- capture_tail = str(capture_result.get("capture") or "")
352
- detected = detect_non_input_scrollback(capture_tail)
353
- if detected:
354
- return _non_input_refusal(target, pane_mode, capture_tail, detected)
355
- if not pane_mode:
356
- return {"ok": True, "verification": "pane_input_ready"}
357
- cancel = _pane_mode_cancel(target, pane_mode)
358
- if not cancel["ok"]:
359
- return _non_input_refusal(
360
- target,
361
- pane_mode,
362
- capture_tail,
363
- f"tmux_{pane_mode}",
364
- error=cancel.get("error") or "tmux pane mode cancel failed",
365
- verification="pane_mode_cancel_failed",
366
- warning_event=cancel.get("warning_event"),
367
- )
368
- warning_event = cancel.get("warning_event")
369
- deadline = time.monotonic() + 1.5
370
- while True:
371
- check = _pane_mode(target)
372
- if not check["ok"]:
373
- return {
374
- "ok": False,
375
- "stage": "pane-mode-check",
376
- "verification": "pane_mode_recheck_failed",
377
- "error": check.get("error") or "tmux pane mode recheck failed",
378
- }
379
- if not _normalize_pane_mode(check.get("pane_mode")):
380
- result = {
381
- "ok": True,
382
- "verification": "pane_input_ready_after_mode_cancel",
383
- "recovered_from_mode": True,
384
- "pane_mode": pane_mode,
385
- }
386
- if warning_event:
387
- result["warning_event"] = warning_event
388
- return result
389
- if time.monotonic() >= deadline:
390
- return _non_input_refusal(
391
- target,
392
- pane_mode,
393
- capture_tail,
394
- f"tmux_{pane_mode}",
395
- error=f"tmux pane stayed in {pane_mode} after cancel",
396
- verification="pane_mode_still_active_after_cancel",
397
- warning_event=warning_event,
398
- )
399
- time.sleep(0.1)
400
-
401
-
402
- def _pane_mode(target: str) -> dict[str, Any]:
403
- proc = run_cmd(["tmux", "display-message", "-p", "-t", target, "#{pane_mode}"], timeout=5)
404
- if proc.returncode != 0:
405
- return {"ok": False, "error": proc.stderr.strip() or "tmux pane mode check failed"}
406
- return {"ok": True, "pane_mode": proc.stdout.strip()}
407
-
408
-
409
- def _pane_capture_tail(target: str, lines: int = 30) -> dict[str, Any]:
410
- capture = run_cmd(["tmux", "capture-pane", "-p", "-S", f"-{lines}", "-t", target], timeout=5)
411
- if capture.returncode != 0:
412
- return {"ok": False, "capture": "", "error": capture.stderr.strip() or "tmux capture-pane failed"}
413
- return {"ok": True, "capture": capture.stdout}
414
-
415
-
416
- def _pane_mode_cancel(target: str, pane_mode: str) -> dict[str, Any]:
417
- mode = _normalize_pane_mode(pane_mode)
418
- warning_event = None
419
- if mode == "copy-mode":
420
- args = ["tmux", "send-keys", "-t", target, "-X", "cancel"]
421
- elif mode in {"tree-mode", "view-mode"}:
422
- args = ["tmux", "send-keys", "-t", target, "q"]
423
- elif mode == "client-mode":
424
- args = ["tmux", "send-keys", "-t", target, "d"]
425
- else:
426
- args = ["tmux", "send-keys", "-t", target, "-X", "cancel"]
427
- warning_event = "pane_mode_unknown_cancel_attempted"
428
- cancel = run_cmd(args, timeout=10)
429
- if cancel.returncode != 0:
430
- return {
431
- "ok": False,
432
- "error": cancel.stderr.strip() or f"tmux {mode or 'unknown'} cancel failed",
433
- "warning_event": warning_event,
434
- }
435
- result = {"ok": True, "mode": mode, "args": args}
436
- if warning_event:
437
- result["warning_event"] = warning_event
438
- return result
439
-
440
-
441
- def _normalize_pane_mode(mode: Any) -> str:
442
- value = str(mode or "").strip()
443
- if value == "0":
444
- return ""
445
- if value == "1":
446
- return "copy-mode"
447
- return value
448
-
449
-
450
- def _non_input_refusal(
451
- target: str,
452
- pane_mode: str,
453
- capture_tail: str,
454
- detected: str,
455
- *,
456
- error: str | None = None,
457
- verification: str = "recipient_pane_in_non_input_mode",
458
- warning_event: str | None = None,
459
- ) -> dict[str, Any]:
460
- result = {
461
- "ok": False,
462
- "status": "failed",
463
- "stage": "pre-paste-pane-state",
464
- "reason": "recipient_pane_in_non_input_mode",
465
- "error": error or "recipient_pane_in_non_input_mode",
466
- "verification": verification,
467
- "detected": detected,
468
- "pane_id": target,
469
- "pane_mode": pane_mode,
470
- "pane_capture_tail": non_input_scrollback_window(capture_tail) or _last_lines(capture_tail, 10),
471
- }
472
- if warning_event:
473
- result["warning_event"] = warning_event
474
- return result
475
-
476
-
477
- def _prepare_failure_attempt(attempt: int, prepared: dict[str, Any]) -> dict[str, Any]:
478
- entry = {
479
- "attempt": attempt,
480
- "visible": False,
481
- "verification": prepared["verification"],
482
- }
483
- for key in ("reason", "detected", "pane_id", "pane_mode", "pane_capture_tail", "warning_event"):
484
- if key in prepared:
485
- entry[key] = prepared[key]
486
- return entry
487
-
488
-
489
- def _last_lines(text: str, count: int) -> str:
490
- lines = text.splitlines()
491
- return "\n".join(lines[-count:])
492
-
493
-
494
-
495
-
496
-
497
-
498
-
499
-
500
-
501
-
502
-
503
-
504
-
505
-
506
-