@zergai/ztc 0.4.0-beta.1 → 0.5.0-beta.1

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 (718) hide show
  1. package/README.md +398 -45
  2. package/RUST_THIRD_PARTY_LICENSES.txt +1080 -822
  3. package/THIRD_PARTY_NOTICES.md +273 -12
  4. package/bin/zmux-darwin-arm64 +0 -0
  5. package/bin/ztc-audio-darwin-arm64 +0 -0
  6. package/bin/ztc-capture-darwin-arm64 +0 -0
  7. package/bin/ztc-computer-darwin-arm64 +0 -0
  8. package/bin/ztc-llm-darwin-arm64 +0 -0
  9. package/bin/ztc-tts-darwin-arm64 +0 -0
  10. package/bin/ztc-tui-darwin-arm64 +0 -0
  11. package/bin/ztc-zlicky-overlay-darwin-arm64 +0 -0
  12. package/bin/zterm-darwin-arm64 +0 -0
  13. package/dist/App.js +1206 -209
  14. package/dist/agent/agent.d.ts +74 -8
  15. package/dist/agent/agent.js +1073 -184
  16. package/dist/agent/backends/account_rotation.d.ts +4 -0
  17. package/dist/agent/backends/account_rotation.js +8 -2
  18. package/dist/agent/backends/anthropic.d.ts +13 -0
  19. package/dist/agent/backends/anthropic.js +169 -28
  20. package/dist/agent/backends/claude_cli.js +18 -8
  21. package/dist/agent/backends/codex_app_server.d.ts +1 -0
  22. package/dist/agent/backends/codex_app_server.js +55 -3
  23. package/dist/agent/backends/codex_auth.d.ts +1 -0
  24. package/dist/agent/backends/codex_auth.js +67 -13
  25. package/dist/agent/backends/codex_buffered_recovery.d.ts +27 -0
  26. package/dist/agent/backends/codex_buffered_recovery.js +293 -0
  27. package/dist/agent/backends/gemini.js +3 -1
  28. package/dist/agent/backends/http_error.d.ts +26 -0
  29. package/dist/agent/backends/http_error.js +221 -0
  30. package/dist/agent/backends/index.d.ts +9 -2
  31. package/dist/agent/backends/index.js +22 -2
  32. package/dist/agent/backends/openai.d.ts +0 -6
  33. package/dist/agent/backends/openai.js +5 -2
  34. package/dist/agent/backends/openai_compatible.d.ts +5 -4
  35. package/dist/agent/backends/openai_compatible.js +26 -19
  36. package/dist/agent/backends/openai_responses.d.ts +8 -3
  37. package/dist/agent/backends/openai_responses.js +77 -33
  38. package/dist/agent/backends/provider_ids.d.ts +1 -0
  39. package/dist/agent/backends/provider_ids.js +4 -0
  40. package/dist/agent/backends/request_metrics.js +12 -2
  41. package/dist/agent/backends/types.d.ts +109 -6
  42. package/dist/agent/backends/types.js +5 -1
  43. package/dist/agent/backends/zrouter_stream.d.ts +6 -1
  44. package/dist/agent/backends/zrouter_stream.js +160 -42
  45. package/dist/agent/background_registry.d.ts +2 -0
  46. package/dist/agent/background_registry.js +1 -0
  47. package/dist/agent/claim_observation.d.ts +6 -0
  48. package/dist/agent/claim_observation.js +54 -0
  49. package/dist/agent/commands/accounts.js +46 -177
  50. package/dist/agent/commands/attention.d.ts +2 -0
  51. package/dist/agent/commands/attention.js +67 -0
  52. package/dist/agent/commands/auth.js +18 -2
  53. package/dist/agent/commands/board.d.ts +2 -0
  54. package/dist/agent/commands/board.js +169 -0
  55. package/dist/agent/commands/clipboard.js +50 -1
  56. package/dist/agent/commands/compact.js +21 -13
  57. package/dist/agent/commands/config.js +4 -1
  58. package/dist/agent/commands/context.js +6 -1
  59. package/dist/agent/commands/desktop.d.ts +2 -0
  60. package/dist/agent/commands/desktop.js +29 -0
  61. package/dist/agent/commands/effort.js +14 -6
  62. package/dist/agent/commands/environment.d.ts +3 -0
  63. package/dist/agent/commands/environment.js +109 -0
  64. package/dist/agent/commands/evidence.d.ts +2 -0
  65. package/dist/agent/commands/evidence.js +9 -0
  66. package/dist/agent/commands/fork.js +4 -3
  67. package/dist/agent/commands/goal.d.ts +33 -1
  68. package/dist/agent/commands/goal.js +174 -14
  69. package/dist/agent/commands/goal_exit.d.ts +36 -0
  70. package/dist/agent/commands/goal_exit.js +120 -0
  71. package/dist/agent/commands/help.js +3 -1
  72. package/dist/agent/commands/history.js +3 -1
  73. package/dist/agent/commands/inbox.d.ts +2 -0
  74. package/dist/agent/commands/inbox.js +148 -0
  75. package/dist/agent/commands/index.js +16 -1
  76. package/dist/agent/commands/input_mode.js +8 -6
  77. package/dist/agent/commands/job.d.ts +2 -0
  78. package/dist/agent/commands/job.js +93 -0
  79. package/dist/agent/commands/keybindings.js +4 -1
  80. package/dist/agent/commands/label.d.ts +2 -0
  81. package/dist/agent/commands/label.js +77 -0
  82. package/dist/agent/commands/layout.d.ts +2 -0
  83. package/dist/agent/commands/layout.js +20 -0
  84. package/dist/agent/commands/mirror.js +16 -1
  85. package/dist/agent/commands/model.js +12 -2
  86. package/dist/agent/commands/permissions.d.ts +3 -1
  87. package/dist/agent/commands/permissions.js +79 -89
  88. package/dist/agent/commands/plan.js +5 -15
  89. package/dist/agent/commands/profile.js +21 -2
  90. package/dist/agent/commands/provider_selection.js +20 -1
  91. package/dist/agent/commands/rename.js +1 -1
  92. package/dist/agent/commands/resources.d.ts +2 -0
  93. package/dist/agent/commands/resources.js +67 -0
  94. package/dist/agent/commands/rewind.d.ts +3 -0
  95. package/dist/agent/commands/rewind.js +16 -0
  96. package/dist/agent/commands/runbooks.d.ts +2 -0
  97. package/dist/agent/commands/runbooks.js +73 -0
  98. package/dist/agent/commands/runbooks_lazy.d.ts +2 -0
  99. package/dist/agent/commands/runbooks_lazy.js +8 -0
  100. package/dist/agent/commands/sessions.d.ts +1 -1
  101. package/dist/agent/commands/sessions.js +33 -5
  102. package/dist/agent/commands/settings.js +185 -39
  103. package/dist/agent/commands/setup.d.ts +2 -0
  104. package/dist/agent/commands/setup.js +78 -0
  105. package/dist/agent/commands/share.d.ts +2 -0
  106. package/dist/agent/commands/share.js +64 -0
  107. package/dist/agent/commands/status.js +14 -2
  108. package/dist/agent/commands/types.d.ts +99 -6
  109. package/dist/agent/commands/update.js +8 -0
  110. package/dist/agent/commands/usage.d.ts +2 -0
  111. package/dist/agent/commands/usage.js +8 -0
  112. package/dist/agent/factory.d.ts +11 -0
  113. package/dist/agent/factory.js +113 -88
  114. package/dist/agent/loop_policy.d.ts +6 -3
  115. package/dist/agent/loop_policy.js +12 -3
  116. package/dist/agent/measurement_guidance.d.ts +2 -0
  117. package/dist/agent/measurement_guidance.js +5 -0
  118. package/dist/agent/request_encoder.d.ts +8 -1
  119. package/dist/agent/request_encoder.js +95 -23
  120. package/dist/agent/runtime/benchmark_comparison.d.ts +30 -0
  121. package/dist/agent/runtime/benchmark_comparison.js +94 -0
  122. package/dist/agent/runtime/benchmark_contract.d.ts +48 -0
  123. package/dist/agent/runtime/benchmark_contract.js +90 -0
  124. package/dist/agent/runtime/checked_commands.d.ts +32 -0
  125. package/dist/agent/runtime/checked_commands.js +119 -0
  126. package/dist/agent/runtime/command_execution_policy.d.ts +26 -0
  127. package/dist/agent/runtime/command_execution_policy.js +91 -0
  128. package/dist/agent/runtime/command_jobs.d.ts +36 -18
  129. package/dist/agent/runtime/command_jobs.js +151 -13
  130. package/dist/agent/runtime/command_panes.d.ts +59 -0
  131. package/dist/agent/runtime/command_panes.js +398 -0
  132. package/dist/agent/runtime/command_wait.d.ts +19 -0
  133. package/dist/agent/runtime/command_wait.js +167 -0
  134. package/dist/agent/runtime/cpu_benchmark.d.ts +30 -0
  135. package/dist/agent/runtime/cpu_benchmark.js +126 -0
  136. package/dist/agent/runtime/delegated_evidence.d.ts +26 -0
  137. package/dist/agent/runtime/delegated_evidence.js +80 -0
  138. package/dist/agent/runtime/evidence.d.ts +127 -0
  139. package/dist/agent/runtime/evidence.js +468 -0
  140. package/dist/agent/runtime/execution_context.d.ts +7 -0
  141. package/dist/agent/runtime/execution_context.js +39 -3
  142. package/dist/agent/runtime/json_verifier_recipe.d.ts +8 -0
  143. package/dist/agent/runtime/json_verifier_recipe.js +66 -0
  144. package/dist/agent/runtime/measurements.d.ts +110 -0
  145. package/dist/agent/runtime/measurements.js +317 -0
  146. package/dist/agent/runtime/policy.d.ts +4 -0
  147. package/dist/agent/runtime/policy.js +31 -20
  148. package/dist/agent/runtime/provider_native_evidence.d.ts +20 -0
  149. package/dist/agent/runtime/provider_native_evidence.js +86 -0
  150. package/dist/agent/runtime/recovery.d.ts +2 -0
  151. package/dist/agent/runtime/recovery.js +45 -2
  152. package/dist/agent/runtime/remote_broker_transport.d.ts +10 -0
  153. package/dist/agent/runtime/remote_broker_transport.js +84 -0
  154. package/dist/agent/runtime/remote_deletion_receipts.d.ts +3 -0
  155. package/dist/agent/runtime/remote_deletion_receipts.js +43 -0
  156. package/dist/agent/runtime/remote_journal_replay.d.ts +13 -0
  157. package/dist/agent/runtime/remote_journal_replay.js +233 -0
  158. package/dist/agent/runtime/remote_mutation_journal.d.ts +25 -0
  159. package/dist/agent/runtime/remote_mutation_journal.js +208 -0
  160. package/dist/agent/runtime/remote_resource_endpoint.d.ts +7 -0
  161. package/dist/agent/runtime/remote_resource_endpoint.js +6 -0
  162. package/dist/agent/runtime/remote_resource_errors.d.ts +5 -0
  163. package/dist/agent/runtime/remote_resource_errors.js +9 -0
  164. package/dist/agent/runtime/remote_resource_script.d.ts +2 -0
  165. package/dist/agent/runtime/remote_resource_script.js +1009 -0
  166. package/dist/agent/runtime/remote_resources.d.ts +29 -0
  167. package/dist/agent/runtime/remote_resources.js +160 -0
  168. package/dist/agent/runtime/source_verification.d.ts +12 -0
  169. package/dist/agent/runtime/source_verification.js +210 -0
  170. package/dist/agent/runtime/source_verification_contract.d.ts +75 -0
  171. package/dist/agent/runtime/source_verification_contract.js +203 -0
  172. package/dist/agent/runtime/tool_checkpoints.d.ts +11 -0
  173. package/dist/agent/runtime/tool_checkpoints.js +26 -0
  174. package/dist/agent/runtime/tool_effects.d.ts +5 -0
  175. package/dist/agent/runtime/tool_progress.d.ts +12 -0
  176. package/dist/agent/runtime/tool_progress.js +76 -0
  177. package/dist/agent/runtime/tool_runtime.d.ts +16 -1
  178. package/dist/agent/runtime/tool_runtime.js +204 -10
  179. package/dist/agent/runtime/tracing.d.ts +1 -1
  180. package/dist/agent/runtime/verifier_capture.d.ts +9 -0
  181. package/dist/agent/runtime/verifier_capture.js +100 -0
  182. package/dist/agent/runtime/verifier_contract.d.ts +24 -0
  183. package/dist/agent/runtime/verifier_contract.js +41 -0
  184. package/dist/agent/subagent.d.ts +20 -10
  185. package/dist/agent/subagent.js +266 -29
  186. package/dist/agent/tool_response_directory.d.ts +24 -0
  187. package/dist/agent/tool_response_directory.js +61 -0
  188. package/dist/agent/tool_response_source.d.ts +8 -0
  189. package/dist/agent/tool_response_source.js +49 -0
  190. package/dist/agent/tool_response_store.d.ts +75 -4
  191. package/dist/agent/tool_response_store.js +583 -64
  192. package/dist/agent/tools/ask_user.d.ts +3 -1
  193. package/dist/agent/tools/ask_user.js +30 -11
  194. package/dist/agent/tools/background.js +1 -0
  195. package/dist/agent/tools/benchmark_cpu.d.ts +2 -0
  196. package/dist/agent/tools/benchmark_cpu.js +102 -0
  197. package/dist/agent/tools/compare_benchmarks.d.ts +2 -0
  198. package/dist/agent/tools/compare_benchmarks.js +53 -0
  199. package/dist/agent/tools/deferred.js +1 -0
  200. package/dist/agent/tools/delegate.js +18 -2
  201. package/dist/agent/tools/helper_requirements.d.ts +7 -0
  202. package/dist/agent/tools/helper_requirements.js +19 -0
  203. package/dist/agent/tools/index.d.ts +1 -0
  204. package/dist/agent/tools/index.js +3 -0
  205. package/dist/agent/tools/measurement_report.d.ts +22 -0
  206. package/dist/agent/tools/measurement_report.js +190 -0
  207. package/dist/agent/tools/pane.d.ts +0 -7
  208. package/dist/agent/tools/pane.js +5 -4
  209. package/dist/agent/tools/project_context.d.ts +3 -0
  210. package/dist/agent/tools/project_context.js +45 -0
  211. package/dist/agent/tools/recall_tool_response.d.ts +3 -5
  212. package/dist/agent/tools/recall_tool_response.js +19 -29
  213. package/dist/agent/tools/registry.d.ts +1 -0
  214. package/dist/agent/tools/registry.js +23 -0
  215. package/dist/agent/tools/related_sessions.d.ts +2 -0
  216. package/dist/agent/tools/related_sessions.js +156 -0
  217. package/dist/agent/tools/routine.js +13 -3
  218. package/dist/agent/tools/session_evidence.d.ts +3 -0
  219. package/dist/agent/tools/session_evidence.js +72 -0
  220. package/dist/agent/tools/shell.d.ts +4 -3
  221. package/dist/agent/tools/shell.js +174 -47
  222. package/dist/agent/tools/tool_search.js +3 -2
  223. package/dist/agent/tools/types.d.ts +28 -0
  224. package/dist/agent/tools/verify_artifact.d.ts +2 -0
  225. package/dist/agent/tools/verify_artifact.js +60 -0
  226. package/dist/agent/tools/workflow.js +1 -0
  227. package/dist/app/activity.d.ts +6 -1
  228. package/dist/app/activity.js +81 -12
  229. package/dist/app/agent_runner.d.ts +6 -1
  230. package/dist/app/agent_runner.js +34 -19
  231. package/dist/app/command_context.js +106 -10
  232. package/dist/app/controller.d.ts +15 -4
  233. package/dist/app/controller.js +29 -3
  234. package/dist/app/escape_stop.d.ts +11 -0
  235. package/dist/app/escape_stop.js +15 -0
  236. package/dist/app/liveness.d.ts +6 -4
  237. package/dist/app/liveness.js +13 -3
  238. package/dist/app/model_catalog_cache.d.ts +5 -0
  239. package/dist/app/model_catalog_cache.js +138 -0
  240. package/dist/app/ordered_transcript.js +43 -4
  241. package/dist/app/prompt_turn.d.ts +14 -0
  242. package/dist/app/prompt_turn.js +53 -0
  243. package/dist/app/recap.d.ts +3 -0
  244. package/dist/app/recap.js +9 -3
  245. package/dist/app/restart.d.ts +3 -2
  246. package/dist/app/restart.js +22 -7
  247. package/dist/app/rewind.d.ts +3 -3
  248. package/dist/app/rewind.js +3 -3
  249. package/dist/app/selection_completion.d.ts +17 -2
  250. package/dist/app/selection_completion.js +84 -9
  251. package/dist/app/session_manager.d.ts +38 -6
  252. package/dist/app/session_manager.js +263 -60
  253. package/dist/app/session_messages.d.ts +3 -0
  254. package/dist/app/session_messages.js +60 -0
  255. package/dist/app/task_scope_router.d.ts +20 -0
  256. package/dist/app/task_scope_router.js +173 -0
  257. package/dist/app/transcript_window.d.ts +2 -0
  258. package/dist/app/transcript_window.js +4 -0
  259. package/dist/app/workspace_admission_details.d.ts +3 -0
  260. package/dist/app/workspace_admission_details.js +26 -0
  261. package/dist/app/workspace_layout_controller.d.ts +11 -0
  262. package/dist/app/workspace_layout_controller.js +88 -0
  263. package/dist/app/workspace_monitor.d.ts +1 -0
  264. package/dist/app/workspace_monitor.js +216 -0
  265. package/dist/app/workspace_presets.d.ts +29 -0
  266. package/dist/app/workspace_presets.js +192 -0
  267. package/dist/attention/queue.d.ts +37 -0
  268. package/dist/attention/queue.js +183 -0
  269. package/dist/bench/rf_shared.d.ts +2 -0
  270. package/dist/board/binding.d.ts +42 -0
  271. package/dist/board/binding.js +38 -0
  272. package/dist/board/client.d.ts +42 -0
  273. package/dist/board/client.js +60 -0
  274. package/dist/cli.js +1 -1
  275. package/dist/cli_args.js +19 -17
  276. package/dist/cli_main.js +110 -13
  277. package/dist/cli_ratatui.d.ts +183 -16
  278. package/dist/cli_ratatui.js +3989 -1255
  279. package/dist/components/ActivityLine.d.ts +3 -2
  280. package/dist/components/ActivityLine.js +2 -2
  281. package/dist/components/InputArea.d.ts +19 -1
  282. package/dist/components/InputArea.js +264 -190
  283. package/dist/components/MessageList.d.ts +2 -0
  284. package/dist/components/MessageList.js +3 -1
  285. package/dist/components/SingleMessage.d.ts +2 -0
  286. package/dist/components/SingleMessage.js +4 -2
  287. package/dist/components/StatusBar.d.ts +4 -2
  288. package/dist/components/StatusBar.js +3 -1
  289. package/dist/conductor_branch.js +3 -0
  290. package/dist/config/api_retry.d.ts +6 -1
  291. package/dist/config/api_retry.js +19 -1
  292. package/dist/config/defaults.d.ts +2 -1
  293. package/dist/config/defaults.js +9 -2
  294. package/dist/config/message_display.d.ts +1 -0
  295. package/dist/config/message_display.js +17 -2
  296. package/dist/config/permissions.d.ts +21 -0
  297. package/dist/config/permissions.js +89 -0
  298. package/dist/config/resolved.d.ts +2 -2
  299. package/dist/config/types.d.ts +32 -5
  300. package/dist/config.d.ts +38 -4
  301. package/dist/config.js +290 -42
  302. package/dist/context/project_intelligence.d.ts +44 -0
  303. package/dist/context/project_intelligence.js +246 -0
  304. package/dist/desktop/cli_launch.d.ts +8 -0
  305. package/dist/desktop/cli_launch.js +6 -0
  306. package/dist/desktop/cli_shim.d.ts +8 -0
  307. package/dist/desktop/cli_shim.js +120 -0
  308. package/dist/desktop/runtime.d.ts +16 -0
  309. package/dist/desktop/runtime.js +161 -0
  310. package/dist/desktop/worker_launch.d.ts +7 -0
  311. package/dist/desktop/worker_launch.js +7 -0
  312. package/dist/diagnostics/cargo_mutants_selection.d.ts +27 -0
  313. package/dist/diagnostics/cargo_mutants_selection.js +48 -0
  314. package/dist/diagnostics/native_terminal_benchmark.d.ts +58 -0
  315. package/dist/diagnostics/native_terminal_benchmark.js +1247 -0
  316. package/dist/diagnostics/session_evidence_package.d.ts +40 -0
  317. package/dist/diagnostics/session_evidence_package.js +234 -0
  318. package/dist/diagnostics/session_export.d.ts +93 -0
  319. package/dist/diagnostics/session_export.js +634 -0
  320. package/dist/emulation/tool_adapters.js +48 -18
  321. package/dist/emulation/ztc_addendum.d.ts +1 -0
  322. package/dist/emulation/ztc_addendum.js +13 -12
  323. package/dist/environment/service_runner.d.ts +1 -0
  324. package/dist/environment/service_runner.js +68 -0
  325. package/dist/environment/store.d.ts +120 -0
  326. package/dist/environment/store.js +387 -0
  327. package/dist/events.d.ts +40 -1
  328. package/dist/events.js +10 -17
  329. package/dist/goal_contract.d.ts +25 -0
  330. package/dist/goal_contract.js +44 -0
  331. package/dist/headless.d.ts +31 -0
  332. package/dist/headless.js +578 -70
  333. package/dist/headless_cli.js +8 -0
  334. package/dist/headless_cli_args.d.ts +1 -0
  335. package/dist/headless_cli_args.js +1 -0
  336. package/dist/intake/cli.d.ts +1 -0
  337. package/dist/intake/cli.js +33 -0
  338. package/dist/intake/format.d.ts +2 -0
  339. package/dist/intake/format.js +14 -0
  340. package/dist/intake/notifications.d.ts +16 -0
  341. package/dist/intake/notifications.js +132 -0
  342. package/dist/intake/store.d.ts +56 -0
  343. package/dist/intake/store.js +238 -0
  344. package/dist/library.d.ts +8 -0
  345. package/dist/library.js +19 -10
  346. package/dist/mcp/client.d.ts +1 -0
  347. package/dist/mcp/client.js +20 -0
  348. package/dist/modes/builtin/plan.yaml +2 -2
  349. package/dist/modes/handlers.js +1 -1
  350. package/dist/onboarding/first_run.d.ts +3 -0
  351. package/dist/onboarding/first_run.js +33 -25
  352. package/dist/onboarding/setup.d.ts +32 -0
  353. package/dist/onboarding/setup.js +133 -0
  354. package/dist/onboarding/setup_agent_health.d.ts +17 -0
  355. package/dist/onboarding/setup_agent_health.js +79 -0
  356. package/dist/onboarding/setup_environment.d.ts +66 -0
  357. package/dist/onboarding/setup_environment.js +219 -0
  358. package/dist/onboarding/setup_workspace.d.ts +17 -0
  359. package/dist/onboarding/setup_workspace.js +129 -0
  360. package/dist/optimize/adapters/index.d.ts +4 -1
  361. package/dist/optimize/adapters/index.js +7 -0
  362. package/dist/optimize/adapters/kernelbench.js +14 -5
  363. package/dist/optimize/adapters/popcorn.js +3 -2
  364. package/dist/optimize/adapters/profile_benchmark.js +13 -7
  365. package/dist/optimize/adapters/rfbench.js +25 -14
  366. package/dist/optimize/adapters/types.d.ts +3 -0
  367. package/dist/optimize/adapters/zergpod.js +5 -2
  368. package/dist/optimize/baseline.js +10 -21
  369. package/dist/optimize/branch.js +9 -12
  370. package/dist/optimize/combine.js +2 -3
  371. package/dist/optimize/executor.js +34 -48
  372. package/dist/optimize/measurements.d.ts +55 -0
  373. package/dist/optimize/measurements.js +173 -0
  374. package/dist/optimize/results.d.ts +1 -0
  375. package/dist/optimize/results.js +11 -33
  376. package/dist/optimize/tge.js +2 -1
  377. package/dist/panes/initial_input.d.ts +19 -0
  378. package/dist/panes/initial_input.js +206 -0
  379. package/dist/panes/labels.d.ts +16 -0
  380. package/dist/panes/labels.js +42 -0
  381. package/dist/panes/model_catalog.d.ts +3 -3
  382. package/dist/panes/model_catalog.js +28 -4
  383. package/dist/panes/pane_registry.js +6 -2
  384. package/dist/panes/types.d.ts +3 -0
  385. package/dist/panes/ztc_launch.js +19 -0
  386. package/dist/plugin/optimization.d.ts +2 -0
  387. package/dist/plugin/optimization.js +1 -0
  388. package/dist/plugin/runtime.d.ts +2 -0
  389. package/dist/plugin/simulation.d.ts +6 -1
  390. package/dist/plugin/simulation_contract.d.ts +836 -1
  391. package/dist/plugin/simulation_documents.d.ts +22 -0
  392. package/dist/plugin/simulation_documents.js +1 -0
  393. package/dist/plugin/simulation_interventions.d.ts +103 -0
  394. package/dist/plugin/simulation_interventions.js +1 -0
  395. package/dist/plugin/simulation_living.d.ts +1 -0
  396. package/dist/plugin/simulation_living.js +3 -0
  397. package/dist/plugin/simulation_meetings.d.ts +121 -0
  398. package/dist/plugin/simulation_meetings.js +1 -0
  399. package/dist/plugin/simulation_story_review.d.ts +111 -0
  400. package/dist/plugin/simulation_story_review.js +1 -0
  401. package/dist/plugin/simulation_storyteller.d.ts +91 -0
  402. package/dist/plugin/simulation_storyteller.js +1 -0
  403. package/dist/plugin/simulation_structured.d.ts +2 -0
  404. package/dist/plugin/simulation_structured.js +2 -0
  405. package/dist/plugin/simulation_toolkit.d.ts +21 -0
  406. package/dist/plugin/simulation_toolkit.js +24 -0
  407. package/dist/prompts/tool_delegate_task.j2 +1 -1
  408. package/dist/remote-broker/Dockerfile +10 -0
  409. package/dist/remote-broker/archive.py +1227 -0
  410. package/dist/remote-broker/cutover.py +761 -0
  411. package/dist/remote-broker/requirements.txt +5 -0
  412. package/dist/remote-broker/resources.json +6 -0
  413. package/dist/remote-broker/resources.write-staging.example.json +18 -0
  414. package/dist/remote-broker/retained.py +686 -0
  415. package/dist/remote-broker/retained_cleanup.py +550 -0
  416. package/dist/remote-broker/server.py +648 -0
  417. package/dist/remote-broker/worker.py +1007 -0
  418. package/dist/router_auth.d.ts +31 -0
  419. package/dist/router_auth.js +155 -9
  420. package/dist/runbooks/catalog.d.ts +3 -0
  421. package/dist/runbooks/catalog.js +26 -0
  422. package/dist/runbooks/library.d.ts +11 -0
  423. package/dist/runbooks/library.js +95 -0
  424. package/dist/runbooks/package.d.ts +43 -0
  425. package/dist/runbooks/package.js +102 -0
  426. package/dist/session.d.ts +65 -13
  427. package/dist/session.js +548 -43
  428. package/dist/session_handoff.d.ts +25 -0
  429. package/dist/session_handoff.js +322 -0
  430. package/dist/session_handoff_contract.d.ts +89 -0
  431. package/dist/session_handoff_contract.js +179 -0
  432. package/dist/session_media.d.ts +41 -0
  433. package/dist/session_media.js +357 -0
  434. package/dist/session_ownership.d.ts +16 -0
  435. package/dist/session_ownership.js +221 -0
  436. package/dist/session_public.d.ts +10 -2
  437. package/dist/session_public.js +6 -1
  438. package/dist/simulation/dynamic_history.d.ts +42 -0
  439. package/dist/simulation/dynamic_history.js +173 -0
  440. package/dist/simulation/engines/swarm/pane_manager.js +7 -6
  441. package/dist/simulation/inference.d.ts +3 -1
  442. package/dist/simulation/inference.js +19 -1
  443. package/dist/simulation/intervention_generation.d.ts +27 -0
  444. package/dist/simulation/intervention_generation.js +246 -0
  445. package/dist/simulation/intervention_material.d.ts +4 -0
  446. package/dist/simulation/intervention_material.js +81 -0
  447. package/dist/simulation/living/context.d.ts +3130 -0
  448. package/dist/simulation/living/context.js +944 -0
  449. package/dist/simulation/living/definer.d.ts +12 -0
  450. package/dist/simulation/living/definer.js +223 -0
  451. package/dist/simulation/living/definition.d.ts +257 -0
  452. package/dist/simulation/living/definition.js +341 -0
  453. package/dist/simulation/living/frame.d.ts +259 -0
  454. package/dist/simulation/living/frame.js +223 -0
  455. package/dist/simulation/living/identifiers.d.ts +2 -0
  456. package/dist/simulation/living/identifiers.js +12 -0
  457. package/dist/simulation/living/index.d.ts +15 -0
  458. package/dist/simulation/living/index.js +15 -0
  459. package/dist/simulation/living/inference.d.ts +219 -0
  460. package/dist/simulation/living/inference.js +576 -0
  461. package/dist/simulation/living/mechanics.d.ts +54 -0
  462. package/dist/simulation/living/mechanics.js +588 -0
  463. package/dist/simulation/living/model-input.d.ts +25 -0
  464. package/dist/simulation/living/model-input.js +215 -0
  465. package/dist/simulation/living/open-world.d.ts +257 -0
  466. package/dist/simulation/living/open-world.js +102 -0
  467. package/dist/simulation/living/projection.d.ts +7 -0
  468. package/dist/simulation/living/projection.js +31 -0
  469. package/dist/simulation/living/recall.d.ts +17 -0
  470. package/dist/simulation/living/recall.js +25 -0
  471. package/dist/simulation/living/reduce.d.ts +15 -0
  472. package/dist/simulation/living/reduce.js +1853 -0
  473. package/dist/simulation/living/replay.d.ts +6 -0
  474. package/dist/simulation/living/replay.js +22 -0
  475. package/dist/simulation/living/runtime.d.ts +140 -0
  476. package/dist/simulation/living/runtime.js +3020 -0
  477. package/dist/simulation/living/shared-kinds.d.ts +24 -0
  478. package/dist/simulation/living/shared-kinds.js +96 -0
  479. package/dist/simulation/living/types.d.ts +2785 -0
  480. package/dist/simulation/living/types.js +669 -0
  481. package/dist/simulation/llm.d.ts +3 -1
  482. package/dist/simulation/llm.js +90 -30
  483. package/dist/simulation/memory/embedding.d.ts +1 -1
  484. package/dist/simulation/memory/embedding.js +9 -3
  485. package/dist/simulation/memory/filesystem.d.ts +2 -0
  486. package/dist/simulation/memory/filesystem.js +5 -1
  487. package/dist/simulation/memory/filesystem_file_tree.d.ts +4 -1
  488. package/dist/simulation/memory/filesystem_file_tree.js +41 -10
  489. package/dist/simulation/memory/filesystem_invariants.js +1 -2
  490. package/dist/simulation/memory/filesystem_types.d.ts +1 -0
  491. package/dist/simulation/memory/memory.d.ts +2 -0
  492. package/dist/simulation/memory/memory.js +5 -1
  493. package/dist/simulation/orchestration/intent.js +0 -2
  494. package/dist/simulation/orchestration/lifecycle.js +0 -2
  495. package/dist/simulation/plugin_host.d.ts +25 -1
  496. package/dist/simulation/plugin_host.js +334 -17
  497. package/dist/simulation/session_documents.d.ts +20 -0
  498. package/dist/simulation/session_documents.js +62 -0
  499. package/dist/simulation/session_input_validation.d.ts +43 -0
  500. package/dist/simulation/session_input_validation.js +364 -0
  501. package/dist/simulation/session_inputs.d.ts +32 -0
  502. package/dist/simulation/session_inputs.js +154 -0
  503. package/dist/simulation/telemetry.d.ts +11 -14
  504. package/dist/simulation/telemetry.js +177 -54
  505. package/dist/simulation/toolkit/bounded_turns.d.ts +13 -0
  506. package/dist/simulation/toolkit/bounded_turns.js +80 -0
  507. package/dist/simulation/toolkit/dynamic_agents.d.ts +25 -0
  508. package/dist/simulation/toolkit/dynamic_agents.js +218 -0
  509. package/dist/simulation/toolkit/dynamic_digest.d.ts +1 -0
  510. package/dist/simulation/toolkit/dynamic_digest.js +8 -0
  511. package/dist/simulation/toolkit/dynamic_documents.d.ts +7 -0
  512. package/dist/simulation/toolkit/dynamic_documents.js +71 -0
  513. package/dist/simulation/toolkit/dynamic_driver.d.ts +8 -0
  514. package/dist/simulation/toolkit/dynamic_driver.js +269 -0
  515. package/dist/simulation/toolkit/dynamic_game.d.ts +53 -0
  516. package/dist/simulation/toolkit/dynamic_game.js +805 -0
  517. package/dist/simulation/toolkit/dynamic_knowledge.d.ts +15 -0
  518. package/dist/simulation/toolkit/dynamic_knowledge.js +91 -0
  519. package/dist/simulation/toolkit/dynamic_mechanics.d.ts +22 -0
  520. package/dist/simulation/toolkit/dynamic_mechanics.js +910 -0
  521. package/dist/simulation/toolkit/dynamic_meetings.d.ts +239 -0
  522. package/dist/simulation/toolkit/dynamic_meetings.js +350 -0
  523. package/dist/simulation/toolkit/dynamic_progress.d.ts +131 -0
  524. package/dist/simulation/toolkit/dynamic_progress.js +214 -0
  525. package/dist/simulation/toolkit/dynamic_projection.d.ts +9 -0
  526. package/dist/simulation/toolkit/dynamic_projection.js +219 -0
  527. package/dist/simulation/toolkit/dynamic_runtime.d.ts +412 -0
  528. package/dist/simulation/toolkit/dynamic_runtime.js +6536 -0
  529. package/dist/simulation/toolkit/dynamic_state.d.ts +111 -0
  530. package/dist/simulation/toolkit/dynamic_state.js +1967 -0
  531. package/dist/simulation/toolkit/dynamic_story_review.d.ts +508 -0
  532. package/dist/simulation/toolkit/dynamic_story_review.js +333 -0
  533. package/dist/simulation/toolkit/dynamic_storyteller.d.ts +77 -0
  534. package/dist/simulation/toolkit/dynamic_storyteller.js +114 -0
  535. package/dist/simulation/toolkit/dynamic_storyteller_runtime.d.ts +26 -0
  536. package/dist/simulation/toolkit/dynamic_storyteller_runtime.js +126 -0
  537. package/dist/simulation/toolkit/dynamic_world.d.ts +22 -0
  538. package/dist/simulation/toolkit/dynamic_world.js +377 -0
  539. package/dist/simulation/toolkit/structured_output.d.ts +5 -0
  540. package/dist/simulation/toolkit/structured_output.js +321 -0
  541. package/dist/simulation/types/world.d.ts +2 -0
  542. package/dist/simulation/world/artifact_store.js +1 -1
  543. package/dist/simulation/world/memory_manager.d.ts +5 -0
  544. package/dist/simulation/world/memory_manager.js +17 -2
  545. package/dist/simulation/world/state.d.ts +3 -2
  546. package/dist/simulation/world/state.js +15 -5
  547. package/dist/skills/bundled/measurement-validation/SKILL.md +144 -0
  548. package/dist/terminal_attach.d.ts +1 -0
  549. package/dist/terminal_attach.js +113 -0
  550. package/dist/tool_progress.d.ts +3 -0
  551. package/dist/tool_progress.js +27 -0
  552. package/dist/types.d.ts +145 -10
  553. package/dist/types.js +3 -0
  554. package/dist/ui/core/input.d.ts +3 -0
  555. package/dist/ui/core/input_segments.d.ts +18 -1
  556. package/dist/ui/core/input_segments.js +131 -47
  557. package/dist/ui/core/input_state.d.ts +12 -0
  558. package/dist/ui/core/layout_yoga.d.ts +1 -1
  559. package/dist/ui/core/turn_metadata.d.ts +5 -0
  560. package/dist/ui/core/turn_metadata.js +22 -0
  561. package/dist/ui/ink/render.d.ts +2 -1
  562. package/dist/ui/ink/render.js +6 -5
  563. package/dist/ui/ratatui/headless_pane_manager.d.ts +14 -1
  564. package/dist/ui/ratatui/headless_pane_manager.js +293 -104
  565. package/dist/ui/ratatui/index.d.ts +1 -0
  566. package/dist/ui/ratatui/input.d.ts +4 -0
  567. package/dist/ui/ratatui/input.js +15 -0
  568. package/dist/ui/ratatui/ipc_path.d.ts +2 -0
  569. package/dist/ui/ratatui/ipc_path.js +29 -1
  570. package/dist/ui/ratatui/mux_persistence.d.ts +3 -1
  571. package/dist/ui/ratatui/mux_persistence.js +139 -1
  572. package/dist/ui/ratatui/pane_relay.d.ts +1 -1
  573. package/dist/ui/ratatui/pane_relay.js +55 -27
  574. package/dist/ui/ratatui/process.d.ts +17 -1
  575. package/dist/ui/ratatui/process.js +80 -7
  576. package/dist/ui/ratatui/protocol.d.ts +236 -1
  577. package/dist/ui/ratatui/protocol.js +90 -0
  578. package/dist/ui/scrollback.d.ts +2 -1
  579. package/dist/ui/scrollback.js +9 -4
  580. package/dist/ui/stream_typewriter.d.ts +8 -3
  581. package/dist/ui/stream_typewriter.js +30 -1
  582. package/dist/ui/streaming_scrollback.d.ts +1 -0
  583. package/dist/ui/streaming_scrollback.js +1 -1
  584. package/dist/ui/transcript_render_cache.js +10 -0
  585. package/dist/ui/views/activity_line.d.ts +5 -3
  586. package/dist/ui/views/activity_line.js +65 -7
  587. package/dist/ui/views/app.d.ts +6 -3
  588. package/dist/ui/views/app.js +17 -6
  589. package/dist/ui/views/completion_menu.js +10 -5
  590. package/dist/ui/views/input_area.d.ts +7 -3
  591. package/dist/ui/views/input_area.js +15 -9
  592. package/dist/ui/views/message_list.d.ts +4 -1
  593. package/dist/ui/views/message_list.js +89 -19
  594. package/dist/ui/views/queue_panel.d.ts +3 -1
  595. package/dist/ui/views/queue_panel.js +9 -2
  596. package/dist/ui/views/status_bar.d.ts +4 -2
  597. package/dist/ui/views/status_bar.js +28 -13
  598. package/dist/ui/views/theme.d.ts +2 -0
  599. package/dist/ui/views/theme.js +2 -0
  600. package/dist/ui/widgets/color_panel.js +18 -0
  601. package/dist/ui/widgets/form.js +8 -0
  602. package/dist/ui/widgets/log_view.js +7 -0
  603. package/dist/ui/widgets/navigator_panel.js +8 -0
  604. package/dist/ui/widgets/prompt_viewer.js +2 -0
  605. package/dist/ui/widgets/questionnaire.d.ts +2 -0
  606. package/dist/ui/widgets/questionnaire.js +79 -16
  607. package/dist/ui/widgets/resume_panel.d.ts +2 -0
  608. package/dist/ui/widgets/resume_panel.js +26 -15
  609. package/dist/ui/widgets/rewind_panel.d.ts +2 -2
  610. package/dist/ui/widgets/rewind_panel.js +4 -2
  611. package/dist/ui/widgets/select.js +16 -27
  612. package/dist/ui/widgets/settings_panel.js +16 -0
  613. package/dist/ui/widgets/status_line_panel.d.ts +1 -0
  614. package/dist/ui/widgets/status_line_panel.js +30 -4
  615. package/dist/ui/widgets/text_input.d.ts +2 -0
  616. package/dist/ui/widgets/text_input.js +15 -1
  617. package/dist/ui/widgets/types.d.ts +2 -0
  618. package/dist/usage_projection.d.ts +24 -0
  619. package/dist/usage_projection.js +130 -0
  620. package/dist/usage_snapshot.d.ts +36 -0
  621. package/dist/usage_snapshot.js +131 -0
  622. package/dist/utils/assistant_message.d.ts +2 -0
  623. package/dist/utils/assistant_message.js +5 -0
  624. package/dist/utils/atomic_write.d.ts +6 -2
  625. package/dist/utils/atomic_write.js +29 -4
  626. package/dist/utils/checked_shell.d.ts +25 -0
  627. package/dist/utils/checked_shell.js +107 -0
  628. package/dist/utils/compaction.d.ts +4 -1
  629. package/dist/utils/compaction.js +31 -7
  630. package/dist/utils/context.d.ts +4 -4
  631. package/dist/utils/context.js +14 -12
  632. package/dist/utils/deepseek.d.ts +2 -2
  633. package/dist/utils/deepseek.js +13 -5
  634. package/dist/utils/ephemeral.js +4 -0
  635. package/dist/utils/ephemeral_tools.d.ts +18 -0
  636. package/dist/utils/ephemeral_tools.js +97 -0
  637. package/dist/utils/jev_client.d.ts +4 -0
  638. package/dist/utils/jev_client.js +15 -0
  639. package/dist/utils/model_cache.d.ts +15 -0
  640. package/dist/utils/model_cache.js +143 -0
  641. package/dist/utils/models.d.ts +4 -2
  642. package/dist/utils/models.js +12 -16
  643. package/dist/utils/reasoning.d.ts +8 -1
  644. package/dist/utils/reasoning.js +31 -11
  645. package/dist/utils/router_catalog.d.ts +49 -0
  646. package/dist/utils/router_catalog.js +271 -0
  647. package/dist/utils/sandbox.d.ts +9 -0
  648. package/dist/utils/sandbox.js +118 -15
  649. package/dist/utils/shell.d.ts +7 -0
  650. package/dist/utils/shell.js +98 -34
  651. package/dist/utils/subprocess_env.d.ts +3 -0
  652. package/dist/utils/subprocess_env.js +27 -1
  653. package/dist/web/accounts_mirror.d.ts +3 -1
  654. package/dist/web/accounts_mirror.js +13 -9
  655. package/dist/web/child_publication.d.ts +17 -0
  656. package/dist/web/child_publication.js +45 -0
  657. package/dist/web/mirror_authenticator.d.ts +31 -11
  658. package/dist/web/mirror_authenticator.js +67 -17
  659. package/dist/web/mirror_client.d.ts +31 -4
  660. package/dist/web/mirror_client.js +189 -23
  661. package/dist/web/mirror_stream.d.ts +84 -22
  662. package/dist/web/mirror_stream.js +676 -95
  663. package/dist/web/observer_query_redaction.d.ts +6 -0
  664. package/dist/web/observer_query_redaction.js +58 -0
  665. package/dist/web/pane_registry.d.ts +2 -0
  666. package/dist/web/pane_registry.js +86 -22
  667. package/dist/web/tool_image.d.ts +6 -0
  668. package/dist/web/tool_image.js +17 -0
  669. package/dist/web/view_plugin.d.ts +14 -0
  670. package/dist/web/view_plugin.js +23 -1
  671. package/dist/worker/executor.js +31 -12
  672. package/dist/worker/index.d.ts +1 -0
  673. package/dist/worker/toolsets.js +3 -1
  674. package/dist/worker/types.d.ts +12 -1
  675. package/dist/workflows/registry.js +1 -0
  676. package/dist/workflows/registry_handle.d.ts +2 -0
  677. package/dist/workflows/runtime.d.ts +2 -0
  678. package/dist/workflows/runtime.js +1 -0
  679. package/dist/workspace_agent.d.ts +7 -0
  680. package/dist/workspace_agent.js +36 -0
  681. package/dist/workspace_collision.d.ts +76 -0
  682. package/dist/workspace_collision.js +688 -0
  683. package/dist/workspace_layout.d.ts +18 -0
  684. package/dist/workspace_layout.js +121 -0
  685. package/dist/workspace_runtime.d.ts +44 -0
  686. package/dist/workspace_runtime.js +82 -0
  687. package/dist/workspace_session_context.d.ts +62 -0
  688. package/dist/workspace_session_context.js +160 -0
  689. package/dist/zlm-embed.mjs +32518 -9615
  690. package/dist/zlm.js +1 -0
  691. package/node_modules/@zerg/model-contracts/LICENSE.md +375 -0
  692. package/node_modules/@zerg/model-contracts/README.md +90 -0
  693. package/node_modules/@zerg/model-contracts/index.d.ts +20 -0
  694. package/node_modules/@zerg/model-contracts/index.js +223 -0
  695. package/node_modules/@zerg/model-contracts/package.json +8 -0
  696. package/node_modules/glob/node_modules/brace-expansion/index.js +78 -22
  697. package/node_modules/glob/node_modules/brace-expansion/package.json +1 -1
  698. package/node_modules/readdir-glob/node_modules/brace-expansion/index.js +78 -22
  699. package/node_modules/readdir-glob/node_modules/brace-expansion/package.json +1 -1
  700. package/package.json +45 -24
  701. package/packages/model-contracts/LICENSE.md +375 -0
  702. package/packages/model-contracts/README.md +90 -0
  703. package/packages/model-contracts/index.d.ts +20 -0
  704. package/packages/model-contracts/index.js +223 -0
  705. package/packages/model-contracts/package.json +8 -0
  706. package/remote-broker/Dockerfile +10 -0
  707. package/remote-broker/README.md +308 -0
  708. package/remote-broker/archive.py +1227 -0
  709. package/remote-broker/cutover.py +761 -0
  710. package/remote-broker/requirements.txt +5 -0
  711. package/remote-broker/resources.example.json +6 -0
  712. package/remote-broker/resources.write-staging.example.json +18 -0
  713. package/remote-broker/retained.py +686 -0
  714. package/remote-broker/retained_cleanup.py +550 -0
  715. package/remote-broker/server.py +648 -0
  716. package/scripts/build-remote-broker.mjs +13 -0
  717. package/scripts/ensure-local-packages.mjs +6 -0
  718. package/scripts/node-pty-helpers.mjs +103 -0
