@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,910 @@
1
+ export class DynamicMechanicContractError extends Error {
2
+ code;
3
+ constructor(code, message) {
4
+ super(message);
5
+ this.code = code;
6
+ this.name = 'DynamicMechanicContractError';
7
+ }
8
+ }
9
+ export function validateDynamicMechanicCatalog(definitions) {
10
+ if (!Array.isArray(definitions) || definitions.length === 0 || definitions.length > 64) {
11
+ fail('mechanic-catalog-invalid', 'A mechanic catalog needs one to sixty-four definitions');
12
+ }
13
+ assertUnique(definitions.map(definition => definition.id), 'mechanic identifiers');
14
+ for (const definition of definitions) {
15
+ assertIdentifier(definition.id, 'mechanic identifier');
16
+ assertText(definition.description, 'mechanic description', 500);
17
+ if (!['required', 'optional', 'game-master'].includes(definition.actor)) {
18
+ fail('mechanic-catalog-invalid', `Mechanic ${definition.id} has an invalid actor rule`);
19
+ }
20
+ if (!['none', 'optional', 'required'].includes(definition.target)) {
21
+ fail('mechanic-catalog-invalid', `Mechanic ${definition.id} has an invalid target rule`);
22
+ }
23
+ if (!Array.isArray(definition.intentParameters)
24
+ || !Array.isArray(definition.resolutionParameters)
25
+ || definition.intentParameters.length > 12
26
+ || definition.resolutionParameters.length > 12) {
27
+ fail('mechanic-catalog-invalid', `Mechanic ${definition.id} has too many parameters`);
28
+ }
29
+ const parameters = [
30
+ ...definition.intentParameters,
31
+ ...definition.resolutionParameters,
32
+ ];
33
+ assertUnique(parameters.map(parameter => parameter.id), `parameters for ${definition.id}`);
34
+ for (const parameter of parameters)
35
+ validateParameterDefinition(parameter, definition.id);
36
+ if (definition.resolutionParameters.some((parameter) => ((parameter.kind === 'object-reference' || parameter.kind === 'object-reference-list')
37
+ && parameter.actorLinks !== undefined)))
38
+ fail('mechanic-catalog-invalid', 'Actor links constrain intent references only');
39
+ validateScalarBindings(definition.intentParameters);
40
+ if (definition.resolutionParameters.some((parameter) => parameter.valueFrom !== undefined)) {
41
+ fail('mechanic-catalog-invalid', 'Scalar bindings constrain intent parameters only');
42
+ }
43
+ referencePairDefinition(definition.intentParameters);
44
+ referencePairDefinition(definition.resolutionParameters);
45
+ }
46
+ return structuredClone(definitions);
47
+ }
48
+ export function validateDynamicMechanicAction(action, definitions, context, mode, resolutionContext = { ...context, actingActorId: null }) {
49
+ const validatedDefinitions = validateDynamicMechanicCatalog(definitions);
50
+ const definition = validatedDefinitions.find(candidate => candidate.id === action.mechanic);
51
+ if (!definition)
52
+ fail('mechanic-not-allowed', `Mechanic ${action.mechanic} is not defined`);
53
+ validateActors(action, definition, context);
54
+ const parameters = assertRecord(action.parameters, 'action parameters');
55
+ const allowedEnvelopeKeys = mode === 'intent' || definition.resolutionParameters.length === 0
56
+ ? ['intent']
57
+ : ['intent', 'resolution'];
58
+ assertExactKeys(parameters, allowedEnvelopeKeys, ['intent'], 'action parameter envelope');
59
+ const intent = assertRecord(parameters.intent, 'intent parameters');
60
+ const participantContext = { ...context, actingActorId: action.actorId ?? null, targetActorId: action.targetActorId ?? null };
61
+ validateParameterRecord(intent, definition.intentParameters, participantContext);
62
+ if (mode === 'intent' && parameters.resolution !== undefined) {
63
+ fail('mechanic-parameter-invalid', 'An intent cannot author Game Master resolution fields');
64
+ }
65
+ if (mode === 'resolution' && definition.resolutionParameters.length > 0) {
66
+ const requiredResolution = definition.resolutionParameters.some(parameter => parameter.required !== false);
67
+ if (parameters.resolution === undefined) {
68
+ if (requiredResolution) {
69
+ fail('mechanic-parameter-invalid', 'Required resolution parameters are missing');
70
+ }
71
+ }
72
+ else {
73
+ validateParameterRecord(assertRecord(parameters.resolution, 'resolution parameters'), definition.resolutionParameters, resolutionContext);
74
+ }
75
+ }
76
+ return structuredClone(action.parameters);
77
+ }
78
+ export function dynamicMechanicParametersSchema(definition, context, mode) {
79
+ validateDynamicMechanicCatalog([definition]);
80
+ const properties = {
81
+ intent: parameterRecordSchema(definition.intentParameters, context),
82
+ };
83
+ const required = ['intent'];
84
+ if (mode === 'resolution' && definition.resolutionParameters.length > 0) {
85
+ properties.resolution = parameterRecordSchema(definition.resolutionParameters, { ...context, actingActorId: null });
86
+ if (definition.resolutionParameters.some(parameter => parameter.required !== false)) {
87
+ required.push('resolution');
88
+ }
89
+ }
90
+ return strictObjectSchema(required, properties);
91
+ }
92
+ export function constrainDynamicMechanicActionSchema(schema, definition, context) {
93
+ if (!definition.intentParameters.some(parameter => ((parameter.kind === 'object-reference' || parameter.kind === 'object-reference-list')
94
+ && parameter.actorLinks?.target !== undefined)))
95
+ return schema;
96
+ const properties = schema.properties;
97
+ const targetSchema = properties.targetActorId;
98
+ const targets = targetSchema?.enum ?? (targetSchema?.const === undefined ? [] : [targetSchema.const]);
99
+ return { oneOf: targets.flatMap(targetActorId => {
100
+ const bound = { ...context, targetActorId };
101
+ if (targetActorId === context.actingActorId || !dynamicMechanicHasRequiredReferences(definition, bound))
102
+ return [];
103
+ return [{ ...schema, properties: { ...properties, targetActorId: { const: targetActorId },
104
+ parameters: dynamicMechanicParametersSchema(definition, bound, 'intent'),
105
+ } }];
106
+ }) };
107
+ }
108
+ export function dynamicMechanicHasRequiredReferences(definition, context) {
109
+ const pair = referencePairDefinition(definition.intentParameters);
110
+ if (pair !== null && compatibleReferencePairs(pair, context).length === 0)
111
+ return false;
112
+ if (definition.intentParameters.some(parameter => parameter.valueFrom !== undefined)
113
+ && parameterRecordSchema(definition.intentParameters, context).anyOf.length === 0)
114
+ return false;
115
+ return definition.intentParameters.every(parameter => {
116
+ if (parameter.required === false)
117
+ return true;
118
+ switch (parameter.kind) {
119
+ case 'object-reference':
120
+ return compatibleObjects(parameter, context).length > 0;
121
+ case 'object-reference-list':
122
+ return compatibleObjects(parameter, context).length >= parameter.minimumItems;
123
+ case 'actor-reference':
124
+ return context.actorIds.some(actorId => parameter.allowSelf === true || actorId !== context.actingActorId);
125
+ case 'resource-reference':
126
+ return parameter.resourceIds.some(resourceId => context.resourceIds.includes(resourceId));
127
+ default:
128
+ return true;
129
+ }
130
+ });
131
+ }
132
+ export function makeDynamicFallbackParameters(definition, context, variant = 0) {
133
+ validateDynamicMechanicCatalog([definition]);
134
+ if (!Number.isSafeInteger(variant) || variant < 0) {
135
+ fail('mechanic-fallback-variant-invalid', 'A fallback variant must be a non-negative integer');
136
+ }
137
+ const intent = fallbackParameterRecord(definition.intentParameters, context, variant);
138
+ return { intent };
139
+ }
140
+ export function makeDynamicFallbackResolution(definition, context, variant = 0) {
141
+ validateDynamicMechanicCatalog([definition]);
142
+ if (!Number.isSafeInteger(variant) || variant < 0) {
143
+ fail('mechanic-fallback-variant-invalid', 'A fallback variant must be a non-negative integer');
144
+ }
145
+ return fallbackParameterRecord(definition.resolutionParameters, { ...context, actingActorId: null }, variant);
146
+ }
147
+ export function resolveDynamicActionParticipantIds(action, definition, objects, effects) {
148
+ const actorIds = new Set();
149
+ if (action.actorId !== undefined)
150
+ actorIds.add(action.actorId);
151
+ if (action.targetActorId !== undefined)
152
+ actorIds.add(action.targetActorId);
153
+ const referencedObjectIds = new Set([
154
+ ...objectReferenceValues(action.parameters.intent, definition.intentParameters),
155
+ ...objectReferenceValues(action.parameters.resolution, definition.resolutionParameters),
156
+ ]);
157
+ const actionEffectObjects = effects.flatMap(effect => (effect.actionId === action.id && effect.operation === 'object.put' ? [effect.object] : []));
158
+ for (const object of actionEffectObjects)
159
+ referencedObjectIds.add(object.id);
160
+ const objectById = new Map(objects.map(object => [object.id, object]));
161
+ for (const object of actionEffectObjects)
162
+ objectById.set(object.id, object);
163
+ for (let pass = 0; pass <= objectById.size; pass += 1) {
164
+ let changed = false;
165
+ for (const object of objectById.values()) {
166
+ const reachesAffected = object.links.some(link => (link.targetType === 'object' && referencedObjectIds.has(link.targetId)));
167
+ if (reachesAffected && !referencedObjectIds.has(object.id)) {
168
+ referencedObjectIds.add(object.id);
169
+ changed = true;
170
+ }
171
+ if (!referencedObjectIds.has(object.id))
172
+ continue;
173
+ for (const link of object.links) {
174
+ if (link.targetType === 'object' && !referencedObjectIds.has(link.targetId)) {
175
+ referencedObjectIds.add(link.targetId);
176
+ changed = true;
177
+ }
178
+ }
179
+ }
180
+ if (!changed)
181
+ break;
182
+ }
183
+ for (const objectId of referencedObjectIds) {
184
+ const object = objectById.get(objectId);
185
+ if (!object)
186
+ continue;
187
+ if (object.ownerActorId !== null)
188
+ actorIds.add(object.ownerActorId);
189
+ for (const link of object.links) {
190
+ if (link.targetType === 'actor')
191
+ actorIds.add(link.targetId);
192
+ }
193
+ }
194
+ return [...actorIds];
195
+ }
196
+ export function dynamicObjectGraph(objects) {
197
+ return objects.map(({ id, ownerActorId, links }) => ({
198
+ id, ownerActorId, links: structuredClone(links),
199
+ }));
200
+ }
201
+ export function dynamicActionObjectGraph(actionId, actions, objects, effects) {
202
+ const graph = new Map(dynamicObjectGraph(objects).map(object => [object.id, object]));
203
+ for (const action of actions) {
204
+ for (const effect of effects) {
205
+ if (effect.actionId === action.id && effect.operation === 'object.put') {
206
+ const { id, ownerActorId, links } = effect.object;
207
+ graph.set(id, { id, ownerActorId, links: structuredClone(links) });
208
+ for (const retiredId of effect.sceneRetention?.retiredIds ?? [])
209
+ graph.delete(retiredId);
210
+ }
211
+ }
212
+ if (action.id === actionId)
213
+ break;
214
+ }
215
+ return [...graph.values()];
216
+ }
217
+ function objectReferenceValues(value, definitions) {
218
+ if (value === null || typeof value !== 'object' || Array.isArray(value))
219
+ return [];
220
+ const record = value;
221
+ return definitions.flatMap((definition) => {
222
+ if (definition.kind === 'object-reference') {
223
+ const objectId = record[definition.id];
224
+ return typeof objectId === 'string' ? [objectId] : [];
225
+ }
226
+ if (definition.kind === 'object-reference-list') {
227
+ const objectIds = record[definition.id];
228
+ return Array.isArray(objectIds)
229
+ ? objectIds.filter((item) => typeof item === 'string')
230
+ : [];
231
+ }
232
+ return [];
233
+ });
234
+ }
235
+ function validateScalarBindings(definitions) {
236
+ for (const [index, parameter] of definitions.entries()) {
237
+ if (parameter.valueFrom === undefined)
238
+ continue;
239
+ const binding = parameter.valueFrom;
240
+ if (!['text', 'integer', 'number', 'boolean', 'enum'].includes(parameter.kind)
241
+ || binding === null || typeof binding !== 'object' || Array.isArray(binding)
242
+ || Object.keys(binding).sort().join(',') !== 'objectParameter,path'
243
+ || typeof binding.objectParameter !== 'string' || !Array.isArray(binding.path)
244
+ || binding.path.length === 0 || binding.path.length > 4
245
+ || binding.path.some(key => typeof key !== 'string' || !/^[A-Za-z][A-Za-z0-9_-]{0,63}$/.test(key)
246
+ || ['constructor', 'prototype', '__proto__'].includes(key))) {
247
+ fail('mechanic-catalog-invalid', `Scalar parameter ${parameter.id} has an invalid value binding`);
248
+ }
249
+ const source = definitions.slice(0, index).find(candidate => candidate.id === binding.objectParameter);
250
+ if (source?.kind !== 'object-reference' || source.required === false) {
251
+ fail('mechanic-catalog-invalid', `Scalar parameter ${parameter.id} needs a preceding required object reference`);
252
+ }
253
+ }
254
+ }
255
+ function scalarBindingValue(parameter, record, definitions, context) {
256
+ const binding = parameter.valueFrom;
257
+ const source = definitions.find(candidate => candidate.id === binding.objectParameter);
258
+ if (source.kind !== 'object-reference')
259
+ fail('mechanic-catalog-invalid', 'Scalar source must be an object reference');
260
+ const object = compatibleObjects(source, context).find(candidate => candidate.id === record[source.id]);
261
+ if (!object)
262
+ fail('mechanic-reference-invalid', `${source.label} must reference a visible compatible object`);
263
+ let value = object;
264
+ for (const key of binding.path) {
265
+ if (value === null || typeof value !== 'object' || Array.isArray(value) || !Object.hasOwn(value, key)) {
266
+ fail('mechanic-value-binding-invalid', `${parameter.label} has no current bound value`);
267
+ }
268
+ value = value[key];
269
+ }
270
+ try {
271
+ validateParameterValue(value, parameter, context);
272
+ }
273
+ catch (error) {
274
+ if (!(error instanceof DynamicMechanicContractError))
275
+ throw error;
276
+ fail('mechanic-value-binding-invalid', `${parameter.label} has an invalid current bound value`);
277
+ }
278
+ return value;
279
+ }
280
+ function validateParameterDefinition(parameter, mechanicId) {
281
+ assertIdentifier(parameter.id, `parameter identifier for ${mechanicId}`);
282
+ assertText(parameter.label, `parameter label for ${mechanicId}`, 120);
283
+ switch (parameter.kind) {
284
+ case 'text': {
285
+ const minimum = parameter.minimumLength ?? 1;
286
+ if (!Number.isSafeInteger(minimum)
287
+ || !Number.isSafeInteger(parameter.maximumLength)
288
+ || minimum < 0
289
+ || parameter.maximumLength < Math.max(1, minimum)
290
+ || parameter.maximumLength > 2_000) {
291
+ fail('mechanic-catalog-invalid', `Text parameter ${parameter.id} has invalid length bounds`);
292
+ }
293
+ return;
294
+ }
295
+ case 'number':
296
+ case 'integer':
297
+ if (!Number.isFinite(parameter.minimum)
298
+ || !Number.isFinite(parameter.maximum)
299
+ || parameter.minimum > parameter.maximum
300
+ || (parameter.kind === 'integer'
301
+ && (!Number.isSafeInteger(parameter.minimum) || !Number.isSafeInteger(parameter.maximum)))) {
302
+ fail('mechanic-catalog-invalid', `Numeric parameter ${parameter.id} has invalid bounds`);
303
+ }
304
+ return;
305
+ case 'boolean':
306
+ return;
307
+ case 'enum':
308
+ if (!Array.isArray(parameter.values)
309
+ || parameter.values.length === 0
310
+ || parameter.values.length > 32
311
+ || parameter.values.some(value => typeof value !== 'string' || value.trim() === '' || value.length > 100)) {
312
+ fail('mechanic-catalog-invalid', `Enum parameter ${parameter.id} has invalid choices`);
313
+ }
314
+ assertUnique(parameter.values, `choices for ${parameter.id}`);
315
+ return;
316
+ case 'actor-reference':
317
+ return;
318
+ case 'resource-reference':
319
+ if (!Array.isArray(parameter.resourceIds)
320
+ || parameter.resourceIds.length === 0
321
+ || parameter.resourceIds.length > 16) {
322
+ fail('mechanic-catalog-invalid', `Resource parameter ${parameter.id} needs bounded resources`);
323
+ }
324
+ for (const resourceId of parameter.resourceIds) {
325
+ assertIdentifier(resourceId, `resource for ${parameter.id}`);
326
+ }
327
+ assertUnique(parameter.resourceIds, `resources for ${parameter.id}`);
328
+ return;
329
+ case 'object-reference':
330
+ case 'object-reference-list':
331
+ if (!Array.isArray(parameter.objectKinds)
332
+ || parameter.objectKinds.length === 0
333
+ || parameter.objectKinds.length > 16) {
334
+ fail('mechanic-catalog-invalid', `Object parameter ${parameter.id} needs bounded kinds`);
335
+ }
336
+ for (const kind of parameter.objectKinds)
337
+ assertIdentifier(kind, `object kind for ${parameter.id}`);
338
+ assertUnique(parameter.objectKinds, `object kinds for ${parameter.id}`);
339
+ if (parameter.ownedByActor !== undefined && typeof parameter.ownedByActor !== 'boolean') {
340
+ fail('mechanic-catalog-invalid', `Object parameter ${parameter.id} has an invalid ownership rule`);
341
+ }
342
+ if (parameter.statuses !== undefined) {
343
+ if (!Array.isArray(parameter.statuses) || parameter.statuses.length === 0 || parameter.statuses.length > 16) {
344
+ fail('mechanic-catalog-invalid', `Object parameter ${parameter.id} has invalid statuses`);
345
+ }
346
+ for (const status of parameter.statuses)
347
+ assertIdentifier(status, `object status for ${parameter.id}`);
348
+ assertUnique(parameter.statuses, `object statuses for ${parameter.id}`);
349
+ }
350
+ if (parameter.actorLinks !== undefined) {
351
+ const links = parameter.actorLinks;
352
+ if (links === null || typeof links !== 'object' || Array.isArray(links)
353
+ || Object.keys(links).length === 0 || Object.keys(links).some(key => key !== 'actor' && key !== 'target')) {
354
+ fail('mechanic-catalog-invalid', `Object parameter ${parameter.id} needs valid actor links`);
355
+ }
356
+ for (const relation of Object.values(links))
357
+ assertIdentifier(relation, `actor link for ${parameter.id}`);
358
+ }
359
+ if (parameter.actorLinkExceptions !== undefined) {
360
+ const exceptions = parameter.actorLinkExceptions;
361
+ if (parameter.actorLinks?.actor === undefined || !Array.isArray(exceptions)
362
+ || exceptions.length === 0 || exceptions.length > 8) {
363
+ fail('mechanic-catalog-invalid', `Object parameter ${parameter.id} needs bounded actor-link exceptions`);
364
+ }
365
+ for (const actorId of exceptions)
366
+ assertIdentifier(actorId, `actor-link exception for ${parameter.id}`);
367
+ assertUnique(exceptions, `actor-link exceptions for ${parameter.id}`);
368
+ }
369
+ if (parameter.requiredNumericData !== undefined) {
370
+ const constraints = parameter.requiredNumericData;
371
+ if (constraints === null || typeof constraints !== 'object' || Array.isArray(constraints)
372
+ || Object.keys(constraints).length === 0 || Object.keys(constraints).length > 8) {
373
+ fail('mechanic-catalog-invalid', `Object parameter ${parameter.id} needs bounded numeric filters`);
374
+ }
375
+ for (const [key, bounds] of Object.entries(constraints)) {
376
+ assertIdentifier(key, `numeric data key for ${parameter.id}`);
377
+ if (bounds === null || typeof bounds !== 'object' || Array.isArray(bounds)
378
+ || (bounds.minimum === undefined && bounds.maximumExclusive === undefined)
379
+ || Object.keys(bounds).some(name => name !== 'minimum' && name !== 'maximumExclusive')
380
+ || (bounds.minimum !== undefined && !Number.isFinite(bounds.minimum))
381
+ || (bounds.maximumExclusive !== undefined && !Number.isFinite(bounds.maximumExclusive))
382
+ || (bounds.minimum !== undefined && bounds.maximumExclusive !== undefined && bounds.minimum >= bounds.maximumExclusive)) {
383
+ fail('mechanic-catalog-invalid', `Object parameter ${parameter.id} has invalid numeric bounds`);
384
+ }
385
+ }
386
+ }
387
+ if (parameter.requiredData !== undefined) {
388
+ const data = parameter.requiredData;
389
+ if (data === null || typeof data !== 'object' || Array.isArray(data)
390
+ || Object.keys(data).length === 0 || Object.keys(data).length > 8) {
391
+ fail('mechanic-catalog-invalid', `Object parameter ${parameter.id} needs bounded data filters`);
392
+ }
393
+ for (const [key, value] of Object.entries(data)) {
394
+ assertIdentifier(key, `object data key for ${parameter.id}`);
395
+ if (!(typeof value === 'boolean'
396
+ || (typeof value === 'number' && Number.isFinite(value))
397
+ || (typeof value === 'string' && value.length <= 240))) {
398
+ fail('mechanic-catalog-invalid', `Object parameter ${parameter.id} has an invalid data filter`);
399
+ }
400
+ }
401
+ }
402
+ if (parameter.kind === 'object-reference-list'
403
+ && (!Number.isSafeInteger(parameter.minimumItems)
404
+ || !Number.isSafeInteger(parameter.maximumItems)
405
+ || parameter.minimumItems < 1
406
+ || parameter.maximumItems < parameter.minimumItems
407
+ || parameter.maximumItems > 16)) {
408
+ fail('mechanic-catalog-invalid', `Object list parameter ${parameter.id} has invalid item bounds`);
409
+ }
410
+ return;
411
+ }
412
+ }
413
+ function validateActors(action, definition, context) {
414
+ if (definition.actor === 'required' && action.actorId === undefined) {
415
+ fail('mechanic-actor-invalid', `Mechanic ${definition.id} needs an actor`);
416
+ }
417
+ if (definition.actor === 'game-master' && action.actorId !== undefined) {
418
+ fail('mechanic-actor-invalid', `Mechanic ${definition.id} is Game Master only`);
419
+ }
420
+ if (action.actorId !== undefined && !context.actorIds.includes(action.actorId)) {
421
+ fail('mechanic-actor-invalid', `Actor ${action.actorId} is unknown`);
422
+ }
423
+ if (context.actingActorId !== null
424
+ && action.actorId !== undefined
425
+ && context.actingActorId !== action.actorId) {
426
+ fail('mechanic-actor-invalid', 'The acting character cannot author another actor action');
427
+ }
428
+ if (definition.target === 'required' && action.targetActorId === undefined) {
429
+ fail('mechanic-target-invalid', `Mechanic ${definition.id} needs a target actor`);
430
+ }
431
+ if (definition.target === 'none' && action.targetActorId !== undefined) {
432
+ fail('mechanic-target-invalid', `Mechanic ${definition.id} cannot target an actor`);
433
+ }
434
+ if (action.targetActorId !== undefined && !context.actorIds.includes(action.targetActorId)) {
435
+ fail('mechanic-target-invalid', `Target ${action.targetActorId} is unknown`);
436
+ }
437
+ if (action.actorId !== undefined && action.actorId === action.targetActorId) {
438
+ fail('mechanic-target-invalid', 'An actor cannot target itself');
439
+ }
440
+ }
441
+ function validateParameterRecord(record, definitions, context) {
442
+ const allowed = definitions.map(definition => definition.id);
443
+ const required = definitions
444
+ .filter(definition => definition.required !== false)
445
+ .map(definition => definition.id);
446
+ assertExactKeys(record, allowed, required, 'mechanic parameters');
447
+ for (const definition of definitions) {
448
+ const value = record[definition.id];
449
+ if (value === undefined && definition.required === false)
450
+ continue;
451
+ validateParameterValue(value, definition, context);
452
+ if (definition.valueFrom !== undefined && value !== scalarBindingValue(definition, record, definitions, context)) {
453
+ fail('mechanic-value-binding-invalid', `${definition.label} differs from the selected object's current value`);
454
+ }
455
+ }
456
+ const relation = referencePairDefinition(definitions);
457
+ if (relation !== null && !compatibleReferencePairs(relation, context).some(pair => (record[relation.peer.id] === pair.peerId && record[relation.parameter.id] === pair.parameterId))) {
458
+ fail('mechanic-reference-invalid', `${relation.parameter.label} must match the selected ${relation.peer.label}`);
459
+ }
460
+ }
461
+ function validateParameterValue(value, definition, context) {
462
+ switch (definition.kind) {
463
+ case 'text': {
464
+ const minimum = definition.minimumLength ?? 1;
465
+ if (typeof value !== 'string' || value.length < minimum || value.length > definition.maximumLength) {
466
+ fail('mechanic-parameter-invalid', `${definition.label} has invalid text`);
467
+ }
468
+ return;
469
+ }
470
+ case 'number':
471
+ case 'integer':
472
+ if (typeof value !== 'number'
473
+ || !Number.isFinite(value)
474
+ || (definition.kind === 'integer' && !Number.isSafeInteger(value))
475
+ || value < definition.minimum
476
+ || value > definition.maximum) {
477
+ fail('mechanic-parameter-invalid', `${definition.label} is outside its bounds`);
478
+ }
479
+ return;
480
+ case 'boolean':
481
+ if (typeof value !== 'boolean')
482
+ fail('mechanic-parameter-invalid', `${definition.label} must be true or false`);
483
+ return;
484
+ case 'enum':
485
+ if (typeof value !== 'string' || !definition.values.includes(value)) {
486
+ fail('mechanic-parameter-invalid', `${definition.label} is not an allowed choice`);
487
+ }
488
+ return;
489
+ case 'actor-reference':
490
+ if (typeof value !== 'string'
491
+ || !context.actorIds.includes(value)
492
+ || (definition.allowSelf !== true && value === context.actingActorId)) {
493
+ fail('mechanic-reference-invalid', `${definition.label} must reference an allowed actor`);
494
+ }
495
+ return;
496
+ case 'resource-reference':
497
+ if (typeof value !== 'string'
498
+ || !definition.resourceIds.includes(value)
499
+ || !context.resourceIds.includes(value)) {
500
+ fail('mechanic-reference-invalid', `${definition.label} must reference an allowed resource`);
501
+ }
502
+ return;
503
+ case 'object-reference': {
504
+ if (typeof value !== 'string') {
505
+ fail('mechanic-reference-invalid', `${definition.label} must reference an object`);
506
+ }
507
+ const object = compatibleObjects(definition, context).find(candidate => candidate.id === value);
508
+ if (!object) {
509
+ fail('mechanic-reference-invalid', `${definition.label} must reference a visible compatible object`);
510
+ }
511
+ return;
512
+ }
513
+ case 'object-reference-list': {
514
+ if (!Array.isArray(value)
515
+ || value.length < definition.minimumItems
516
+ || value.length > definition.maximumItems
517
+ || value.some(candidate => typeof candidate !== 'string')
518
+ || new Set(value).size !== value.length) {
519
+ fail('mechanic-reference-invalid', `${definition.label} must contain unique object references`);
520
+ }
521
+ for (const objectId of value) {
522
+ const object = compatibleObjects(definition, context).find(candidate => candidate.id === objectId);
523
+ if (!object) {
524
+ fail('mechanic-reference-invalid', `${definition.label} must reference visible compatible objects`);
525
+ }
526
+ }
527
+ return;
528
+ }
529
+ }
530
+ }
531
+ function parameterRecordSchema(definitions, context) {
532
+ const bindings = definitions.filter(parameter => parameter.valueFrom !== undefined);
533
+ if (bindings.length > 0) {
534
+ const unbound = definitions.map(({ valueFrom: _binding, ...parameter }) => parameter);
535
+ const base = parameterRecordSchema(unbound, context);
536
+ let branches = (base.anyOf ?? [base]);
537
+ for (const sourceId of new Set(bindings.map(parameter => parameter.valueFrom.objectParameter))) {
538
+ const source = definitions.find(parameter => parameter.id === sourceId);
539
+ if (source.kind !== 'object-reference')
540
+ fail('mechanic-catalog-invalid', 'Scalar source must be an object reference');
541
+ const objects = compatibleObjects(source, context);
542
+ if (branches.length * objects.length > 4096)
543
+ fail('mechanic-catalog-invalid', 'Scalar binding schema exceeds its branch bound');
544
+ branches = branches.flatMap(branch => objects.flatMap(object => {
545
+ const offered = branch.properties[sourceId].enum;
546
+ if (!offered.includes(object.id))
547
+ return [];
548
+ const properties = { ...branch.properties, [sourceId]: { enum: [object.id] } };
549
+ for (const parameter of bindings.filter(item => item.valueFrom.objectParameter === sourceId)) {
550
+ try {
551
+ properties[parameter.id] = { const: scalarBindingValue(parameter, { [sourceId]: object.id }, definitions, context) };
552
+ }
553
+ catch (error) {
554
+ if (!(error instanceof DynamicMechanicContractError) || error.code !== 'mechanic-value-binding-invalid')
555
+ throw error;
556
+ if (parameter.required !== false)
557
+ return [];
558
+ delete properties[parameter.id];
559
+ }
560
+ }
561
+ return [{ ...branch, properties }];
562
+ }));
563
+ }
564
+ return { anyOf: branches };
565
+ }
566
+ const relation = referencePairDefinition(definitions);
567
+ if (relation !== null) {
568
+ const choices = new Map();
569
+ for (const pair of compatibleReferencePairs(relation, context)) {
570
+ const values = choices.get(pair.peerId) ?? [];
571
+ values.push(pair.parameterId);
572
+ choices.set(pair.peerId, values);
573
+ }
574
+ return {
575
+ anyOf: [...choices].map(([peerId, parameterIds]) => strictObjectSchema(definitions.filter(definition => definition.required !== false).map(definition => definition.id), Object.fromEntries(definitions.map(definition => [definition.id,
576
+ definition.id === relation.peer.id ? { enum: [peerId] }
577
+ : definition.id === relation.parameter.id ? { enum: parameterIds }
578
+ : parameterSchema(definition, context),
579
+ ])))),
580
+ };
581
+ }
582
+ return strictObjectSchema(definitions
583
+ .filter(definition => definition.required !== false)
584
+ .map(definition => definition.id), Object.fromEntries(definitions.map(definition => [
585
+ definition.id,
586
+ parameterSchema(definition, context),
587
+ ])));
588
+ }
589
+ function parameterSchema(definition, context) {
590
+ switch (definition.kind) {
591
+ case 'text':
592
+ return {
593
+ type: 'string',
594
+ minLength: definition.minimumLength ?? 1,
595
+ maxLength: definition.maximumLength,
596
+ };
597
+ case 'number':
598
+ case 'integer':
599
+ return {
600
+ type: definition.kind,
601
+ minimum: definition.minimum,
602
+ maximum: definition.maximum,
603
+ };
604
+ case 'boolean':
605
+ return { type: 'boolean' };
606
+ case 'enum':
607
+ return { enum: [...definition.values] };
608
+ case 'actor-reference':
609
+ return {
610
+ enum: context.actorIds.filter(actorId => (definition.allowSelf === true || actorId !== context.actingActorId)),
611
+ };
612
+ case 'resource-reference':
613
+ return { enum: definition.resourceIds.filter(resourceId => context.resourceIds.includes(resourceId)) };
614
+ case 'object-reference':
615
+ return {
616
+ enum: compatibleObjects(definition, context).map(object => object.id),
617
+ };
618
+ case 'object-reference-list':
619
+ return {
620
+ type: 'array',
621
+ minItems: definition.minimumItems,
622
+ maxItems: definition.maximumItems,
623
+ uniqueItems: true,
624
+ items: {
625
+ enum: compatibleObjects(definition, context).map(object => object.id),
626
+ },
627
+ };
628
+ }
629
+ }
630
+ function fallbackValue(definition, context, variant) {
631
+ switch (definition.kind) {
632
+ case 'text': {
633
+ const minimum = Math.max(1, definition.minimumLength ?? 1);
634
+ const base = definition.label.slice(0, definition.maximumLength);
635
+ const candidate = base.length >= minimum ? base : 'x'.repeat(minimum);
636
+ if (variant === 0)
637
+ return candidate;
638
+ const width = Math.max(minimum, candidate.length);
639
+ const stem = candidate.padEnd(width, 'x').slice(0, width);
640
+ const marker = String.fromCharCode(97 + ((variant - 1) % 26));
641
+ const alternative = `${stem.slice(0, -1)}${marker}`;
642
+ if (alternative !== candidate)
643
+ return alternative;
644
+ return `${stem.slice(0, -1)}${marker === 'z' ? 'a' : String.fromCharCode(marker.charCodeAt(0) + 1)}`;
645
+ }
646
+ case 'number':
647
+ return variant === 0 || definition.minimum === definition.maximum
648
+ ? definition.minimum
649
+ : definition.maximum;
650
+ case 'integer': {
651
+ const bounded = (value) => Math.min(definition.maximum, Math.max(definition.minimum, value));
652
+ const candidates = [
653
+ definition.minimum,
654
+ definition.maximum,
655
+ bounded(0),
656
+ bounded(1),
657
+ bounded(-1),
658
+ Math.floor((definition.minimum + definition.maximum) / 2),
659
+ Math.ceil((definition.minimum + definition.maximum) / 2),
660
+ ];
661
+ const candidate = candidates[variant % candidates.length];
662
+ if (candidate === undefined)
663
+ fail('mechanic-fallback-unavailable', `${definition.label} has no fallback number`);
664
+ return candidate;
665
+ }
666
+ case 'boolean':
667
+ return variant % 2 === 1;
668
+ case 'enum': {
669
+ const value = definition.values[variant % definition.values.length];
670
+ if (value === undefined)
671
+ fail('mechanic-fallback-unavailable', `${definition.label} has no fallback choice`);
672
+ return value;
673
+ }
674
+ case 'actor-reference': {
675
+ const candidates = context.actorIds.filter(actorId => (definition.allowSelf === true || actorId !== context.actingActorId));
676
+ const value = candidates[variant % candidates.length];
677
+ if (value === undefined)
678
+ fail('mechanic-fallback-unavailable', `${definition.label} has no visible actor`);
679
+ return value;
680
+ }
681
+ case 'resource-reference': {
682
+ const candidates = definition.resourceIds.filter(resourceId => context.resourceIds.includes(resourceId));
683
+ const value = candidates[variant % candidates.length];
684
+ if (value === undefined)
685
+ fail('mechanic-fallback-unavailable', `${definition.label} has no resource`);
686
+ return value;
687
+ }
688
+ case 'object-reference': {
689
+ const objects = compatibleObjects(definition, context);
690
+ const value = objects[variant % objects.length]?.id;
691
+ if (value === undefined)
692
+ fail('mechanic-fallback-unavailable', `${definition.label} has no visible object`);
693
+ return value;
694
+ }
695
+ case 'object-reference-list': {
696
+ const objects = compatibleObjects(definition, context);
697
+ const offset = objects.length === 0 ? 0 : variant % objects.length;
698
+ const values = [...objects.slice(offset), ...objects.slice(0, offset)]
699
+ .slice(0, definition.minimumItems)
700
+ .map(object => object.id);
701
+ if (values.length < definition.minimumItems) {
702
+ fail('mechanic-fallback-unavailable', `${definition.label} has too few visible objects`);
703
+ }
704
+ return values;
705
+ }
706
+ }
707
+ }
708
+ function fallbackParameterRecord(definitions, context, variant) {
709
+ const relation = referencePairDefinition(definitions);
710
+ const pairs = relation === null ? null : compatibleReferencePairs(relation, context);
711
+ if (pairs !== null && pairs.length === 0) {
712
+ fail('mechanic-fallback-unavailable', 'The mechanic has no compatible reference pair');
713
+ }
714
+ const selected = pairs === null ? null : pairs[variant % pairs.length];
715
+ let stride = pairs?.length ?? 1;
716
+ const entries = definitions
717
+ .filter(definition => definition.required !== false)
718
+ .map((definition) => {
719
+ if (relation !== null && selected !== null) {
720
+ if (definition.id === relation.peer.id)
721
+ return [definition.id, selected.peerId];
722
+ if (definition.id === relation.parameter.id)
723
+ return [definition.id, selected.parameterId];
724
+ }
725
+ if (definition.valueFrom !== undefined)
726
+ return [definition.id, null];
727
+ const parameterVariant = Math.floor(variant / stride);
728
+ const entry = [
729
+ definition.id,
730
+ fallbackValue(definition, context, parameterVariant),
731
+ ];
732
+ stride = Math.min(Number.MAX_SAFE_INTEGER, stride * Math.max(1, fallbackVariantCount(definition, context)));
733
+ return entry;
734
+ });
735
+ const record = Object.fromEntries(entries);
736
+ for (const definition of definitions) {
737
+ if (definition.valueFrom !== undefined && definition.required !== false) {
738
+ record[definition.id] = scalarBindingValue(definition, record, definitions, context);
739
+ }
740
+ }
741
+ return record;
742
+ }
743
+ function referencePairDefinition(definitions) {
744
+ const linked = definitions.filter((parameter) => (parameter.kind === 'object-reference' && (parameter.dataMatch !== undefined || parameter.capacityMatch !== undefined || parameter.linkMatch !== undefined)));
745
+ if (linked.length === 0)
746
+ return null;
747
+ if (linked.length > 1) {
748
+ fail('mechanic-catalog-invalid', 'A parameter record supports one reference pair');
749
+ }
750
+ const parameter = linked[0];
751
+ const capacity = parameter.capacityMatch;
752
+ const link = parameter.linkMatch;
753
+ const match = capacity ?? link ?? parameter.dataMatch;
754
+ const keys = link !== undefined ? ['parameterId', 'relation'] : capacity === undefined ? ['parameterId', 'key', 'otherKey']
755
+ : ['parameterId', 'amountKey', 'capacityKey', 'usedKey', 'excludePeerReferenceKey'];
756
+ const required = capacity === undefined ? keys : keys.slice(0, 4);
757
+ if (match === null || typeof match !== 'object' || Array.isArray(match)
758
+ || [capacity, link, parameter.dataMatch].filter(value => value !== undefined).length !== 1
759
+ || required.some(key => !Object.hasOwn(match, key))
760
+ || Object.keys(match).some(key => !keys.includes(key))) {
761
+ fail('mechanic-catalog-invalid', 'A reference pair needs one complete supported constraint');
762
+ }
763
+ for (const value of Object.values(match))
764
+ assertIdentifier(value, 'reference pair field');
765
+ const peer = definitions.find(candidate => candidate.id === match.parameterId);
766
+ if (peer === undefined || peer.kind !== 'object-reference' || peer.id === parameter.id
767
+ || peer.required === false || parameter.required === false) {
768
+ fail('mechanic-catalog-invalid', 'A reference pair needs two distinct required object parameters');
769
+ }
770
+ if (link !== undefined) {
771
+ return { parameter, peer, matches: (candidate, other) => {
772
+ const links = other.links.filter(edge => edge.relation === link.relation);
773
+ return links.length === 1 && links[0].targetType === 'object' && links[0].targetId === candidate.id;
774
+ } };
775
+ }
776
+ if (capacity !== undefined) {
777
+ return { parameter, peer, matches: (candidate, other) => {
778
+ const amount = other.data[capacity.amountKey];
779
+ const maximum = candidate.data[capacity.capacityKey];
780
+ const used = candidate.data[capacity.usedKey];
781
+ if (typeof amount !== 'number' || !Number.isFinite(amount) || amount < 0
782
+ || typeof maximum !== 'number' || !Number.isFinite(maximum) || maximum < 0
783
+ || typeof used !== 'number' || !Number.isFinite(used) || used < 0 || used > maximum)
784
+ return false;
785
+ if (capacity.excludePeerReferenceKey !== undefined) {
786
+ const sourceId = other.data[capacity.excludePeerReferenceKey];
787
+ if (typeof sourceId !== 'string' || sourceId.length === 0 || sourceId === candidate.id)
788
+ return false;
789
+ }
790
+ return amount <= maximum - used;
791
+ } };
792
+ }
793
+ const equality = parameter.dataMatch;
794
+ return { parameter, peer, matches: (candidate, other) => {
795
+ const value = other.data[equality.otherKey];
796
+ return (typeof value === 'string' || typeof value === 'boolean'
797
+ || (typeof value === 'number' && Number.isFinite(value))) && candidate.data[equality.key] === value;
798
+ } };
799
+ }
800
+ function compatibleReferencePairs(relation, context) {
801
+ const candidates = compatibleObjects(relation.parameter, context);
802
+ return compatibleObjects(relation.peer, context).flatMap(peer => (candidates.filter(candidate => relation.matches(candidate, peer))
803
+ .map(candidate => ({ peerId: peer.id, parameterId: candidate.id }))));
804
+ }
805
+ function fallbackVariantCount(definition, context) {
806
+ switch (definition.kind) {
807
+ case 'text':
808
+ return 27;
809
+ case 'number':
810
+ return definition.minimum === definition.maximum ? 1 : 2;
811
+ case 'integer':
812
+ return 7;
813
+ case 'boolean':
814
+ return 2;
815
+ case 'enum':
816
+ return definition.values.length;
817
+ case 'actor-reference':
818
+ return context.actorIds.filter(actorId => (definition.allowSelf === true || actorId !== context.actingActorId)).length;
819
+ case 'resource-reference':
820
+ return definition.resourceIds.filter(resourceId => context.resourceIds.includes(resourceId)).length;
821
+ case 'object-reference':
822
+ case 'object-reference-list':
823
+ return compatibleObjects(definition, context).length;
824
+ }
825
+ }
826
+ function compatibleObjects(definition, context) {
827
+ return context.objects.filter(object => (definition.objectKinds.includes(object.kind)
828
+ && (definition.ownedByActor !== true || (context.actingActorId !== null && object.ownerActorId === context.actingActorId))
829
+ && (definition.statuses === undefined || definition.statuses.includes(object.status))
830
+ && (definition.requiredData === undefined
831
+ || Object.entries(definition.requiredData).every(([key, value]) => object.data[key] === value))
832
+ && (definition.actorLinks === undefined || Object.entries(definition.actorLinks).every(([role, relation]) => {
833
+ const links = object.links.filter(link => link.targetType === 'actor' && link.relation === relation);
834
+ if (links.length !== 1)
835
+ return false;
836
+ const linked = links[0].targetId;
837
+ if (role === 'actor')
838
+ return linked === context.actingActorId
839
+ || (context.actingActorId !== null && context.actorIds.includes(context.actingActorId)
840
+ && definition.actorLinkExceptions?.includes(context.actingActorId) === true);
841
+ return context.targetActorId === undefined
842
+ ? context.actorIds.includes(linked) && linked !== context.actingActorId
843
+ : linked === context.targetActorId;
844
+ }))
845
+ && (definition.requiredNumericData === undefined || Object.entries(definition.requiredNumericData).every(([key, bounds]) => {
846
+ const value = object.data[key];
847
+ return typeof value === 'number' && Number.isFinite(value)
848
+ && (bounds.minimum === undefined || value >= bounds.minimum)
849
+ && (bounds.maximumExclusive === undefined || value < bounds.maximumExclusive);
850
+ }))
851
+ && isObjectVisibleToActor(object, context.actingActorId))).map((object, index) => ({ object, index })).sort((left, right) => {
852
+ if (definition.statuses === undefined)
853
+ return left.index - right.index;
854
+ const statusOrder = definition.statuses.indexOf(left.object.status)
855
+ - definition.statuses.indexOf(right.object.status);
856
+ return statusOrder === 0 ? left.index - right.index : statusOrder;
857
+ }).map(item => item.object);
858
+ }
859
+ function isObjectVisibleToActor(object, actorId) {
860
+ if (actorId === null || object.visibility.scope === 'world')
861
+ return true;
862
+ if (object.visibility.scope === 'shared')
863
+ return object.visibility.actorIds.includes(actorId);
864
+ return object.ownerActorId === actorId;
865
+ }
866
+ function strictObjectSchema(required, properties) {
867
+ return {
868
+ type: 'object',
869
+ additionalProperties: false,
870
+ required: [...required],
871
+ properties: structuredClone(properties),
872
+ };
873
+ }
874
+ function assertRecord(value, label) {
875
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
876
+ fail('mechanic-parameter-invalid', `${label} must be an object`);
877
+ }
878
+ return value;
879
+ }
880
+ function assertExactKeys(value, allowed, required, label) {
881
+ const keys = Object.keys(value);
882
+ if (keys.some(key => !allowed.includes(key))) {
883
+ fail('mechanic-parameter-invalid', `${label} contains an unknown field`);
884
+ }
885
+ if (required.some(key => !Object.prototype.hasOwnProperty.call(value, key))) {
886
+ fail('mechanic-parameter-invalid', `${label} is missing a required field`);
887
+ }
888
+ }
889
+ function assertIdentifier(value, label) {
890
+ if (typeof value !== 'string'
891
+ || value.trim() !== value
892
+ || value.length === 0
893
+ || value.length > 128
894
+ || !/^[a-zA-Z][a-zA-Z0-9-]*$/.test(value)) {
895
+ fail('mechanic-catalog-invalid', `${label} is invalid`);
896
+ }
897
+ }
898
+ function assertText(value, label, maximum) {
899
+ if (typeof value !== 'string' || value.trim() === '' || value.length > maximum) {
900
+ fail('mechanic-catalog-invalid', `${label} must contain bounded text`);
901
+ }
902
+ }
903
+ function assertUnique(values, label) {
904
+ if (new Set(values).size !== values.length) {
905
+ fail('mechanic-catalog-invalid', `${label} must be unique`);
906
+ }
907
+ }
908
+ function fail(code, message) {
909
+ throw new DynamicMechanicContractError(code, message);
910
+ }