@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
@@ -0,0 +1,648 @@
1
+ """Authenticated fixed-operation receiver; requires a read-only execution image."""
2
+
3
+ import hashlib
4
+ import hmac
5
+ import json
6
+ import logging
7
+ import os
8
+ import re
9
+ import socket
10
+ import stat
11
+ import subprocess
12
+ import sys
13
+ import threading
14
+ from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
15
+ from pathlib import Path
16
+ from typing import Any, Literal
17
+
18
+ from pydantic import BaseModel, ConfigDict, Field
19
+
20
+ L = logging.getLogger(__name__)
21
+ MAXIMUM_BYTES = 8 * 1024 * 1024
22
+ MAXIMUM_CONCURRENT_REQUESTS = 16
23
+ INSTALLATION = Path(__file__).resolve().parent
24
+
25
+
26
+ class MountTopologyChangedError(ValueError):
27
+ """A stable operator-facing refusal without request or filesystem contents."""
28
+
29
+
30
+ class RequestNotDispatchedError(ValueError):
31
+ """Preparation failed before the worker could run."""
32
+
33
+
34
+ class FilesystemRegion(BaseModel):
35
+ model_config = ConfigDict(extra="forbid", strict=True, frozen=True)
36
+ version: Literal[1] = 1
37
+ device: str = Field(pattern=r"^[0-9]+:[0-9]+$")
38
+ path: str = Field(min_length=1, max_length=4096)
39
+
40
+
41
+ class MountEntry(BaseModel):
42
+ model_config = ConfigDict(extra="forbid", strict=True, frozen=True)
43
+ mount_id: int = Field(gt=0)
44
+ device: str
45
+ root: str
46
+ mount_point: str
47
+
48
+
49
+ def read_mount_snapshot() -> bytes:
50
+ with Path("/proc/self/mountinfo").open("rb") as stream:
51
+ data = stream.read(MAXIMUM_BYTES + 1)
52
+ if not data or len(data) > MAXIMUM_BYTES:
53
+ raise ValueError("Host mount topology is empty or exceeds its bound")
54
+ return data
55
+
56
+
57
+ def decode_mount_path(value: str) -> str:
58
+ if re.search(r"\\(?!040|011|012|134)", value):
59
+ raise ValueError("Unsupported host mount path escape")
60
+ path = re.sub(r"\\(040|011|012|134)", lambda match: chr(int(match[1], 8)), value)
61
+ if not os.path.isabs(path) or os.path.normpath(path) != path or "\x00" in path:
62
+ raise ValueError("Host mount paths must be canonical and absolute")
63
+ return path
64
+
65
+
66
+ def parse_mount_snapshot(data: bytes) -> dict[int, MountEntry]:
67
+ entries: dict[int, MountEntry] = {}
68
+ for line in data.decode("utf-8").splitlines():
69
+ before, separator, after = line.partition(" - ")
70
+ fields = before.split()
71
+ if (
72
+ not separator
73
+ or len(fields) < 6
74
+ or len(after.split()) < 3
75
+ or not re.fullmatch(r"[0-9]+", fields[0])
76
+ or not re.fullmatch(r"[0-9]+:[0-9]+", fields[2])
77
+ ):
78
+ raise ValueError("Malformed host mount topology")
79
+ entry = MountEntry(
80
+ mount_id=int(fields[0]),
81
+ device=fields[2],
82
+ root=decode_mount_path(fields[3]),
83
+ mount_point=decode_mount_path(fields[4]),
84
+ )
85
+ if entry.mount_id in entries:
86
+ raise ValueError("Duplicate host mount identity")
87
+ entries[entry.mount_id] = entry
88
+ if not entries:
89
+ raise ValueError("Host mount topology is empty")
90
+ return entries
91
+
92
+
93
+ class Endpoint(BaseModel):
94
+ model_config = ConfigDict(extra="forbid", strict=True, frozen=True)
95
+ host: str = Field(min_length=1, max_length=253)
96
+ user: str = Field(min_length=1, max_length=100)
97
+ port: int = Field(ge=1, le=65535)
98
+
99
+
100
+ class Resource(BaseModel):
101
+ model_config = ConfigDict(extra="forbid", strict=True, frozen=True)
102
+ id: str = Field(min_length=1, max_length=100, pattern=r"^[a-zA-Z0-9._:-]+$")
103
+ root: str = Field(min_length=1, max_length=4096)
104
+ endpoint: Endpoint
105
+ # Operator configuration contract; request fields cannot supply this policy.
106
+ write_staging_directory: str | None = Field(default=None, max_length=4096)
107
+
108
+
109
+ class Configuration(BaseModel):
110
+ model_config = ConfigDict(extra="forbid", strict=True, frozen=True)
111
+ version: Literal[1]
112
+ resources: list[Resource] = Field(min_length=1, max_length=100)
113
+ receipt_archive_index: bool = False
114
+ legacy_write_staging_directories: list[str] = Field(
115
+ default_factory=list, max_length=100
116
+ )
117
+
118
+
119
+ class Request(BaseModel):
120
+ # Unknown model fields have no authority and are never forwarded to the worker.
121
+ model_config = ConfigDict(extra="ignore", strict=True)
122
+ operation: Literal[
123
+ "status",
124
+ "claim",
125
+ "transfer",
126
+ "stop",
127
+ "read",
128
+ "list",
129
+ "stat",
130
+ "write",
131
+ "delete",
132
+ "receipt",
133
+ "ack",
134
+ "reconcile",
135
+ "resolve",
136
+ ]
137
+ root: str = Field(max_length=4096)
138
+ resource_id: str = Field(max_length=100)
139
+ owner_id: str = Field(min_length=1, max_length=200)
140
+ endpoint: Endpoint
141
+ client_journal: str | None = Field(default=None, max_length=4096)
142
+ path: str | None = Field(default=None, max_length=4096)
143
+ content: str | None = Field(default=None, max_length=1048576)
144
+ dry_run: bool = False
145
+ tool_call_id: str | None = Field(default=None, max_length=200)
146
+ operation_id: str | None = Field(default=None, max_length=36)
147
+ receipt_id: str | None = Field(default=None, max_length=36)
148
+ observation_token: str | None = Field(default=None, max_length=64)
149
+ expected_generation: int | None = None
150
+ target_owner_id: str | None = Field(default=None, max_length=200)
151
+ ttl_seconds: int | float | None = None
152
+ original_operation: Literal["write", "delete"] | None = None
153
+ original_owner_id: str | None = Field(default=None, max_length=200)
154
+ original_tool_call_id: str | None = Field(default=None, max_length=200)
155
+
156
+
157
+ class ImmutableResourceBroker:
158
+ def __init__(self) -> None:
159
+ self._init_execution_system()
160
+ self._init_resource_system()
161
+ self._init_mount_system()
162
+
163
+ def _init_execution_system(self) -> None:
164
+ if not sys.flags.isolated or os.geteuid() == 0:
165
+ raise ValueError(
166
+ "Broker requires isolated Python and a non-root service user"
167
+ )
168
+ self.interpreter = Path(sys.executable).resolve()
169
+ self.worker = INSTALLATION / "worker.py"
170
+ self.configuration_path = INSTALLATION / "resources.json"
171
+ trusted = [
172
+ INSTALLATION,
173
+ self.worker,
174
+ self.configuration_path,
175
+ self.interpreter,
176
+ Path(sys.prefix),
177
+ ]
178
+ for path in trusted:
179
+ if not os.statvfs(path).f_flag & os.ST_RDONLY:
180
+ raise ValueError(
181
+ "Broker requires a read-only execution image and policy"
182
+ )
183
+ self.trusted_devices = {path.stat().st_dev for path in trusted}
184
+ self.token = os.environ.get("ZTC_BROKER_TOKEN", "")
185
+ if not re.fullmatch(r"[!-~]{32,4096}", self.token):
186
+ raise ValueError(
187
+ "Broker requires a credential of 32 to 4096 ASCII characters"
188
+ )
189
+ self.root_identities: dict[str, tuple[int, int]] = {}
190
+
191
+ def _init_resource_system(self) -> None:
192
+ config = Configuration.model_validate_json(self.configuration_path.read_text())
193
+ self.receipt_archive_index = config.receipt_archive_index
194
+ self.resources = {resource.id: resource for resource in config.resources}
195
+ if len(self.resources) != len(config.resources):
196
+ raise ValueError("Broker resource IDs must be unique")
197
+ self.deletion_staging = Path("/data/.ztc-delete-quarantine")
198
+ self.deletion_staging.mkdir(mode=0o700, exist_ok=True)
199
+ private = self.deletion_staging.lstat()
200
+ if (
201
+ not stat.S_ISDIR(private.st_mode)
202
+ or private.st_uid != os.geteuid()
203
+ or private.st_mode & 0o077
204
+ ):
205
+ raise ValueError(
206
+ "Broker deletion staging must be private to its service UID"
207
+ )
208
+ self.deletion_staging_identity = (private.st_dev, private.st_ino)
209
+ for directory in [Path("/data"), self.deletion_staging]:
210
+ descriptor = os.open(
211
+ directory, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW
212
+ )
213
+ try:
214
+ os.fsync(descriptor)
215
+ finally:
216
+ os.close(descriptor)
217
+ for resource in config.resources:
218
+ root = Path(resource.root)
219
+ if (
220
+ not root.is_absolute()
221
+ or str(root.resolve()) != resource.root
222
+ or not root.is_relative_to("/data")
223
+ or root.is_relative_to(self.deletion_staging)
224
+ ):
225
+ raise ValueError(
226
+ "Broker writable roots must be canonical directories beneath /data"
227
+ )
228
+ root.mkdir(mode=0o700, parents=True, exist_ok=True)
229
+ info = root.stat()
230
+ if not stat.S_ISDIR(info.st_mode) or info.st_dev in self.trusted_devices:
231
+ raise ValueError(
232
+ "Broker data must use a separate filesystem "
233
+ "from its executor and policy"
234
+ )
235
+ self.root_identities[resource.id] = (info.st_dev, info.st_ino)
236
+ self.write_staging_directories: dict[str, Path] = {}
237
+ self.trusted_staging_identities: dict[str, tuple[int, int]] = {
238
+ str(self.deletion_staging): self.deletion_staging_identity
239
+ }
240
+ for resource in config.resources:
241
+ self.write_staging_directories[resource.id] = (
242
+ Path(resource.write_staging_directory)
243
+ if resource.write_staging_directory is not None
244
+ else self.deletion_staging
245
+ )
246
+ for path in [
247
+ *self.write_staging_directories.values(),
248
+ *map(Path, config.legacy_write_staging_directories),
249
+ ]:
250
+ if (
251
+ not path.is_absolute()
252
+ or str(path.resolve(strict=True)) != str(path)
253
+ or not path.is_relative_to("/data")
254
+ ):
255
+ raise ValueError(
256
+ "Write staging must be an existing canonical /data directory"
257
+ )
258
+ private = path.lstat()
259
+ if (
260
+ not stat.S_ISDIR(private.st_mode)
261
+ or private.st_uid != os.geteuid()
262
+ or private.st_mode & 0o077
263
+ or private.st_dev in self.trusted_devices
264
+ ):
265
+ raise ValueError(
266
+ "Write staging must be private to the broker on its data filesystem"
267
+ )
268
+ self.trusted_staging_identities[str(path)] = (
269
+ private.st_dev,
270
+ private.st_ino,
271
+ )
272
+ os.makedirs("/state", mode=0o700, exist_ok=True)
273
+
274
+ def _init_mount_system(self) -> None:
275
+ snapshot = read_mount_snapshot()
276
+ entries = parse_mount_snapshot(snapshot)
277
+ self.mountinfo_sha256 = hashlib.sha256(snapshot).hexdigest()
278
+ self.filesystem_regions: dict[str, FilesystemRegion] = {}
279
+ self.resource_mount_ids: dict[str, int] = {}
280
+ for resource in self.resources.values():
281
+ root = Path(resource.root)
282
+ if any(
283
+ Path(entry.mount_point) != root
284
+ and Path(entry.mount_point).is_relative_to(root)
285
+ for entry in entries.values()
286
+ ):
287
+ raise ValueError("Nested mounts require proven overlap before serving")
288
+ descriptor = os.open(root, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW)
289
+ try:
290
+ info = os.fstat(descriptor)
291
+ details = Path(f"/proc/self/fdinfo/{descriptor}").read_text()
292
+ match = re.search(r"^mnt_id:\s*([0-9]+)$", details, re.MULTILINE)
293
+ if match is None or int(match[1]) not in entries:
294
+ raise ValueError("Host root has no proven mount identity")
295
+ entry = entries[int(match[1])]
296
+ if (
297
+ (info.st_dev, info.st_ino) != self.root_identities[resource.id]
298
+ or entry.device
299
+ != f"{os.major(info.st_dev)}:{os.minor(info.st_dev)}"
300
+ or not root.is_relative_to(entry.mount_point)
301
+ ):
302
+ raise ValueError("Host root does not match its mount identity")
303
+ path = str(Path(entry.root) / root.relative_to(entry.mount_point))
304
+ self.filesystem_regions[resource.id] = FilesystemRegion(
305
+ device=entry.device, path=path
306
+ )
307
+ self.resource_mount_ids[resource.id] = entry.mount_id
308
+ finally:
309
+ os.close(descriptor)
310
+ staging_mount_ids: dict[str, int] = {}
311
+ for path, expected in self.trusted_staging_identities.items():
312
+ location = Path(path)
313
+ if any(
314
+ Path(entry.mount_point) != location
315
+ and Path(entry.mount_point).is_relative_to(location)
316
+ for entry in entries.values()
317
+ ):
318
+ raise ValueError("Nested private staging mounts are unsupported")
319
+ descriptor = os.open(location, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW)
320
+ try:
321
+ info = os.fstat(descriptor)
322
+ details = Path(f"/proc/self/fdinfo/{descriptor}").read_text()
323
+ match = re.search(r"^mnt_id:\s*([0-9]+)$", details, re.MULTILINE)
324
+ if match is None or int(match[1]) not in entries:
325
+ raise ValueError("Write staging has no proven mount identity")
326
+ entry = entries[int(match[1])]
327
+ if (
328
+ (info.st_dev, info.st_ino) != expected
329
+ or entry.device
330
+ != f"{os.major(info.st_dev)}:{os.minor(info.st_dev)}"
331
+ or not location.is_relative_to(entry.mount_point)
332
+ ):
333
+ raise ValueError("Write staging does not match its mount identity")
334
+ physical_path = str(
335
+ Path(entry.root) / location.relative_to(entry.mount_point)
336
+ )
337
+ if any(
338
+ region.device == entry.device
339
+ and os.path.commonpath([physical_path, region.path])
340
+ in [physical_path, region.path]
341
+ for region in self.filesystem_regions.values()
342
+ ):
343
+ raise ValueError(
344
+ "Private staging overlaps a configured resource through its filesystem region"
345
+ )
346
+ staging_mount_ids[path] = entry.mount_id
347
+ finally:
348
+ os.close(descriptor)
349
+ for resource in self.resources.values():
350
+ if resource.write_staging_directory is not None and (
351
+ staging_mount_ids[str(self.write_staging_directories[resource.id])]
352
+ != self.resource_mount_ids[resource.id]
353
+ ):
354
+ raise ValueError(
355
+ "Configured write staging must share the exact resource mount"
356
+ )
357
+ self._validate_mount_system()
358
+
359
+ def _validate_mount_system(self) -> None:
360
+ if hashlib.sha256(read_mount_snapshot()).hexdigest() != self.mountinfo_sha256:
361
+ raise MountTopologyChangedError(
362
+ "Host mount topology changed; restart with reviewed policy"
363
+ )
364
+ for resource in self.resources.values():
365
+ if str(Path(resource.root).resolve()) != resource.root:
366
+ raise ValueError("Host broker resource canonical path changed")
367
+ info = os.stat(resource.root)
368
+ if (info.st_dev, info.st_ino) != self.root_identities[resource.id]:
369
+ raise ValueError("Host broker resource identity changed")
370
+ for path, expected in self.trusted_staging_identities.items():
371
+ private = Path(path).lstat()
372
+ if (
373
+ str(Path(path).resolve()) != path
374
+ or not stat.S_ISDIR(private.st_mode)
375
+ or (private.st_dev, private.st_ino) != expected
376
+ or private.st_uid != os.geteuid()
377
+ or private.st_mode & 0o077
378
+ ):
379
+ raise ValueError(
380
+ "Host broker private staging identity or permissions changed"
381
+ )
382
+
383
+ def _prepare_request(self, data: dict[str, Any]) -> str:
384
+ request = Request.model_validate(data)
385
+ resource = self.resources.get(request.resource_id)
386
+ if (
387
+ resource is None
388
+ or request.root != resource.root
389
+ or request.endpoint != resource.endpoint
390
+ ):
391
+ raise ValueError("Request does not match a host-configured broker resource")
392
+ info = os.stat(resource.root)
393
+ identity = (info.st_dev, info.st_ino)
394
+ if identity != self.root_identities[resource.id]:
395
+ raise ValueError("Host broker resource identity changed")
396
+ self._validate_mount_system()
397
+ payload = request.model_dump(exclude_unset=True)
398
+ payload["host_receipt_archive_index"] = self.receipt_archive_index
399
+ payload["host_root_identity"] = list(identity)
400
+ payload["host_mountinfo_sha256"] = self.mountinfo_sha256
401
+ payload["host_filesystem_region"] = self.filesystem_regions[
402
+ resource.id
403
+ ].model_dump()
404
+ payload["host_resource_roots"] = {
405
+ item.root: list(self.root_identities[item.id])
406
+ for item in self.resources.values()
407
+ }
408
+ private = self.deletion_staging.lstat()
409
+ if (private.st_dev, private.st_ino) != self.deletion_staging_identity:
410
+ raise ValueError("Host broker deletion staging identity changed")
411
+ payload["host_delete_staging"] = str(self.deletion_staging)
412
+ payload["host_delete_staging_identity"] = list(self.deletion_staging_identity)
413
+ write_staging = str(self.write_staging_directories[resource.id])
414
+ payload["host_write_staging"] = write_staging
415
+ payload["host_write_staging_identity"] = list(
416
+ self.trusted_staging_identities[write_staging]
417
+ )
418
+ payload["host_write_staging_directories"] = {
419
+ path: list(identity)
420
+ for path, identity in self.trusted_staging_identities.items()
421
+ }
422
+ return json.dumps(payload)
423
+
424
+ def execute_request(self, data: dict[str, Any]) -> dict[str, Any]:
425
+ try:
426
+ payload = self._prepare_request(data)
427
+ except (ValueError, OSError) as error:
428
+ raise RequestNotDispatchedError(
429
+ str(error)
430
+ if isinstance(error, MountTopologyChangedError)
431
+ else "Request refused by immutable broker policy"
432
+ ) from error
433
+ # No shell, PATH lookup, account startup or writable Python search path.
434
+ # Neither credentials nor caller environment enter the worker process.
435
+ try:
436
+ result = subprocess.run(
437
+ [str(self.interpreter), "-I", "-B", str(self.worker)],
438
+ input=payload,
439
+ capture_output=True,
440
+ text=True,
441
+ cwd=str(INSTALLATION),
442
+ env={"HOME": "/state", "LANG": "C.UTF-8"},
443
+ timeout=30,
444
+ check=False,
445
+ )
446
+ except (OSError, ValueError):
447
+ return {
448
+ "ok": False,
449
+ "error": "Broker execution interrupted; outcome may be unresolved",
450
+ }
451
+ except subprocess.TimeoutExpired:
452
+ return {
453
+ "ok": False,
454
+ "error": "Broker execution timed out; outcome may be unresolved",
455
+ }
456
+ try:
457
+ if len(result.stdout.encode()) > MAXIMUM_BYTES:
458
+ return {
459
+ "ok": False,
460
+ "error": "Broker execution exceeded its response bound",
461
+ }
462
+ envelope = json.loads(result.stdout)
463
+ except (ValueError, RecursionError):
464
+ return {
465
+ "ok": False,
466
+ "error": "Broker execution did not return a complete receipt",
467
+ }
468
+ if not isinstance(envelope, dict) or not isinstance(envelope.get("ok"), bool):
469
+ return {"ok": False, "error": "Invalid broker execution envelope"}
470
+ if result.returncode != 0 and envelope["ok"]:
471
+ return {
472
+ "ok": False,
473
+ "error": "Broker execution failed before acknowledgement",
474
+ }
475
+ return envelope
476
+
477
+
478
+ class BrokerServer(ThreadingHTTPServer):
479
+ def __init__(self, broker: ImmutableResourceBroker, port: int) -> None:
480
+ self.broker = broker
481
+ self.request_slots = threading.BoundedSemaphore(MAXIMUM_CONCURRENT_REQUESTS)
482
+ super().__init__(("0.0.0.0", port), BrokerHandler)
483
+
484
+ def process_request(
485
+ self, request: socket.socket, client_address: tuple[str, int]
486
+ ) -> None:
487
+ # Admission happens in the accept loop, before a handler or header timer
488
+ # exists. Waiting here would let incomplete peers block every new client.
489
+ if not self.request_slots.acquire(blocking=False):
490
+ encoded = json.dumps(
491
+ {"ok": False, "error": "Broker request capacity reached"}
492
+ ).encode()
493
+ response = (
494
+ "HTTP/1.1 503 Service Unavailable\r\n"
495
+ "Content-Type: application/json\r\n"
496
+ f"Content-Length: {len(encoded)}\r\n"
497
+ "Cache-Control: no-store\r\n"
498
+ "Connection: close\r\n\r\n"
499
+ ).encode() + encoded
500
+ try:
501
+ request.settimeout(1)
502
+ request.sendall(response)
503
+ except OSError:
504
+ L.debug("Overloaded broker peer disconnected")
505
+ finally:
506
+ self.shutdown_request(request)
507
+ return
508
+ try:
509
+ super().process_request(request, client_address)
510
+ except BaseException:
511
+ self.request_slots.release()
512
+ raise
513
+
514
+ def process_request_thread(
515
+ self, request: socket.socket, client_address: tuple[str, int]
516
+ ) -> None:
517
+ try:
518
+ super().process_request_thread(request, client_address)
519
+ finally:
520
+ self.request_slots.release()
521
+
522
+
523
+ class BrokerHandler(BaseHTTPRequestHandler):
524
+ server: BrokerServer
525
+
526
+ def setup(self) -> None:
527
+ super().setup()
528
+ self.connection.settimeout(5)
529
+ self.header_timer: threading.Timer | None = None
530
+
531
+ def handle_one_request(self) -> None:
532
+ # Socket read timeouts bound silence only. An absolute deadline also
533
+ # bounds unfinished request lines/headers that continue receiving bytes.
534
+ self.header_timer = threading.Timer(5, self._expire_headers)
535
+ self.header_timer.daemon = True
536
+ self.header_timer.start()
537
+ try:
538
+ super().handle_one_request()
539
+ finally:
540
+ self.header_timer.cancel()
541
+
542
+ def parse_request(self) -> bool:
543
+ try:
544
+ return super().parse_request()
545
+ finally:
546
+ # Complete headers enter the ordinary authenticated/body path,
547
+ # whose read timeout and framing bounds remain independent.
548
+ if self.header_timer is not None:
549
+ self.header_timer.cancel()
550
+
551
+ def _expire_headers(self) -> None:
552
+ try:
553
+ self.connection.shutdown(socket.SHUT_RDWR)
554
+ except OSError:
555
+ pass # The peer or request cleanup already closed this connection.
556
+
557
+ def log_message(self, format: str, *args: Any) -> None:
558
+ # Request paths, headers, payloads and credentials are never logged.
559
+ L.debug("Broker HTTP request completed")
560
+
561
+ def send_envelope(self, status: int, envelope: dict[str, Any]) -> None:
562
+ encoded = json.dumps(envelope).encode()
563
+ self.send_response(status)
564
+ self.send_header("Content-Type", "application/json")
565
+ self.send_header("Content-Length", str(len(encoded)))
566
+ self.send_header("Cache-Control", "no-store")
567
+ self.end_headers()
568
+ self.wfile.write(encoded)
569
+
570
+ def do_POST(self) -> None:
571
+ credential = self.headers.get("Authorization", "").encode()
572
+ if not hmac.compare_digest(
573
+ credential, ("Bearer " + self.server.broker.token).encode()
574
+ ):
575
+ self.send_envelope(
576
+ 401, {"ok": False, "error": "Broker authentication required"}
577
+ )
578
+ return
579
+ if (
580
+ self.path != "/v1/resources"
581
+ or self.headers.get("Transfer-Encoding") is not None
582
+ ):
583
+ self.send_envelope(
584
+ 400, {"ok": False, "error": "Invalid broker route or framing"}
585
+ )
586
+ return
587
+ length = self.headers.get("Content-Length", "")
588
+ if (
589
+ not length.isdecimal()
590
+ or len(length) > 9
591
+ or not 0 < int(length) <= MAXIMUM_BYTES
592
+ ):
593
+ self.send_envelope(
594
+ 413, {"ok": False, "error": "Broker request exceeds its bound"}
595
+ )
596
+ return
597
+ data: dict[str, Any] = {}
598
+ try:
599
+ raw = self.rfile.read(int(length))
600
+ if len(raw) != int(length):
601
+ raise ValueError("Incomplete broker request")
602
+ parsed = json.loads(raw)
603
+ if not isinstance(parsed, dict):
604
+ raise ValueError("Broker request must be an object")
605
+ data = parsed
606
+ except (ValueError, OSError, RecursionError):
607
+ # Body parsing cannot dispatch a worker or recover a trusted request.
608
+ self.send_envelope(
609
+ 200,
610
+ {"ok": False, "error": "Request refused by immutable broker policy"},
611
+ )
612
+ return
613
+ try:
614
+ envelope = self.server.broker.execute_request(data)
615
+ except RequestNotDispatchedError as error:
616
+ # Only preparation can establish this proof. Other execution errors
617
+ # must not release a client's reservation after a possible effect.
618
+ envelope = {
619
+ "ok": False,
620
+ "error": str(error),
621
+ "admitted": False,
622
+ "operation_id": data.get("operation_id"),
623
+ }
624
+ except (ValueError, OSError, RecursionError):
625
+ envelope = {
626
+ "ok": False,
627
+ "error": "Broker execution failed; outcome may be unresolved",
628
+ }
629
+ self.send_envelope(200, envelope)
630
+
631
+
632
+ def main() -> None:
633
+ logging.basicConfig(level=logging.INFO)
634
+ try:
635
+ broker = ImmutableResourceBroker()
636
+ port = int(os.environ.get("ZTC_BROKER_PORT", "8787"))
637
+ if not 1 <= port <= 65535:
638
+ raise ValueError("Invalid broker port")
639
+ with BrokerServer(broker, port) as server:
640
+ L.info("Immutable resource broker ready on port %d", port)
641
+ server.serve_forever()
642
+ except (ValueError, OSError) as error:
643
+ L.error("Broker startup refused: %s", error)
644
+ raise SystemExit(1) from error
645
+
646
+
647
+ if __name__ == "__main__":
648
+ main()