@@ -10,6 +10,7 @@ export type { RatatuiRendererOptions } from './adapter.js';
10
10
  export { TuiProcess, NullTuiProcess, getTuiProcess, getNullTuiProcess, isTTY, isZmuxAvailable, isZtermAvailable, launchZtermDesktop, isRatatuiBinaryAvailable } from './process.js';
11
11
  export type { TuiEventHandler } from './process.js';
12
12
  export type { RustCommand, RustEvent } from './protocol.js';
13
+ export type { DesktopTaskControlState, DesktopTaskControlEntry, DesktopTaskControlAttachment, DesktopTaskAction, DesktopTaskActionResult } from './protocol.js';
13
14
  export { PaneRelayServer, PaneRelayClient, generateRelaySocketPath } from './pane_relay.js';
14
15
  export type { PaneCommandTransport } from './pane_relay.js';
15
16
  export { HeadlessPaneManager, encodeZtcPaneInput, decodeZtcPaneInput } from './headless_pane_manager.js';
@@ -0,0 +1,4 @@
1
+ import { type InputKey } from '../core/input.js';
2
+ export type ClipboardPastePreference = 'text' | 'image' | 'image-only';
3
+ /** Identify a clipboard gesture while keeping terminal paste payloads literal. */
4
+ export declare function clipboardPastePreference(input: string, key: InputKey, paste?: boolean): ClipboardPastePreference | null;
@@ -0,0 +1,15 @@
1
+ import { isControlKey } from '../core/input.js';
2
+ /** Identify a clipboard gesture while keeping terminal paste payloads literal. */
3
+ export function clipboardPastePreference(input, key, paste = false) {
4
+ if (paste)
5
+ return null;
6
+ const command = key.super === true || (key.meta === true && key.alt !== true);
7
+ const isV = input.toLowerCase() === 'v';
8
+ if (isV && (command || (key.ctrl && key.shift)))
9
+ return 'text';
10
+ if (isV && key.ctrl)
11
+ return 'image';
12
+ if (isControlKey(input, key, 'i'))
13
+ return 'image-only';
14
+ return null;
15
+ }
@@ -14,6 +14,8 @@
14
14
  * than only whichever one the host happens to run.
