@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,576 @@
1
+ // The model boundary. The app supplies a transport; the engine supplies prompts and
2
+ // schemas, then validates every answer before it can touch the world.
3
+ import { LIVING_ENGINE_VERSION, MAX_ADDED_LINE, MAX_ROLE, MAX_SPOKEN } from './types.js';
4
+ import { neverHeld } from './shared-kinds.js';
5
+ export const LIVING_INFERENCE_LIMITS = Object.freeze({
6
+ attempt: { maxTokens: 1200, timeoutMs: 60_000 },
7
+ world: { maxTokens: 1200, timeoutMs: 60_000 },
8
+ 'speech-impact': { maxTokens: 200, timeoutMs: 20_000 },
9
+ reaction: { maxTokens: 500, timeoutMs: 30_000 },
10
+ reply: { maxTokens: 500, timeoutMs: 30_000 },
11
+ plan: { maxTokens: 500, timeoutMs: 30_000 },
12
+ 'message-reply': { maxTokens: 500, timeoutMs: 30_000 },
13
+ epilogue: { maxTokens: 900, timeoutMs: 45_000 },
14
+ define: { maxTokens: 700, timeoutMs: 45_000 },
15
+ });
16
+ // JSON schemas for structured answers. They stay small so a modest model can fill
17
+ // them, and every value they admit is re-checked against the world before commit.
18
+ const str = (maxLength) => ({ type: 'string', minLength: 1, maxLength });
19
+ const nullable = (schema) => ({ anyOf: [schema, { type: 'null' }] });
20
+ const ids = (max) => ({ type: 'array', items: str(64), maxItems: max });
21
+ export const GM_EFFECT_KINDS = ['move', 'take', 'drop', 'object.update', 'object.create', 'place.condition', 'place.create', 'person.create', 'money', 'transfer', 'relationship', 'belief', 'commitment', 'goal', 'mood', 'person.condition', 'hold', 'role', 'schedule', 'fact', 'tension.update', 'tension.create', 'incapacitate', 'message', 'entity.create', 'property.set', 'relation.set', 'request.open', 'person.leave', 'person.away', 'ballot'];
22
+ const described = (schema, description) => ({ ...schema, description });
23
+ // What each kind of typed change means. The fields block shows it beside the kind's fields.
24
+ const EFFECT_MEANINGS = {
25
+ move: 'personId goes to the neighboring placeId.',
26
+ take: 'personId picks up or is handed objectId here.',
27
+ drop: 'The holder puts objectId down at placeId.',
28
+ 'object.update': 'objectId\'s condition, holder targetId, place placeId or owner personId change; null keeps one.',
29
+ 'object.create': 'A new object exists.',
30
+ 'place.condition': 'A condition of a place changes.',
31
+ 'place.create': 'A new place placeId, with name and text, joins its connections.',
32
+ 'person.create': 'A new person personId, name and role, at placeId: anyone narrated who could be spoken to; person.away if only on a call.',
33
+ money: "personId's money changes by amount.",
34
+ transfer: 'amount passes from personId to targetId; null is outside the world.',
35
+ relationship: "A person's trust or warmth toward another changes.",
36
+ belief: 'A person now holds a claim as true.',
37
+ commitment: 'A person promises something to another.',
38
+ goal: 'A person takes up or drops an aim.',
39
+ mood: "A person's mood changes.",
40
+ 'person.condition': "A person's visible physical state changes.",
41
+ hold: 'A person is kept where they are by another.',
42
+ role: "A person's role changes.",
43
+ schedule: 'A world happening, text, comes due at placeId in minutes; targetId is what it concerns.',
44
+ fact: 'A fact about the world changes.',
45
+ 'tension.update': 'A problem changes status.',
46
+ 'tension.create': 'A new problem opens.',
47
+ incapacitate: 'personId can no longer act, for the reason in text; a typed condition must now stop them.',
48
+ message: 'A written message reaches another person.',
49
+ 'entity.create': 'A new thing entityId of kindId, named name, at placeId or no place (an agreement, debt, right or rumor); initialProperties holds its required values.',
50
+ 'property.set': 'propertyId of entityId becomes value; text replaces it whole, null erases it; a time counts minutes as clockMinutes does.',
51
+ 'relation.set': 'relationId of entityId links to targetId; null unlinks.',
52
+ 'request.open': 'The actor personId asks targetId here to do text; priorId names a known request this repeats.',
53
+ 'person.leave': 'personId leaves this world for good: quit, moved or died; text says why.',
54
+ 'person.away': 'personId is away for minutes: home, asleep or an errand; text says where.',
55
+ ballot: 'The actor\'s own vote.',
56
+ };
57
+ // A world begun on engines 42 to 44 adds each write to a paper as a line of its own.
58
+ const ADDED_LINE_MEANING = 'propertyId of entityId becomes value; text adds a line, null erases it; a time counts minutes as clockMinutes does.';
59
+ const effectFields = {
60
+ personId: described(nullable(str(64)), 'Person whose state changes.'),
61
+ targetId: described(nullable(str(64)), 'Other person or entity id; null when none.'),
62
+ sourcePersonId: described(nullable(str(64)), 'Person who supplied the credited account; null for the sender’s own account.'),
63
+ placeId: described(nullable(str(64)), 'Place where this change occurs; null when it has no place.'),
64
+ objectId: described(nullable(str(64)), 'Existing object id; a written thing or token here counts as one.'),
65
+ tensionId: described(nullable(str(64)), 'Existing or new problem id.'),
66
+ name: described(nullable(str(120)), 'Name or stable aspect id for this change.'),
67
+ text: described(nullable(str(600)), 'Current value or short description; null to clear it.'),
68
+ condition: described(nullable(str(200)), 'Object condition; null when unchanged.'),
69
+ // A newcomer's role is offered only as long as the world accepts.
70
+ role: described(nullable(str(MAX_ROLE)), 'Their job or role in a few words, as anyone could tell, such as "site visitor"; never how they stand.'),
71
+ amount: described(nullable({ type: 'integer', minimum: -1_000_000_000, maximum: 1_000_000_000 }), 'Signed change in money.'),
72
+ trust: described(nullable({ type: 'integer', minimum: -40, maximum: 40 }), 'Change in trust.'),
73
+ warmth: described(nullable({ type: 'integer', minimum: -40, maximum: 40 }), 'Change in warmth.'),
74
+ minutes: described(nullable({ type: 'integer', minimum: 0, maximum: 100_000 }), 'Minutes until due or spent.'),
75
+ connections: described(nullable(ids(4)), 'Place ids connected to a new place.'),
76
+ participantIds: described(nullable(ids(6)), 'People involved in a problem.'),
77
+ status: described(nullable({ type: 'string', enum: ['open', 'settled'] }), 'Current problem status.'),
78
+ entityId: described(nullable(str(64)), 'Id of a typed entity.'),
79
+ kindId: described(nullable(str(64)), 'Kind id from the local kind definitions.'),
80
+ propertyId: described(nullable(str(64)), 'Property id defined by the entity kind.'),
81
+ relationId: described(nullable(str(64)), 'Relation id defined by the entity kind.'),
82
+ roleId: described(nullable(str(64)), 'Typed role id granted to this person; null removes an earlier role.'),
83
+ priorId: described(nullable(str(64)), 'Known request id when repeating or rewording that request; otherwise null.'),
84
+ value: described(nullable({ anyOf: [{ type: 'boolean' }, { type: 'number' }, str(2000)] }), 'Typed property value; use text for written content and null to clear it.'),
85
+ choice: described(nullable({ type: 'string', enum: ['yes', 'no', 'abstain'] }), 'The vote cast.'),
86
+ initialProperties: described({ type: 'object', additionalProperties: true }, 'Typed values written when the entity is created; include required values such as a document body.'),
87
+ };
88
+ const fieldsByEffect = {
89
+ move: ['personId', 'placeId'],
90
+ take: ['objectId', 'personId'],
91
+ drop: ['objectId', 'placeId'],
92
+ 'object.update': ['objectId', 'condition', 'name', 'targetId', 'placeId', 'personId'],
93
+ 'object.create': ['objectId', 'name', 'text', 'condition', 'placeId', 'targetId', 'personId'],
94
+ 'place.condition': ['placeId', 'name', 'text'],
95
+ 'place.create': ['placeId', 'name', 'text', 'connections'],
96
+ 'person.create': ['personId', 'name', 'role', 'text', 'placeId'],
97
+ money: ['personId', 'amount'],
98
+ transfer: ['personId', 'targetId', 'amount'],
99
+ relationship: ['personId', 'targetId', 'trust', 'warmth'],
100
+ belief: ['personId', 'name', 'text'],
101
+ commitment: ['personId', 'targetId', 'text', 'minutes'],
102
+ goal: ['personId', 'name', 'text'],
103
+ mood: ['personId', 'text'],
104
+ 'person.condition': ['personId', 'text'],
105
+ hold: ['personId', 'targetId', 'text'],
106
+ role: ['personId', 'text', 'roleId'],
107
+ schedule: ['personId', 'minutes', 'text', 'placeId', 'targetId'],
108
+ fact: ['name', 'text'],
109
+ 'tension.update': ['tensionId', 'status', 'text'],
110
+ 'tension.create': ['tensionId', 'name', 'text', 'participantIds'],
111
+ incapacitate: ['personId', 'text'],
112
+ message: ['personId', 'targetId', 'sourcePersonId', 'text'],
113
+ 'entity.create': ['entityId', 'kindId', 'name', 'placeId', 'condition', 'personId', 'participantIds', 'initialProperties'],
114
+ 'property.set': ['entityId', 'propertyId', 'value'],
115
+ 'relation.set': ['entityId', 'relationId', 'targetId'],
116
+ 'request.open': ['personId', 'targetId', 'text', 'priorId'],
117
+ 'person.leave': ['personId', 'text'],
118
+ 'person.away': ['personId', 'minutes', 'text'],
119
+ ballot: ['entityId', 'personId', 'choice'],
120
+ };
121
+ // Old events still decode through GmEffectRecord. New rulings use typed entities
122
+ // for lasting things instead of open-ended prose records.
123
+ const nonGmEffectKinds = new Set([
124
+ 'fact', 'place.condition', 'object.create', 'money',
125
+ 'belief', 'relationship', 'message', 'goal', 'mood', 'commitment', 'hold', 'person.condition',
126
+ 'tension.create', 'tension.update', 'role',
127
+ ]);
128
+ const requiredEffectValues = {
129
+ 'place.create': ['name', 'text'], 'person.create': ['name', 'text'], money: ['amount'], transfer: ['amount'],
130
+ role: ['text'], schedule: ['text', 'minutes'], incapacitate: ['text'],
131
+ 'entity.create': ['entityId', 'name', 'initialProperties'], 'property.set': ['entityId', 'propertyId'],
132
+ 'relation.set': ['entityId', 'relationId'], 'request.open': ['text'], 'person.leave': ['personId', 'text'],
133
+ 'person.away': ['personId', 'minutes', 'text'], ballot: ['entityId', 'choice'],
134
+ };
135
+ function effectField(kind, field) {
136
+ const source = effectFields[field];
137
+ if (field === 'initialProperties')
138
+ return source;
139
+ if (kind === 'schedule' && field === 'minutes')
140
+ return described({ type: 'integer', minimum: 1, maximum: 100_000 }, source.description);
141
+ if (kind === 'person.away' && field === 'minutes')
142
+ return described({ type: 'integer', minimum: 15, maximum: 1440 }, source.description);
143
+ if (kind === 'transfer' && field === 'amount')
144
+ return described({ type: 'number', exclusiveMinimum: 0, maximum: 1_000_000_000 }, source.description);
145
+ if (kind === 'money' && field === 'amount')
146
+ return described({ anyOf: [
147
+ { type: 'integer', minimum: -1_000_000_000, maximum: -1 },
148
+ { type: 'integer', minimum: 1, maximum: 1_000_000_000 },
149
+ ] }, source.description);
150
+ if (!requiredEffectValues[kind]?.includes(field))
151
+ return source;
152
+ const variants = source.anyOf;
153
+ return described(variants[0], source.description);
154
+ }
155
+ // The provider writes object keys in sorted order, so the first key written decides which
156
+ // shape of a union remains possible. Each shape therefore names its kind first and keeps its
157
+ // own fields under one key that sorts after it.
158
+ export function kindFirst(container) {
159
+ return (arm) => {
160
+ const { kind, ...fields } = arm.properties;
161
+ return { type: 'object', additionalProperties: false, required: ['kind', container], properties: { kind,
162
+ [container]: { type: 'object', additionalProperties: false, required: arm.required.filter(name => name !== 'kind'), properties: fields } } };
163
+ };
164
+ }
165
+ // What a field means for one kind of change, where the shared meaning would mislead.
166
+ const FIELD_MEANINGS = {
167
+ move: { personId: 'Person who goes.', placeId: 'Neighboring place the person goes to.' },
168
+ take: { personId: 'Person who takes the object.' },
169
+ drop: { placeId: 'Place where the object is put down.' },
170
+ 'object.update': { condition: 'New condition; null when unchanged.', name: 'Condition side, such as damage; null for state.', targetId: 'New holder; null when unchanged.',
171
+ placeId: 'New place; null when unchanged.', personId: 'New owner; null when unchanged.' },
172
+ 'place.create': { placeId: 'Id for the new place.', name: 'Name of the new place.', text: 'Short description of the new place.' },
173
+ 'person.create': { personId: 'Id for the new person.', name: 'Full name of the new person.',
174
+ text: 'What brought them here and what they want now, in their own terms.', placeId: 'Place where the person appears.' },
175
+ money: { personId: 'Person whose money changes.' },
176
+ transfer: { personId: 'Who pays: a person or an account id; null when it comes from outside the world.', targetId: 'Who receives: a person or an account id; null when it leaves the world.',
177
+ amount: 'How much, in the world\'s money unit; parts of a unit are allowed.' },
178
+ schedule: { personId: 'Always null; people choose their own plans.', minutes: 'Minutes until it happens.', text: 'What will happen.',
179
+ placeId: 'Place where it happens.', targetId: 'Entity or person it concerns; null when none.' },
180
+ incapacitate: { personId: 'Person who can no longer act.', text: 'Why they cannot act.' },
181
+ 'entity.create': { participantIds: 'A decision\'s voters; else null.', name: 'Name of the new thing.', placeId: 'Place where the new thing is; null when it belongs to no place, such as an agreement, a debt, a right, or a rumor.',
182
+ condition: 'How it is now, as anyone could see; null when it belongs to no place.', personId: 'Person here whose hand the act leaves it in; null for words on a wall, a board or a thing, and for anything that lies there.' },
183
+ 'person.leave': { personId: 'Person who leaves.', text: 'Why and how they leave.' },
184
+ 'person.away': { personId: 'Person who goes away for a while.', minutes: 'Minutes until they are back.', text: 'Where they go and why.' },
185
+ 'request.open': { personId: 'Actor who makes the request.', targetId: 'Person here who receives the request.',
186
+ priorId: 'Known request id when repeating or rewording that request; otherwise null.', text: 'Action requested, with no answer implied.' },
187
+ };
188
+ const flatEffectArms = GM_EFFECT_KINDS.filter(kind => !nonGmEffectKinds.has(kind)).map(kind => {
189
+ const fields = fieldsByEffect[kind];
190
+ return {
191
+ type: 'object', additionalProperties: false, required: ['kind', ...fields],
192
+ properties: { kind: { const: kind, description: EFFECT_MEANINGS[kind] },
193
+ ...Object.fromEntries(fields.map(field => [field, FIELD_MEANINGS[kind]?.[field] === undefined ? effectField(kind, field)
194
+ : described(effectField(kind, field), FIELD_MEANINGS[kind][field])])) },
195
+ };
196
+ });
197
+ export const gmEffectSchema = { anyOf: flatEffectArms.map(kindFirst('values')) };
198
+ export function responseFieldLines(schema) {
199
+ const lines = Object.entries(schema.properties).map(([name, field]) => {
200
+ if (!field.description)
201
+ throw new Error(`Response field ${name} needs a description`);
202
+ return `${name}: ${field.description}`;
203
+ });
204
+ const unions = Object.values(schema.properties);
205
+ for (const arm of unions.flatMap(field => field.items?.anyOf ?? [])) {
206
+ const kind = arm.properties.kind?.const;
207
+ if (!kind || !arm.properties.kind?.description)
208
+ continue;
209
+ // Each kind of change is one line that names its own fields; their schema descriptions stay in the schema.
210
+ lines.push(`${kind}: ${arm.properties.kind.description}`);
211
+ }
212
+ return lines.join('\n');
213
+ }
214
+ // The provider emits object keys in sorted order. The names make that order the order of
215
+ // reasoning: the written result comes first, then whether a kind fits, then the typed changes.
216
+ // What a ruling may carry to the rooms around, each worded by the engine, so a notice never names anyone.
217
+ export const SIGNAL_SENSES = ['sound', 'voices', 'shouting', 'scream', 'crash', 'bang', 'alarm', 'machinery', 'footsteps', 'music', 'loudspeaker', 'sight', 'light', 'smoke', 'burning', 'smell'];
218
+ export const SIGNAL_NOTICES = {
219
+ sound: 'A sound reaches', voices: 'Voices carry', shouting: 'Shouting carries', scream: 'A scream carries', crash: 'A crash carries', bang: 'A bang carries',
220
+ alarm: 'An alarm sounds', machinery: 'The noise of machinery carries', footsteps: 'Running feet sound', music: 'Music carries', loudspeaker: 'A voice on a loudspeaker carries',
221
+ sight: 'A sight reaches', light: 'A light shows', smoke: 'Smoke drifts', burning: 'A smell of burning drifts', smell: 'A smell reaches',
222
+ };
223
+ export const attemptResponseSchema = {
224
+ type: 'object',
225
+ additionalProperties: false,
226
+ required: ['narration', 'record', 'observed', 'perceivedBy', 'visibleObjectIds', 'visibleTensionIds', 'outcome', 'minutes', 'importance', 'reach', 'signalChannel', 'actionKind', 'reactorIds', 'settledTensionId', 'settlement', 'newTension', 'stateKindFit', 'stateNewKind', 'stateUpdates', 'thingIds'],
227
+ properties: {
228
+ narration: described(str(900), 'What the actor senses now, in the requested voice.'),
229
+ record: described(str(300), 'Objective result, hidden facts included.'),
230
+ observed: described(str(600), 'What onlookers here see: outward behavior only.'),
231
+ perceivedBy: described(ids(32), 'Present people who noticed it.'),
232
+ visibleObjectIds: described(ids(48), 'Local objects whose state onlookers see.'),
233
+ visibleTensionIds: described(ids(32), 'Local problems whose status onlookers see.'),
234
+ outcome: described({ type: 'string', enum: ['succeeded', 'partial', 'failed', 'impossible'] }, 'What happened to the attempt.'),
235
+ minutes: described({ type: 'integer', minimum: 0, maximum: 240 }, 'Game minutes it takes.'),
236
+ importance: described({ type: 'integer', minimum: 1, maximum: 10 }, 'Impact, 1 routine to 10 life changing.'),
237
+ reach: described({ type: 'string', enum: ['here', 'nearby', 'everywhere'] }, 'here, nearby (a shout, crash or smoke carries next door), or everywhere.'),
238
+ signalChannel: described(nullable({ type: 'string', enum: [...SIGNAL_SENSES] }), 'For nearby or everywhere, what carries to the rooms around; else null.'),
239
+ actionKind: described(nullable(str(64)), 'Act category from a local norm; null when none covers it.'),
240
+ reactorIds: described(ids(2), 'Up to two present people who react now.'),
241
+ settledTensionId: described(nullable(str(64)), 'Problem this resolves; else null.'),
242
+ settlement: described(nullable(str(600)), 'How that problem ended.'),
243
+ newTension: described(nullable({ type: 'object', additionalProperties: false, required: ['title', 'summary', 'participantIds', 'visible'], properties: { title: str(120), summary: str(600), participantIds: ids(6), visible: { type: 'boolean' } } }), 'A new problem; else null.'),
244
+ stateKindFit: described({ type: 'string', enum: ['not-needed', 'complete', 'missing'] }, 'complete: typed slots hold every lasting part; missing: no listed kind fits; not-needed: nothing lasting changes.'),
245
+ stateNewKind: described(nullable({ type: 'object', additionalProperties: false, required: ['id', 'name', 'meaning'], properties: { id: str(64), name: str(120), meaning: str(300) } }), 'When stateKindFit is missing: id, name and general meaning of a reusable kind.'),
246
+ stateUpdates: described({ type: 'array', items: gmEffectSchema, maxItems: 8 }, 'Typed changes that make the result last, each as its kind with fields in values.'),
247
+ thingIds: described(ids(8), 'Things here the act handles, uses or changes.'),
248
+ },
249
+ };
250
+ export function scopedAttemptResponseSchema(input) {
251
+ const kinds = input.kinds;
252
+ const kindIds = [...new Set(kinds.map(kind => kind.id))].sort();
253
+ const propertyIds = [...new Set(kinds.flatMap(kind => kind.properties.map(property => property.id)))].sort();
254
+ const relationIds = [...new Set(kinds.flatMap(kind => kind.relations.map(relation => relation.id)))].sort();
255
+ const world = input.world;
256
+ const scene = input.scene;
257
+ const actor = input.actor;
258
+ // Only the actor votes in their own act, and only on a decision open to them.
259
+ const voteIds = (actor?.votes ?? []).map(vote => vote.id).sort();
260
+ const requests = input.requests ?? [];
261
+ // The selected present IDs and cards share one response vocabulary.
262
+ const present = input.possiblePerceiverIds ?? [];
263
+ const localPeople = new Set([...scene.people.map(person => person.id), ...present, ...(actor ? [actor.id] : [])]);
264
+ const people = world.people;
265
+ const personIds = [...new Set([...people.map(person => person.id), ...present])].sort();
266
+ const placeIds = world.places.map(place => place.id).sort();
267
+ // Things at this place come from the scene; the directory adds what is nearby or held.
268
+ const objects = [...scene.objects.map(object => ({ id: object.id, placeId: scene.id, holderId: null })), ...world.objects];
269
+ const objectIds = [...new Set(objects.map(object => object.id))].sort();
270
+ const localObjectIds = [...new Set(objects.filter(object => object.placeId === scene.id
271
+ || (object.holderId !== null && localPeople.has(object.holderId))).map(object => object.id))].sort();
272
+ // A written thing or token that is here changes hands the way an object does.
273
+ const carriable = scene.entities.flatMap(entity => entity.holderId === undefined ? []
274
+ : [{ id: entity.id, placeId: entity.holderId === null ? scene.id : null, holderId: entity.holderId }]);
275
+ const reachable = [...objects, ...carriable];
276
+ const takeIds = [...new Set([...localObjectIds, ...carriable.map(thing => thing.id)])].sort();
277
+ const heldObjectIds = [...world.objects, ...carriable].filter(object => object.holderId !== null && localPeople.has(object.holderId))
278
+ .map(object => object.id).sort();
279
+ const tensionIds = world.tensions.map(tension => tension.id).sort();
280
+ const visibleTensionIds = world.tensions.filter(tension => tension.participants.some(person => localPeople.has(person.id)))
281
+ .map(tension => tension.id).sort();
282
+ const perceiverIds = input.possiblePerceiverIds.slice().sort();
283
+ const reactorIds = input.presentCharacterIds.slice().sort();
284
+ const knownIds = [...new Set([...personIds, ...placeIds])].sort();
285
+ const typedValue = (type) => type === 'flag' ? { type: 'boolean' } : type === 'number' ? { type: 'number' }
286
+ : type === 'time' ? { type: 'integer', minimum: 0 } : type === 'level' ? { type: 'string', enum: ['none', 'low', 'medium', 'high'] }
287
+ : type === 'id' ? { type: 'string', enum: knownIds } : str(2000);
288
+ const idField = (ids, field, optional = false) => described(optional ? nullable({ type: 'string', enum: ids }) : { type: 'string', enum: ids }, effectFields[field].description);
289
+ // A ruling names the kind of act when a norm or a gate in scope speaks about that kind.
290
+ const actionKinds = [...new Set(kinds.flatMap(kind => kind.mechanics.flatMap(mechanic => mechanic.kind === 'norm' && mechanic.actionKind !== undefined ? [mechanic.actionKind]
291
+ : mechanic.kind === 'gate' ? (mechanic.blockedActionKinds ?? []).filter(actionKind => !ENGINE_ACTION_KINDS.has(actionKind)) : [])))].sort();
292
+ const arms = flatEffectArms
293
+ .filter(arm => (objectIds.length > 0 || carriable.length > 0 || arm.properties.kind.const !== 'object.update')
294
+ && (takeIds.length > 0 || arm.properties.kind.const !== 'take')
295
+ && (heldObjectIds.length > 0 || arm.properties.kind.const !== 'drop')
296
+ && (scene.entities.length > 0 || !['property.set', 'relation.set'].includes(arm.properties.kind.const))
297
+ && (tensionIds.length > 0 || arm.properties.kind.const !== 'tension.update')
298
+ && (actor !== undefined && localPeople.size > 1 || arm.properties.kind.const !== 'request.open')
299
+ && (voteIds.length > 0 || arm.properties.kind.const !== 'ballot')
300
+ // A happening removes no one from the story; people leave by their own decisions.
301
+ && (input.phase !== 'world' || arm.properties.kind.const !== 'person.leave'))
302
+ .flatMap(arm => {
303
+ const kind = arm.properties.kind.const;
304
+ // Options for moving and taking grow with places and holders, not with people and things:
305
+ // everyone at one place shares its neighbors, and everything one holder has shares its takers.
306
+ if (kind === 'move') {
307
+ // A happening moves no one: people walk by their own decisions. The player moves only by their own act.
308
+ if (input.phase === 'world')
309
+ return [];
310
+ const listed = new Set(world.people.map(person => person.id));
311
+ const movers = [...world.people.filter(person => !person.isPlayer || person.id === actor?.id),
312
+ ...reactorIds.filter(id => !listed.has(id)).map(id => ({ id, placeId: scene.id }))];
313
+ const origins = [...new Set(movers.map(person => person.placeId))].sort();
314
+ return origins.flatMap(origin => {
315
+ const destinations = [...new Set(world.places.find(place => place.id === origin)?.connections ?? [])].filter(id => id !== origin).sort();
316
+ const walkers = movers.filter(person => person.placeId === origin).map(person => person.id).sort();
317
+ if (walkers.length === 0)
318
+ return [];
319
+ return destinations.length > 0 ? [{ ...arm, properties: { ...arm.properties,
320
+ personId: described({ type: 'string', enum: walkers }, effectFields.personId.description),
321
+ placeId: described({ type: 'string', enum: destinations }, 'Neighboring place the person goes to.'), } }] : [];
322
+ });
323
+ }
324
+ if (kind === 'take') {
325
+ const holders = [...new Set(takeIds.map(id => reachable.find(object => object.id === id).holderId))];
326
+ return holders.flatMap(holder => {
327
+ const things = takeIds.filter(id => reachable.find(object => object.id === id).holderId === holder);
328
+ const takers = [...localPeople].filter(id => id !== holder).sort();
329
+ return takers.length > 0 ? [{ ...arm, properties: { ...arm.properties,
330
+ objectId: described(things.length === 1 ? { const: things[0] } : { type: 'string', enum: things }, effectFields.objectId.description),
331
+ personId: described({ type: 'string', enum: takers }, effectFields.personId.description),
332
+ } }] : [];
333
+ });
334
+ }
335
+ const fields = {};
336
+ if (kind === 'entity.create')
337
+ return kinds.map(definition => ({ ...arm,
338
+ required: arm.required,
339
+ properties: { ...arm.properties,
340
+ // A fire, a flood or a sound stays where it is, and an injury or a debt belongs to no hand.
341
+ ...(neverHeld(LIVING_ENGINE_VERSION, definition.id, definition) ? { personId: described({ type: 'null' }, 'No one holds this kind of thing.') } : {}),
342
+ kindId: described({ const: definition.id }, effectFields.kindId.description),
343
+ placeId: described({ enum: [scene.id, null] }, 'Place where the new thing is; null when it belongs to no place, such as an agreement, a debt, a right, or a rumor.'),
344
+ initialProperties: described({ type: 'object', additionalProperties: false,
345
+ required: definition.properties.filter(property => property.requiredOnCreate).map(property => property.id),
346
+ properties: Object.fromEntries(definition.properties.map(property => [property.id,
347
+ property.type === 'flag' ? { type: 'boolean' }
348
+ : property.type === 'number' ? { type: 'number' }
349
+ : property.type === 'time' ? { type: 'integer', minimum: 0, description: 'Minutes since Day 1, 00:00; now is clockMinutes.' }
350
+ : property.type === 'level' ? { type: 'string', enum: ['none', 'low', 'medium', 'high'] }
351
+ : property.type === 'id' ? { type: 'string', maxLength: 64, description: 'Id of a person, place or thing in the input.' }
352
+ : str(2000)])) }, 'Values written when this entity is created. Include every required property.'), },
353
+ }));
354
+ // One option for each kind here: its things, its properties, and values of its properties' types
355
+ // only, with an id naming a person or a place.
356
+ const addsLine = input.textWrites === 'add';
357
+ if (kind === 'property.set')
358
+ return kinds.flatMap(definition => {
359
+ const entityIds = scene.entities.filter(entity => entity.kindId === definition.id).map(entity => entity.id).sort();
360
+ const types = [...new Set(definition.properties.map(property => property.type))].sort();
361
+ if (entityIds.length === 0 || types.length === 0)
362
+ return [];
363
+ return [{ ...arm, properties: { ...arm.properties,
364
+ ...(addsLine ? { kind: { const: kind, description: ADDED_LINE_MEANING } } : {}),
365
+ entityId: described({ type: 'string', enum: entityIds }, effectFields.entityId.description),
366
+ propertyId: described({ type: 'string', enum: definition.properties.map(property => property.id).sort() }, effectFields.propertyId.description),
367
+ value: described({ anyOf: [...types.map(type => type === 'text' ? (addsLine ? described(str(MAX_ADDED_LINE), 'Only the words written now; what is written stays.')
368
+ : described(str(2000), 'The whole text as it now reads, with the change.')) : typedValue(type)), { type: 'null' }] }, effectFields.value.description) } }];
369
+ });
370
+ // Likewise one link option for each kind here that has links: its things and its own relations only.
371
+ if (kind === 'relation.set')
372
+ return kinds.flatMap(definition => {
373
+ const entityIds = scene.entities.filter(entity => entity.kindId === definition.id).map(entity => entity.id).sort();
374
+ if (entityIds.length === 0 || definition.relations.length === 0)
375
+ return [];
376
+ return [{ ...arm, properties: { ...arm.properties,
377
+ entityId: described({ type: 'string', enum: entityIds }, effectFields.entityId.description),
378
+ relationId: described({ type: 'string', enum: definition.relations.map(relation => relation.id).sort() }, effectFields.relationId.description) } }];
379
+ });
380
+ if (kind === 'request.open') {
381
+ fields.personId = described({ const: actor.id }, 'Actor who makes the request.');
382
+ fields.targetId = described({ type: 'string', enum: [...localPeople].filter(id => id !== actor.id).sort() }, 'Person here who receives the request.');
383
+ fields.priorId = described(requests.length > 0
384
+ ? nullable({ type: 'string', enum: requests.map(request => request.id).sort() }) : { type: 'null' }, effectFields.priorId.description);
385
+ }
386
+ if (kind === 'ballot') {
387
+ fields.personId = described({ const: actor.id }, 'The actor, who casts their own vote.');
388
+ fields.entityId = described({ type: 'string', enum: voteIds }, 'Decision voted on.');
389
+ fields.choice = described({ type: 'string', enum: ['yes', 'no', 'abstain'] }, effectFields.choice.description);
390
+ }
391
+ if (kind === 'schedule')
392
+ fields.personId = described({ type: 'null' }, effectFields.personId.description);
393
+ if (fieldsByEffect[kind].includes('personId') && !['person.create', 'schedule', 'request.open', 'ballot'].includes(kind))
394
+ fields.personId = idField(personIds, 'personId', kind === 'object.update');
395
+ // A happening sends away only someone it brings in, heard on a call; the rest leave by their own decisions.
396
+ if (kind === 'person.away' && input.phase === 'world')
397
+ fields.personId = described(str(64), 'Someone this ruling brings in who is only on a call.');
398
+ if (['take', 'drop', 'object.update'].includes(kind))
399
+ fields.objectId = idField(kind === 'object.update' ? [...new Set([...objectIds, ...carriable.map(thing => thing.id)])].sort() : kind === 'drop' ? heldObjectIds : takeIds, 'objectId');
400
+ if (fieldsByEffect[kind].includes('placeId') && kind !== 'place.create')
401
+ fields.placeId = idField(placeIds, 'placeId', !['move', 'drop', 'person.create'].includes(kind));
402
+ if (kind === 'tension.update')
403
+ fields.tensionId = idField(tensionIds, 'tensionId');
404
+ if (['relationship', 'commitment', 'message'].includes(kind))
405
+ fields.targetId = idField(personIds, 'targetId');
406
+ if (['hold', 'object.update'].includes(kind))
407
+ fields.targetId = idField(personIds, 'targetId', true);
408
+ if (kind === 'message')
409
+ fields.sourcePersonId = idField(personIds, 'sourcePersonId', true);
410
+ if (kind === 'tension.create')
411
+ fields.participantIds = described({ type: 'array', items: { type: 'string', enum: personIds }, maxItems: 6 }, effectFields.participantIds.description);
412
+ return [{ ...arm, properties: { ...arm.properties, ...fields } }];
413
+ });
414
+ return { ...attemptResponseSchema, properties: { ...attemptResponseSchema.properties,
415
+ actionKind: described(actionKinds.length > 0 ? nullable({ type: 'string', enum: actionKinds }) : { type: 'null' }, attemptResponseSchema.properties.actionKind.description),
416
+ stateUpdates: described({ type: 'array', items: { anyOf: arms.map(kindFirst('values')) }, maxItems: 8 }, attemptResponseSchema.properties.stateUpdates.description),
417
+ perceivedBy: described({ type: 'array', items: perceiverIds.length > 0 ? { type: 'string', enum: perceiverIds } : str(64), maxItems: Math.min(32, perceiverIds.length) }, attemptResponseSchema.properties.perceivedBy.description),
418
+ reactorIds: described({ type: 'array', items: reactorIds.length > 0 ? { type: 'string', enum: reactorIds } : str(64), maxItems: Math.min(2, reactorIds.length) }, attemptResponseSchema.properties.reactorIds.description),
419
+ visibleObjectIds: described({ type: 'array', items: localObjectIds.length > 0 ? { type: 'string', enum: localObjectIds } : str(64), maxItems: Math.min(48, localObjectIds.length) }, attemptResponseSchema.properties.visibleObjectIds.description),
420
+ visibleTensionIds: described({ type: 'array', items: visibleTensionIds.length > 0 ? { type: 'string', enum: visibleTensionIds } : str(64), maxItems: Math.min(32, visibleTensionIds.length) }, attemptResponseSchema.properties.visibleTensionIds.description),
421
+ settledTensionId: described(tensionIds.length > 0 ? nullable({ type: 'string', enum: tensionIds }) : { type: 'null' }, attemptResponseSchema.properties.settledTensionId.description),
422
+ } };
423
+ }
424
+ // An activity: its private purpose, what anyone watching sees, where and with whom, and how long it lasts.
425
+ // Round 9: named "doing", the outward view drew the person's aim in 9 of 60 answers; "seenDoing" drew none.
426
+ const ACTIVITY = { type: 'object', additionalProperties: false, required: ['intent', 'seenDoing', 'placeId', 'targetId', 'inMinutes'], properties: {
427
+ intent: described(str(300), 'Your private purpose.'), seenDoing: described({ ...str(200), minLength: 3 }, 'What anyone watching sees you doing.'),
428
+ placeId: nullable(str(64)), targetId: nullable(str(64)), inMinutes: described({ type: 'integer', minimum: 1, maximum: 100_000 }, 'Minutes it really takes, often 30 to 120. Replies and anything you notice reach you during it.')
429
+ } };
430
+ export const reactionResponseSchema = {
431
+ type: 'object',
432
+ additionalProperties: false,
433
+ required: ['say', 'act', 'toIds', 'mood', 'weight', 'leaveToPlaceId', 'trust', 'warmth', 'relationshipNote', 'belief', 'commitment', 'newGoal', 'goalDone', 'plan', 'tell', 'suggestedReplies', 'endConversation', 'request', 'requestDecision', 'answered', 'stance'],
434
+ properties: {
435
+ say: described(nullable(str(MAX_SPOKEN)), 'Your words to people here; null for silence.'),
436
+ request: described(nullable({ type: 'object', additionalProperties: false,
437
+ required: ['topic', 'receiverId', 'priorId'],
438
+ properties: { topic: str(600), receiverId: str(64), priorId: nullable(str(64)) } }), 'A concrete ask of someone in this line, with priorId when it repeats a known request; else null.'),
439
+ requestDecision: described(nullable({ type: 'object', additionalProperties: false, required: ['id', 'status'],
440
+ properties: { id: str(64), status: { type: 'string', enum: ['answered', 'refused', 'done'] } } }), 'Your answer to an open request to you; else null.'),
441
+ answered: described(nullable(str(64)), 'Id of your own open request these words answer; else null.'),
442
+ act: described(nullable(str(200)), 'One physical act you try now; null if you only speak.'),
443
+ toIds: described(ids(4), 'People here you address.'),
444
+ mood: described(str(40), 'Your feeling now in a few words.'),
445
+ weight: described({ type: 'integer', minimum: 1, maximum: 10 }, 'How serious this is to you, 1 to 10.'),
446
+ stance: described(nullable({ type: 'string', enum: ['undecided', 'cooperate', 'refuse', 'report', 'avoid', 'confront'] }), 'Your decision toward the actor after a serious act; else null.'),
447
+ leaveToPlaceId: described(nullable(str(64)), 'Exit you take now; else null.'),
448
+ trust: described({ type: 'integer', minimum: -20, maximum: 20 }, 'Change in your trust of the actor.'),
449
+ warmth: described({ type: 'integer', minimum: -20, maximum: 20 }, 'Change in your warmth toward the actor.'),
450
+ relationshipNote: described(nullable(str(200)), 'Why your feelings changed; else null.'),
451
+ belief: described(nullable({ type: 'object', additionalProperties: false, required: ['subject', 'claim'], properties: { subject: str(120), claim: str(300) } }), 'A conclusion you now hold; else null.'),
452
+ commitment: described(nullable({ type: 'object', additionalProperties: false, required: ['toId', 'text', 'dueInMinutes', 'placeId'], properties: { toId: str(64), text: str(300), dueInMinutes: nullable({ type: 'integer', minimum: 0, maximum: 100_000 }),
453
+ placeId: described(nullable(str(64)), 'Where you promised to be, when you promised to be somewhere; else null.') } }), 'A promise you make; else null.'),
454
+ newGoal: described(nullable(str(300)), 'A new aim; else null.'),
455
+ goalDone: described(nullable(str(300)), 'Id of your goal now resolved; else null.'),
456
+ plan: described(nullable(ACTIVITY), 'A new activity you switch to now; null to carry on.'),
457
+ tell: described(nullable({ type: 'object', additionalProperties: false, required: ['targetId', 'text'], properties: { targetId: str(64), text: str(300) } }), 'Someone to inform and what to tell them; else null.'),
458
+ suggestedReplies: described({ type: 'array', items: str(120), maxItems: 3 }, 'Lines the player might say next, in the player\'s voice.'),
459
+ endConversation: described({ type: 'boolean' }, 'Whether you end this exchange.'),
460
+ },
461
+ };
462
+ // The engine's own action kinds, which gates block outside any ruling.
463
+ export const ENGINE_ACTION_KINDS = new Set(['move', 'speak', 'message', 'act', 'incapacitate']);
464
+ export function scopedReactionResponseSchema(input) {
465
+ const identity = input.identity;
466
+ const blocked = new Set(identity.blocked ?? []);
467
+ const requests = input.requests;
468
+ const openIds = requests.filter(request => request.toId === identity.id && request.status === 'open').map(request => request.id).sort();
469
+ // Only the person spoken to can answer what this person asked them.
470
+ const speakerId = input.happened?.byId ?? null;
471
+ const askedIds = requests.filter(request => request.fromId === identity.id && request.toId === speakerId && request.status === 'open')
472
+ .map(request => request.id).sort();
473
+ const goalIds = [...new Set((input.goals ?? []).map(goal => goal.id))].sort();
474
+ // People here may be addressed, except someone who has left this person's last lines unanswered.
475
+ const addressable = directoryPeople(input).filter(person => person.here === true && person.id !== identity.id && person.noAnswerSince === undefined)
476
+ .map(person => person.id).sort();
477
+ return withBallot({ ...reactionResponseSchema, properties: { ...reactionResponseSchema.properties,
478
+ requestDecision: described(openIds.length > 0 ? nullable({ type: 'object', additionalProperties: false,
479
+ required: ['id', 'status'], properties: { id: { type: 'string', enum: openIds },
480
+ status: { type: 'string', enum: ['answered', 'refused', 'done'] } } }) : { type: 'null' }, reactionResponseSchema.properties.requestDecision.description),
481
+ answered: described(askedIds.length > 0 ? nullable({ type: 'string', enum: askedIds }) : { type: 'null' }, reactionResponseSchema.properties.answered.description),
482
+ goalDone: described(goalIds.length > 0 ? nullable({ type: 'string', enum: goalIds }) : { type: 'null' }, reactionResponseSchema.properties.goalDone.description),
483
+ toIds: described(addressable.length > 0 ? { type: 'array', items: { type: 'string', enum: addressable }, maxItems: Math.min(4, addressable.length) } : { type: 'array', maxItems: 0 }, reactionResponseSchema.properties.toIds.description),
484
+ // A gated person is offered no line or act of the blocked kinds.
485
+ ...(blocked.has('speak') ? { say: described({ type: 'null' }, reactionResponseSchema.properties.say.description) } : {}),
486
+ ...(blocked.has('act') ? { act: described({ type: 'null' }, reactionResponseSchema.properties.act.description) } : {}),
487
+ } }, input);
488
+ }
489
+ // Someone with a vote open to them may cast it in this answer; anyone else is offered no ballot at all.
490
+ // On their own turn to vote they must cast it; abstaining is a choice.
491
+ function withBallot(schema, input, turn = false) {
492
+ const voteIds = (input.votes ?? []).map(vote => vote.id).sort();
493
+ if (voteIds.length === 0)
494
+ return schema;
495
+ const cast = { type: 'object', additionalProperties: false, required: ['decisionId', 'choice'], properties: {
496
+ decisionId: { type: 'string', enum: voteIds }, choice: { type: 'string', enum: ['yes', 'no', 'abstain'] }
497
+ } };
498
+ return { ...schema, required: [...schema.required, 'ballot'], properties: { ...schema.properties,
499
+ ballot: turn ? described(cast, 'Your own vote on the open decision, cast now.') : described(nullable(cast), 'Your own vote on an open decision, cast now; else null.') } };
500
+ }
501
+ const PLAN_ACTION_GATES = { go: 'move', 'go-home': 'move', speak: 'speak', message: 'message', attempt: 'act' };
502
+ const directoryPeople = (input) => (input.directory?.people ?? []);
503
+ export function scopedPlanResponseSchema(input) {
504
+ const identity = input.identity;
505
+ const blocked = new Set(identity.blocked ?? []);
506
+ const actions = PLAN_ACTIONS.filter(action => !blocked.has(PLAN_ACTION_GATES[action] ?? ''));
507
+ // Anyone known may be sought out, except someone who has left this person's last lines unanswered.
508
+ const targets = directoryPeople(input).filter(person => person.id !== identity.id && person.noAnswerSince === undefined).map(person => person.id).sort();
509
+ return withBallot({ ...planResponseSchema, properties: { ...planResponseSchema.properties,
510
+ action: described({ type: 'string', enum: actions }, planResponseSchema.properties.action.description),
511
+ targetId: described(targets.length > 0 ? nullable({ type: 'string', enum: targets }) : { type: 'null' }, planResponseSchema.properties.targetId.description) } }, input, true);
512
+ }
513
+ export const speechImpactResponseSchema = {
514
+ type: 'object',
515
+ additionalProperties: false,
516
+ required: ['importance', 'pressure', 'loud', 'addressedIds', 'aboutIds'],
517
+ properties: {
518
+ importance: described({ type: 'integer', minimum: 1, maximum: 10 }, 'Social impact, 1 routine to 10 severe.'),
519
+ pressure: described(nullable({ type: 'object', additionalProperties: false, required: ['kind', 'text', 'dueInMinutes'], properties: {
520
+ kind: { type: 'string', enum: ['demand', 'threat', 'accusation', 'proposal', 'promise'] },
521
+ text: described(str(200), 'What is demanded, threatened, charged, proposed or promised.'),
522
+ dueInMinutes: described(nullable({ type: 'integer', minimum: 0, maximum: 100_000 }), 'When a promise falls due, in minutes from now; else null.')
523
+ } }), 'What the line presses on listeners; else null.'),
524
+ loud: described({ type: 'boolean' }, 'True only if shouted, loud enough to carry next door.'),
525
+ addressedIds: described({ type: 'array', items: str(64), maxItems: 4 }, 'People these words are for; empty for the room.'),
526
+ aboutIds: described({ type: 'array', items: str(64), maxItems: 4 }, 'Things here the words are about.'),
527
+ },
528
+ };
529
+ // A line may be for someone present or someone known elsewhere.
530
+ export function scopedSpeechImpactResponseSchema(presentIds, thingIds = []) {
531
+ return { ...speechImpactResponseSchema, properties: { ...speechImpactResponseSchema.properties,
532
+ addressedIds: described({ type: 'array', items: presentIds.length > 0 ? { type: 'string', enum: [...presentIds].sort() } : str(64), maxItems: Math.min(4, presentIds.length) }, speechImpactResponseSchema.properties.addressedIds.description),
533
+ aboutIds: described({ type: 'array', items: thingIds.length > 0 ? { type: 'string', enum: [...thingIds].sort() } : str(64), maxItems: Math.min(4, thingIds.length) }, speechImpactResponseSchema.properties.aboutIds.description) } };
534
+ }
535
+ const PLAN_ACTIONS = ['go', 'speak', 'message', 'attempt', 'go-home', 'wait'];
536
+ export const planResponseSchema = {
537
+ type: 'object',
538
+ additionalProperties: false,
539
+ required: ['action', 'placeId', 'targetId', 'text', 'mood', 'nextPlan', 'request', 'stance'],
540
+ properties: {
541
+ action: described({ type: 'string', enum: [...PLAN_ACTIONS] }, 'One act now; go-home: away until nextPlan ends.'),
542
+ placeId: described(nullable(str(64)), 'Destination for go; else null.'),
543
+ targetId: described(nullable(str(64)), 'Person for speak or message; else null.'),
544
+ text: described(nullable(str(MAX_SPOKEN)), 'Words to say or act to try; else null.'),
545
+ request: described(nullable({ type: 'object', additionalProperties: false, required: ['topic', 'priorId'],
546
+ properties: { topic: str(600), priorId: nullable(str(64)) } }), 'When your words ask someone to act: its topic, with priorId for a known request.'),
547
+ mood: described(str(40), 'Your feeling now in a few words.'),
548
+ nextPlan: described(ACTIVITY, 'What you do next, until it ends.'),
549
+ stance: described(nullable({ type: 'string', enum: ['undecided', 'cooperate', 'refuse', 'report', 'avoid', 'confront'] }), 'Where you now stand toward someone after their serious act; else null.'),
550
+ },
551
+ };
552
+ export const messageReplyResponseSchema = {
553
+ type: 'object',
554
+ additionalProperties: false,
555
+ required: ['reply', 'mood', 'trust', 'warmth', 'belief', 'plan'],
556
+ properties: {
557
+ reply: described(nullable(str(MAX_SPOKEN)), 'Your reply; null for silence.'),
558
+ mood: described(str(40), 'Your feeling now in a few words.'),
559
+ trust: described({ type: 'integer', minimum: -20, maximum: 20 }, 'Change in trust of the sender.'),
560
+ warmth: described({ type: 'integer', minimum: -20, maximum: 20 }, 'Change in warmth toward the sender.'),
561
+ belief: described(nullable({ type: 'object', additionalProperties: false, required: ['subject', 'claim'], properties: { subject: str(120), claim: str(300) } }), 'A conclusion you now hold; else null.'),
562
+ plan: described(nullable(ACTIVITY), 'A new activity you switch to; null to carry on.'),
563
+ },
564
+ };
565
+ export const epilogueResponseSchema = {
566
+ type: 'object',
567
+ additionalProperties: false,
568
+ required: ['title', 'verdict', 'highlights', 'cast', 'closing'],
569
+ properties: {
570
+ title: described(str(120), 'Short title for the ending.'),
571
+ verdict: described(str(300), 'One sentence on the outcome.'),
572
+ highlights: described({ type: 'array', minItems: 1, maxItems: 5, items: str(240) }, 'Recorded major events in order.'),
573
+ cast: described({ type: 'array', maxItems: 4, items: { type: 'object', additionalProperties: false, required: ['name', 'line'], properties: { name: str(120), line: str(200) } } }, 'Where up to four recorded people ended up.'),
574
+ closing: described(str(200), 'One final line grounded in the recorded outcome.'),
575
+ },
576
+ };