15
15
  */
16
16
  export declare function generateIpcPath(prefix: string, platformName?: string): string;
17
+ /** Retire only directories allocated by this host, without recursive removal. */
18
+ export declare function removeOwnedIpcPath(endpoint: string): void;
17
19
  /**
18
20
  * True when the path names a Windows pipe rather than a filesystem entry.
19
21
  *
@@ -7,8 +7,10 @@
7
7
  * `\\.\pipe\<name>` form: libuv maps a bare path into the pipe namespace itself,
8
8
  * so a filesystem-style path can never reach an AF_UNIX socket there.
9
9
  */
10
+ import { chmodSync, mkdtempSync, rmdirSync } from 'fs';
10
11
  import { tmpdir } from 'os';
11
12
  import { join } from 'path';
13
+ const ownedEndpoints = new Map();
12
14
  /**
13
15
  * Build a unique IPC endpoint name for the current process.
14
16
  *
@@ -20,7 +22,33 @@ export function generateIpcPath(prefix, platformName = process.platform) {
20
22
  if (platformName === 'win32') {
21
23
  return `\\\\.\\pipe\\${prefix}-${unique}`;
22
24
  }
23
- return join(tmpdir(), `${prefix}-${unique}.sock`);
25
+ const requested = join(tmpdir(), `${prefix}-${unique}.sock`);
26
+ // Darwin reserves one of its 104 address bytes for NUL. A long TMPDIR
27
+ // must not truncate distinct endpoints onto the same kernel address.
28
+ if (Buffer.byteLength(requested, 'utf8') <= 103)
29
+ return requested;
30
+ const channel = prefix.replace(/[^a-zA-Z0-9_-]/g, '').slice(0, 16) || 'ztc-ipc';
31
+ const directory = mkdtempSync(join('/tmp', `${channel}-`));
32
+ chmodSync(directory, 0o700);
33
+ const endpoint = join(directory, 'socket');
34
+ ownedEndpoints.set(endpoint, directory);
35
+ return endpoint;
36
+ }
37
+ /** Retire only directories allocated by this host, without recursive removal. */
38
+ export function removeOwnedIpcPath(endpoint) {
39
+ const directory = ownedEndpoints.get(endpoint);
40
+ if (!directory)
41
+ return;
42
+ // The listener retires its endpoint first. Never delete anything a failed
43
+ // bind might have found in the allocated directory.
44
+ try {
45
+ rmdirSync(directory);
46
+ }
47
+ catch (error) {
48
+ if (error.code !== 'ENOENT')
49
+ throw error;
50
+ }
51
+ ownedEndpoints.delete(endpoint);
24
52
  }
25
53
  /**
26
54
  * True when the path names a Windows pipe rather than a filesystem entry.
@@ -4,5 +4,7 @@ export interface MuxPersistenceOptions {
4
4
  }
5
5
  export declare function resolveMuxPersistenceOptions(env?: NodeJS.ProcessEnv): MuxPersistenceOptions;
6
6
  export declare function shouldPersistMuxPaneType(paneType: string, options: MuxPersistenceOptions): boolean;
7
- export declare function isMuxPaneRestorable(pane: Pick<MuxPaneState, 'id' | 'pane_type'>, options: MuxPersistenceOptions): boolean;
7
+ export declare function isMuxPaneRestorable(pane: Pick<MuxPaneState, 'id' | 'pane_type' | 'agent_session'>, options: MuxPersistenceOptions): boolean;
8
8
  export declare function sanitizeMuxSessionState(state: MuxSessionState, options: MuxPersistenceOptions): MuxSessionState;
9
+ /** Decode/admit a bounded checkpoint before traversing it or changing live panes. */
10
+ export declare function validateWorkspaceState(value: unknown): asserts value is MuxSessionState;
@@ -16,6 +16,9 @@ export function isMuxPaneRestorable(pane, options) {
16
16
  if (pane.id === 0) {
17
17
  return false;
18
18
  }
19
+ // A canonical session link is descriptive; restoration never launches its saved argv.
20
+ if (pane.pane_type === 'ztc' && pane.agent_session)
21
+ return true;
19
22
  return shouldPersistMuxPaneType(pane.pane_type, options);
20
23
  }
21
24
  function pruneMuxLayoutNode(node, allowedPaneIds) {
@@ -30,13 +33,14 @@ function pruneMuxLayoutNode(node, allowedPaneIds) {
30
33
  return first || second;
31
34
  }
32
35
  export function sanitizeMuxSessionState(state, options) {
36
+ validateWorkspaceState(state);
33
37
  const panes = state.panes.filter((pane) => isMuxPaneRestorable(pane, options));
34
38
  const allowedPaneIds = new Set([0, ...panes.map((pane) => pane.id)]);
35
39
  const layout = pruneMuxLayoutNode(state.layout, allowedPaneIds) || { type: 'leaf', pane_id: 0 };
36
40
  const layoutPaneIds = new Set(collectMuxLayoutPaneIds(layout));
37
41
  const focused_pane_id = layoutPaneIds.has(state.focused_pane_id)
38
42
  ? state.focused_pane_id
39
- : 0;
43
+ : collectMuxLayoutPaneIds(layout)[0];
40
44
  const zoomed_pane_id = state.zoomed_pane_id !== undefined
41
45
  && layoutPaneIds.has(state.zoomed_pane_id)
42
46
  ? state.zoomed_pane_id
@@ -47,8 +51,142 @@ export function sanitizeMuxSessionState(state, options) {
47
51
  zoomed_pane_id,
48
52
  layout,
49
53
  panes,
54
+ ...(state.windows ? { windows: state.windows.map(window => {
55
+ const windowLayout = pruneMuxLayoutNode(window.layout, allowedPaneIds) || { type: 'leaf', pane_id: 0 };
56
+ const ids = new Set(collectMuxLayoutPaneIds(windowLayout));
57
+ return { ...window, layout: windowLayout,
58
+ focused_pane_id: ids.has(window.focused_pane_id) ? window.focused_pane_id : collectMuxLayoutPaneIds(windowLayout)[0],
59
+ zoomed_pane_id: window.zoomed_pane_id !== undefined && ids.has(window.zoomed_pane_id) ? window.zoomed_pane_id : undefined };
60
+ }) } : {}),
50
61
  };
51
62
  }
63
+ /** Decode/admit a bounded checkpoint before traversing it or changing live panes. */
64
+ export function validateWorkspaceState(value) {
65
+ const object = (v) => {
66
+ if (!v || typeof v !== 'object' || Array.isArray(v))
67
+ throw new Error('Workspace requires an object');
68
+ return v;
69
+ };
70
+ const id = (v) => {
71
+ if (typeof v !== 'number' || !Number.isInteger(v) || v < 0 || v > 0xffffffff)
72
+ throw new Error('Workspace identity must be an unsigned integer');
73
+ return v;
74
+ };
75
+ const text = (v, max) => {
76
+ if (typeof v !== 'string' || Buffer.byteLength(v) > max)
77
+ throw new Error('Workspace metadata exceeds its bounds');
78
+ };
79
+ const saved = object(value);
80
+ if (saved.schema_version !== undefined && saved.schema_version !== 1)
81
+ throw new Error(`Unsupported workspace schema version ${String(saved.schema_version)}`);
82
+ if (!Array.isArray(saved.panes) || saved.panes.length > 256)
83
+ throw new Error('Workspace requires at most 256 panes');
84
+ const paneIds = new Set();
85
+ for (const entry of saved.panes) {
86
+ const pane = object(entry);
87
+ const paneId = id(pane.id);
88
+ if (paneIds.has(paneId))
89
+ throw new Error(`Duplicate workspace pane ID ${paneId}`);
90
+ paneIds.add(paneId);
91
+ text(pane.title, 4096);
92
+ text(pane.pane_type, 64);
93
+ for (const key of ['command', 'cwd'])
94
+ if (pane[key] !== undefined && pane[key] !== null)
95
+ text(pane[key], 65536);
96
+ if (pane.content !== undefined && pane.content !== null)
97
+ text(pane.content, 4 * 1024 * 1024);
98
+ if (pane.args !== undefined) {
99
+ if (!Array.isArray(pane.args) || pane.args.length > 256)
100
+ throw new Error('Workspace arguments exceed their bounds');
101
+ pane.args.forEach(arg => text(arg, 65536));
102
+ }
103
+ if (pane.agent_session !== undefined && pane.agent_session !== null) {
104
+ const ref = object(pane.agent_session);
105
+ text(ref.session_id, 256);
106
+ text(ref.project_path, 65536);
107
+ if (!ref.session_id || !ref.project_path)
108
+ throw new Error('Workspace agent session requires a bounded session ID and project path');
109
+ }
110
+ if (pane.restoration_status !== undefined && pane.restoration_status !== null
111
+ && (typeof pane.restoration_status !== 'string' || !['not_started', 'missing_command', 'missing_directory', 'session_missing', 'session_active_elsewhere', 'session_unreadable'].includes(pane.restoration_status)))
112
+ throw new Error('Unknown workspace restoration status');
113
+ }
114
+ paneIds.add(0);
115
+ const layout = (v, depth = 0) => {
116
+ if (depth > 64)
117
+ throw new Error('Workspace layout exceeds depth 64');
118
+ const node = object(v);
119
+ if (node.type === 'leaf') {
120
+ const paneId = id(node.pane_id);
121
+ if (!paneIds.has(paneId))
122
+ throw new Error(`Workspace layout names missing pane ${paneId}`);
123
+ return new Set([paneId]);
124
+ }
125
+ if (node.type !== 'split' || typeof node.direction !== 'string' || !['horizontal', 'vertical'].includes(node.direction))
126
+ throw new Error('Workspace requires a valid layout node');
127
+ if (typeof node.ratio !== 'number' || !Number.isFinite(node.ratio) || node.ratio <= 0 || node.ratio >= 1)
128
+ throw new Error('Workspace split ratio must be between 0 and 1');
129
+ const ids = layout(node.first, depth + 1);
130
+ for (const second of layout(node.second, depth + 1)) {
131
+ if (ids.has(second))
132
+ throw new Error(`Duplicate workspace layout pane ID ${second}`);
133
+ ids.add(second);
134
+ }
135
+ return ids;
136
+ };
137
+ layout(saved.layout);
138
+ if (!paneIds.has(id(saved.focused_pane_id)) || (saved.zoomed_pane_id !== undefined && saved.zoomed_pane_id !== null && !paneIds.has(id(saved.zoomed_pane_id))))
139
+ throw new Error('Workspace focus names a missing pane');
140
+ const windows = saved.windows ?? [];
141
+ if (!Array.isArray(windows) || windows.length > 64)
142
+ throw new Error('Workspace requires at most 64 windows');
143
+ const windowIds = new Set();
144
+ const paneWindows = new Map();
145
+ for (const entry of windows) {
146
+ const window = object(entry);
147
+ const windowId = id(window.id);
148
+ if (windowIds.has(windowId))
149
+ throw new Error(`Duplicate workspace window ID ${windowId}`);
150
+ windowIds.add(windowId);
151
+ text(window.title, 4096);
152
+ for (const key of ['color', 'pattern'])
153
+ if (window[key] !== undefined && window[key] !== null)
154
+ text(window[key], 64);
155
+ const ids = layout(window.layout);
156
+ for (const paneId of ids) {
157
+ if (paneId === 0)
158
+ continue;
159
+ if (paneWindows.has(paneId))
160
+ throw new Error(`Workspace pane ${paneId} appears in multiple windows`);
161
+ paneWindows.set(paneId, windowId);
162
+ }
163
+ if (!ids.has(id(window.focused_pane_id)) || (window.zoomed_pane_id !== undefined && window.zoomed_pane_id !== null && !ids.has(id(window.zoomed_pane_id))))
164
+ throw new Error('Workspace window focus names a missing pane');
165
+ }
166
+ if (windows.length) {
167
+ for (const entry of saved.panes) {
168
+ const pane = object(entry);
169
+ const paneId = id(pane.id);
170
+ if (paneId !== 0 && pane.window_id !== undefined && pane.window_id !== null
171
+ && paneWindows.has(paneId) && paneWindows.get(paneId) !== id(pane.window_id))
172
+ throw new Error(`Workspace pane ${paneId} window assignment contradicts its layout`);
173
+ }
174
+ }
175
+ if (windows.length && ((saved.active_window_id !== undefined && saved.active_window_id !== null && !windowIds.has(id(saved.active_window_id)))
176
+ || saved.panes.some(entry => { const pane = object(entry); return pane.window_id !== undefined && pane.window_id !== null && !windowIds.has(id(pane.window_id)); })))
177
+ throw new Error('Workspace names a missing window');
178
+ if (saved.geometry !== undefined && saved.geometry !== null) {
179
+ const geometry = object(saved.geometry);
180
+ for (const key of ['cols', 'rows', 'pixel_width', 'pixel_height']) {
181
+ const v = geometry[key];
182
+ if (v === undefined || v === null)
183
+ continue;
184
+ const cells = key === 'cols' || key === 'rows';
185
+ if (typeof v !== 'number' || !Number.isFinite(v) || v <= 0 || v > (cells ? 10000 : 32768) || (cells && !Number.isInteger(v)))
186
+ throw new Error('Workspace geometry must be positive and bounded');
187
+ }
188
+ }
189
+ }
52
190
  function collectMuxLayoutPaneIds(node) {
53
191
  if (node.type === 'leaf') {
54
192
  return [node.pane_id];
@@ -25,7 +25,7 @@ export declare class PaneRelayServer {
25
25
  private tuiUnsubscribe;
26
26
  constructor(transport: PaneCommandTransport, socketPath: string);
27
27
  /** Start listening for child connections */
28
- start(): void;
28
+ start(): Promise<void>;
29
29
  /** Broadcast a pane event to all connected children */
30
30
  private broadcast;
31
31
  /** Stop the relay server and clean up */
@@ -11,9 +11,9 @@
11
11
  */
12
12
  import { createServer, createConnection } from 'net';
13
13
  import { createInterface } from 'readline';
14
- import { unlinkSync } from 'fs';
15
- import { serializeCommand, parseEvent, CAPABILITY_PANE_DELIVERY_ACK } from './protocol.js';
16
- import { generateIpcPath, isNamedPipePath } from './ipc_path.js';
14
+ import { serializeCommand, parseEvent, CAPABILITY_PANE_DELIVERY_ACK, CAPABILITY_DESKTOP_TASK_CONTROLS, CAPABILITY_DESKTOP_RUNTIME_CONTROLS, CAPABILITY_DESKTOP_SESSION_SHARE } from './protocol.js';
15
+ import { runtimeDiag } from '../../utils/debug_log.js';
16
+ import { generateIpcPath, removeOwnedIpcPath } from './ipc_path.js';
17
17
  // ============================================================================
18
18
  // PaneRelayServer — runs in parent ZTC (--mux mode)
19
19
  // ============================================================================
@@ -27,6 +27,9 @@ const PANE_EVENT_TYPES = new Set([
27
27
  'pane_state',
28
28
  'pane_output',
29
29
  'error',
30
+ 'desktop_task_action',
31
+ 'desktop_runtime_action',
32
+ 'desktop_session_share_action',
30
33
  ]);
31
34
  export class PaneRelayServer {
32
35
  transport;
@@ -39,7 +42,9 @@ export class PaneRelayServer {
39
42
  this.socketPath = socketPath;
40
43
  }
41
44
  /** Start listening for child connections */
42
- start() {
45
+ async start() {
46
+ if (this.server !== null)
47
+ throw new Error('Pane relay is already started.');
43
48
  // Subscribe to pane events from the parent's TuiProcess
44
49
  this.tuiUnsubscribe = this.transport.on((event) => {
45
50
  if (PANE_EVENT_TYPES.has(event.type)) {
@@ -49,9 +54,15 @@ export class PaneRelayServer {
49
54
  this.server = createServer((client) => {
50
55
  this.clients.add(client);
51
56
  client.write(JSON.stringify({ type: 'ready', version: 'pane-relay', cols: 0, rows: 0,
52
- capabilities: this.transport.hasCapability?.(CAPABILITY_PANE_DELIVERY_ACK) ? [CAPABILITY_PANE_DELIVERY_ACK] : [],
57
+ capabilities: [CAPABILITY_PANE_DELIVERY_ACK, 'pane_labels_v1', CAPABILITY_DESKTOP_TASK_CONTROLS, CAPABILITY_DESKTOP_RUNTIME_CONTROLS, CAPABILITY_DESKTOP_SESSION_SHARE]
58
+ .filter(capability => this.transport.hasCapability?.(capability)),
53
59
  }) + '\n');
54
60
  const rl = createInterface({ input: client, crlfDelay: Infinity });
61
+ // Readline re-emits input errors; one failed peer must not terminate its parent.
62
+ rl.on('error', () => {
63
+ this.clients.delete(client);
64
+ client.destroy();
65
+ });
55
66
  rl.on('line', (line) => {
56
67
  const parsed = parseEvent(line);
57
68
  if (!parsed)
@@ -68,21 +79,29 @@ export class PaneRelayServer {
68
79
  rl.close();
69
80
  });
70
81
  });
71
- this.server.on('error', (err) => {
72
- // If socket file already exists from a crash, unlink and retry once.
73
- // Named pipes leave no file behind, so there is nothing to clear.
74
- if (err.code === 'EADDRINUSE') {
75
- if (!isNamedPipePath(this.socketPath)) {
76
- try {
77
- unlinkSync(this.socketPath);
78
- }
79
- catch { /* ignore */ }
80
- }
81
- this.server.listen(this.socketPath);
82
- return;
83
- }
84
- });
85
- this.server.listen(this.socketPath);
82
+ const server = this.server;
83
+ try {
84
+ await new Promise((resolve, reject) => {
85
+ const failed = (error) => reject(error);
86
+ server.once('error', failed);
87
+ server.once('listening', () => {
88
+ server.off('error', failed);
89
+ server.on('error', error => {
90
+ runtimeDiag('error', `Pane relay stopped: ${error.message}`);
91
+ this.stop();
92
+ });
93
+ resolve();
94
+ });
95
+ server.listen(this.socketPath);
96
+ });
97
+ }
98
+ catch (error) {
99
+ // An occupied address is not proof that its owner crashed. Never unlink
100
+ // another listener or spin in a repeated listen/error retry cycle.
101
+ this.stop();
102
+ const cause = error instanceof Error ? error : new Error(String(error));
103
+ throw new Error(`Pane relay could not listen: ${cause.message}`, { cause });
104
+ }
86
105
  }
87
106
  /** Broadcast a pane event to all connected children */
88
107
  broadcast(event) {
@@ -110,15 +129,18 @@ export class PaneRelayServer {
110
129
  }
111
130
  this.clients.clear();
112
131
  if (this.server) {
113
- this.server.close();
132
+ this.server.close(() => {
133
+ try {
134
+ removeOwnedIpcPath(this.socketPath);
135
+ }
136
+ catch (error) {
137
+ runtimeDiag('error', `Pane relay IPC cleanup failed: ${String(error)}`);
138
+ }
139
+ });
114
140
  this.server = null;
115
141
  }
116
- if (!isNamedPipePath(this.socketPath)) {
117
- try {
118
- unlinkSync(this.socketPath);
119
- }
120
- catch { /* ignore */ }
121
- }
142
+ // Node closes its own bound endpoint. A failed bind never owns a path
143
+ // and must not unlink a file belonging to an existing listener.
122
144
  }
123
145
  }
124
146
  // ============================================================================
@@ -194,6 +216,12 @@ export class PaneRelayClient {
194
216
  this.ready = false;
195
217
  this.cleanup();
196
218
  });
219
+ // readline forwards input errors independently of the socket listener.
220
+ // A stale write after the parent closes must retire this transport too.
221
+ this.readline.on('error', () => {
222
+ this.ready = false;
223
+ this.cleanup();
224
+ });
197
225
  this.socket.on('error', () => {
198
226
  this.ready = false;
199
227
  this.cleanup();
@@ -9,6 +9,7 @@
9
9
  * a fullscreen multiplexer with split panes (alternate screen mode).
10
10
  */
11
11
  import type { RustCommand, RustEvent } from './protocol.js';
12
+ import { type DesktopRuntime } from '../../desktop/runtime.js';
12
13
  export type TuiEventHandler = (event: RustEvent) => void;
13
14
  /**
14
15
  * Get the path to the zmux binary
@@ -32,7 +33,7 @@ export declare function isZmuxAvailable(): boolean;
32
33
  * Check if zterm is available. Unlike zmux, zterm is a desktop process and
33
34
  * does not require the current process to have a TTY.
34
35
  */
35
- export declare function isZtermAvailable(): boolean;
36
+ export declare function isZtermAvailable(admission?: DesktopRuntime | null): boolean;
36
37
  /**
37
38
  * Launch the native zterm desktop binary and resolve with its exit code.
38
39
  */
@@ -83,6 +84,11 @@ export declare function isTransientSocketConnectError(code: string | undefined):
83
84
  * Manages the Rust TUI process with Unix socket communication
84
85
  */
85
86
  export declare class TuiProcess {
87
+ private readonly options;
88
+ /** Host-selected unmanaged renderer; validated bundle admission takes precedence. */
89
+ constructor(options?: {
90
+ desktopBinaryPath?: string;
91
+ });
86
92
  private process;
87
93
  private socket;
88
94
  private readline;
@@ -98,6 +104,9 @@ export declare class TuiProcess {
98
104
  private _muxMode;
99
105
  /** Whether zterm is being used as the native desktop renderer */
100
106
  private _desktopMode;
107
+ private desktopCompatibility;
108
+ /** Retained across socket cleanup so an admitted renderer can request owner exit. */
109
+ private desktopStartupAdmitted;
101
110
  private stopping;
102
111
  /** Whether zmux was detected from the ready event version string */
103
112
  private _isZmux;
@@ -123,6 +132,7 @@ export declare class TuiProcess {
123
132
  */
124
133
  private clipboardRequests;
125
134
  private clipboardRequestSeq;
135
+ private clipboardTextRequests;
126
136
  /**
127
137
  * Subscribe to zmux's mirror-socket path. The callback runs exactly once:
128
138
  * synchronously if the path is already known, otherwise as soon as zmux
@@ -151,6 +161,9 @@ export declare class TuiProcess {
151
161
  */
152
162
  readClipboardImage(timeoutMs?: number): Promise<Buffer | null>;
153
163
  private settleClipboardRequest;
164
+ /** Read exact text through the renderer; null means unavailable, '' means empty. */
165
+ readClipboardText(timeoutMs?: number): Promise<string | null>;
166
+ private settleClipboardTextRequest;
154
167
  /**
155
168
  * Mirror socket path this zmux is exposing, or null if unavailable
156
169
  * (non-zmux mode, bind failed, or announcement not received yet).
@@ -167,6 +180,8 @@ export declare class TuiProcess {
167
180
  mux?: boolean;
168
181
  headless?: boolean;
169
182
  desktop?: boolean;
183
+ /** Admission from this host's CLI bootstrap, never an environment cache. */
184
+ desktopRuntime?: DesktopRuntime | null;
170
185
  desktopUpdateRelaunch?: string;
171
186
  /** Extra environment for the renderer process (e.g. the zmux keymap). */
172
187
  env?: Record<string, string>;
@@ -218,6 +233,7 @@ export declare class NullTuiProcess {
218
233
  get zmuxMirrorSocketPath(): string | null;
219
234
  hasCapability(_name: string): boolean;
220
235
  readClipboardImage(): Promise<Buffer | null>;
236
+ readClipboardText(): Promise<string | null>;
221
237
  /** NullTuiProcess never has a mirror socket; callback never fires. */
222
238
  onZmuxMirrorSocketReady(_cb: (path: string) => void): () => void;
223
239
  on(handler: TuiEventHandler): () => void;
@@ -15,8 +15,9 @@ import { join, dirname, resolve } from 'path';
15
15
  import { homedir, platform, arch, tmpdir } from 'os';
16
16
  import { fileURLToPath } from 'url';
17
17
  import { createConnection } from 'net';
18
- import { serializeCommand, parseEvent, CAPABILITY_CLIPBOARD_IMAGE } from './protocol.js';
19
- import { generateIpcPath } from './ipc_path.js';
18
+ import { serializeCommand, parseEvent, CAPABILITY_CLIPBOARD_IMAGE, CAPABILITY_CLIPBOARD_TEXT } from './protocol.js';
19
+ import { generateIpcPath, removeOwnedIpcPath } from './ipc_path.js';
20
+ import { loadDesktopRuntime, validateDesktopRendererReady } from '../../desktop/runtime.js';
20
21
  // Debug log file - use a file to avoid interfering with TUI
21
22
  const DEBUG_LOG_FILE = join(tmpdir(), `ztc-debug-${process.pid}.log`);
22
23
  function debugLog(message) {
@@ -203,7 +204,10 @@ export function resolveZtermBinaryPath(dependencies) {
203
204
  return dependencies.resolveFallback();
204
205
  }
205
206
  /** Get the path to the zterm desktop binary. */
206
- function getZtermBinaryPath() {
207
+ function getZtermBinaryPath(admission) {
208
+ const runtime = admission === undefined ? loadDesktopRuntime() : admission;
209
+ if (runtime)
210
+ return runtime.rendererPath;
207
211
  const binaryName = getZtermBinaryName();
208
212
  return resolveZtermBinaryPath({
209
213
  operatingSystem: platform(),
@@ -222,8 +226,8 @@ export function isZmuxAvailable() {
222
226
  * Check if zterm is available. Unlike zmux, zterm is a desktop process and
223
227
  * does not require the current process to have a TTY.
224
228
  */
225
- export function isZtermAvailable() {
226
- return getZtermBinaryPath() !== null;
229
+ export function isZtermAvailable(admission) {
230
+ return getZtermBinaryPath(admission) !== null;
227
231
  }
228
232
  /**
229
233
  * Launch the native zterm desktop binary and resolve with its exit code.
@@ -314,6 +318,11 @@ export function isTransientSocketConnectError(code) {
314
318
  * Manages the Rust TUI process with Unix socket communication
315
319
  */
316
320
  export class TuiProcess {
321
+ options;
322
+ /** Host-selected unmanaged renderer; validated bundle admission takes precedence. */
323
+ constructor(options = {}) {
324
+ this.options = options;
325
+ }
317
326
  process = null;
318
327
  socket = null;
319
328
  readline = null;
@@ -329,6 +338,9 @@ export class TuiProcess {
329
338
  _muxMode = false;
330
339
  /** Whether zterm is being used as the native desktop renderer */
331
340
  _desktopMode = false;
341
+ desktopCompatibility = null;
342
+ /** Retained across socket cleanup so an admitted renderer can request owner exit. */
343
+ desktopStartupAdmitted = false;
332
344
  stopping = false;
333
345
  /** Whether zmux was detected from the ready event version string */
334
346
  _isZmux = false;
@@ -354,6 +366,7 @@ export class TuiProcess {
354
366
  */
355
367
  clipboardRequests = new Map();
356
368
  clipboardRequestSeq = 0;
369
+ clipboardTextRequests = new Map();
357
370
  /**
358
371
  * Subscribe to zmux's mirror-socket path. The callback runs exactly once:
359
372
  * synchronously if the path is already known, otherwise as soon as zmux
@@ -436,6 +449,26 @@ export class TuiProcess {
436
449
  this.clipboardRequests.delete(requestId);
437
450
  pending.resolve(png);
438
451
  }
452
+ /** Read exact text through the renderer; null means unavailable, '' means empty. */
453
+ readClipboardText(timeoutMs = 4000) {
454
+ if (!this.hasCapability(CAPABILITY_CLIPBOARD_TEXT))
455
+ return Promise.resolve(null);
456
+ const requestId = `clip-text-${++this.clipboardRequestSeq}-${Date.now().toString(36)}`;
457
+ return new Promise((resolve) => {
458
+ const timer = setTimeout(() => this.settleClipboardTextRequest(requestId, null), timeoutMs);
459
+ this.clipboardTextRequests.set(requestId, { resolve, timer });
460
+ if (!this.send({ type: 'read_clipboard_text', request_id: requestId }))
461
+ this.settleClipboardTextRequest(requestId, null);
462
+ });
463
+ }
464
+ settleClipboardTextRequest(requestId, text) {
465
+ const pending = this.clipboardTextRequests.get(requestId);
466
+ if (!pending)
467
+ return;
468
+ clearTimeout(pending.timer);
469
+ this.clipboardTextRequests.delete(requestId);
470
+ pending.resolve(text);
471
+ }
439
472
  /**
440
473
  * Mirror socket path this zmux is exposing, or null if unavailable
441
474
  * (non-zmux mode, bind failed, or announcement not received yet).
@@ -456,12 +489,21 @@ export class TuiProcess {
456
489
  }
457
490
  this._muxMode = options?.mux ?? false;
458
491
  this._desktopMode = options?.desktop ?? false;
492
+ this.desktopCompatibility = null;
493
+ this.desktopStartupAdmitted = false;
494
+ this._capabilities.clear();
495
+ this.stopping = false;
459
496
  let binaryPath;
460
497
  if (this._desktopMode) {
461
- binaryPath = getZtermBinaryPath();
498
+ const runtime = options?.desktopRuntime === undefined ? loadDesktopRuntime() : options.desktopRuntime;
499
+ binaryPath = runtime?.rendererPath ?? this.options.desktopBinaryPath ?? getZtermBinaryPath(runtime);
462
500
  if (!binaryPath) {
463
501
  throw new Error('zterm binary not found. Build with: cd packages/zterm && cargo build --release');
464
502
  }
503
+ if (runtime)
504
+ this.desktopCompatibility = { version: runtime.rendererVersion, requiredCapabilities: runtime.requiredCapabilities };
505
+ else if (binaryPath === resolveInstalledZtermExecutable())
506
+ this.desktopCompatibility = {};
465
507
  }
466
508
  else if (this._muxMode) {
467
509
  binaryPath = getZmuxBinaryPath();
@@ -576,7 +618,7 @@ export class TuiProcess {
576
618
  this.process.on('close', (code, signal) => {
577
619
  debugLog(`[TuiProcess] Process closed: code=${code}, signal=${signal}`);
578
620
  debugLog(`[TuiProcess] stderr buffer at close: ${stderrBuffer || '(empty)'}`);
579
- const shouldExitOwner = this._desktopMode && this.readyReject === null && !this.stopping;
621
+ const shouldExitOwner = this._desktopMode && this.desktopStartupAdmitted && !this.stopping;
580
622
  this.cleanup();
581
623
  if (shouldExitOwner) {
582
624
  this.emit({ type: 'quit_requested' });
@@ -734,7 +776,24 @@ export class TuiProcess {
734
776
  this.settleClipboardRequest(event.request_id, event.png_base64 ? Buffer.from(event.png_base64, 'base64') : null);
735
777
  return;
736
778
  }
779
+ if (event.type === 'clipboard_text') {
780
+ this.settleClipboardTextRequest(event.request_id, !event.error && typeof event.text === 'string' ? event.text : null);
781
+ return;
782
+ }
737
783
  if (event.type === 'ready' && this.readyResolve) {
784
+ if (this.desktopCompatibility) {
785
+ try {
786
+ validateDesktopRendererReady(event, this.desktopCompatibility.version, this.desktopCompatibility.requiredCapabilities);
787
+ }
788
+ catch (error) {
789
+ this.readyReject?.(error);
790
+ this.readyResolve = null;
791
+ this.readyReject = null;
792
+ this.cleanup();
793
+ return;
794
+ }
795
+ }
796
+ this.desktopStartupAdmitted = this._desktopMode;
738
797
  this.ready = true;
739
798
  this._isZmux = event.version.startsWith('zmux-') || event.version.startsWith('zterm-');
740
799
  if (event.capabilities) {
@@ -783,6 +842,11 @@ export class TuiProcess {
783
842
  pending.resolve(null);
784
843
  }
785
844
  this.clipboardRequests.clear();
845
+ for (const pending of this.clipboardTextRequests.values()) {
846
+ clearTimeout(pending.timer);
847
+ pending.resolve(null);
848
+ }
849
+ this.clipboardTextRequests.clear();
786
850
  if (this.connectRetryTimer) {
787
851
  clearTimeout(this.connectRetryTimer);
788
852
  this.connectRetryTimer = null;
@@ -802,6 +866,12 @@ export class TuiProcess {
802
866
  catch {
803
867
  // Ignore
804
868
  }
869
+ try {
870
+ removeOwnedIpcPath(this.socketPath);
871
+ }
872
+ catch (error) {
873
+ debugLog(`[TuiProcess] IPC directory cleanup failed: ${String(error)}`);
874
+ }
805
875
  this.socketPath = null;
806
876
  }
807
877
  // Tearing down without signalling a still-running child orphans the native
@@ -884,6 +954,9 @@ export class NullTuiProcess {
884
954
  readClipboardImage() {
885
955
  return Promise.resolve(null);
886
956
  }
957
+ readClipboardText() {
958
+ return Promise.resolve(null);
959
+ }
887
960
  /** NullTuiProcess never has a mirror socket; callback never fires. */
888
961
  onZmuxMirrorSocketReady(_cb) {
889
962
  return () => { };