@hraness/ghostget 0.17.2

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 (500) hide show
  1. package/CHANGELOG.md +458 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1359 -0
  4. package/bunfig.toml +2 -0
  5. package/dist/apple-photos-client.js +704 -0
  6. package/dist/beeper-client.js +4602 -0
  7. package/dist/client.js +1605 -0
  8. package/dist/index-26yq8q16.js +31 -0
  9. package/dist/index-9t13b4k7.js +508 -0
  10. package/dist/index-axwm9b3v.js +5 -0
  11. package/dist/index-gwk7rbyj.js +30 -0
  12. package/dist/index.js +701 -0
  13. package/dist/messaging.js +1130 -0
  14. package/dist/omni-client.js +1406 -0
  15. package/dist/whatsapp-client.js +355 -0
  16. package/docs/imessage-direct-provider.md +106 -0
  17. package/docs/rental-listings.md +94 -0
  18. package/package.json +600 -0
  19. package/skills/ghostget/SKILL.md +251 -0
  20. package/skills/ghostget/agents/openai.yaml +4 -0
  21. package/skills/ghostget/references/adapter-contract.md +181 -0
  22. package/skills/ghostget/references/apple-photos.md +115 -0
  23. package/skills/ghostget/references/article-drafts.md +235 -0
  24. package/skills/ghostget/references/code-owned-provider-scaffold.md +134 -0
  25. package/skills/ghostget/references/cross-posting-video.md +139 -0
  26. package/skills/ghostget/references/cross-posting.md +82 -0
  27. package/skills/ghostget/references/derivation.md +390 -0
  28. package/skills/ghostget/references/hraness-social-profile-stats.json +269 -0
  29. package/skills/ghostget/references/install.md +66 -0
  30. package/skills/ghostget/references/linkedin-adapter.md +442 -0
  31. package/skills/ghostget/references/messaging.md +168 -0
  32. package/skills/ghostget/references/meta-comet-contract.md +153 -0
  33. package/skills/ghostget/references/platform-patterns.md +122 -0
  34. package/skills/ghostget/references/provider-plugins.md +496 -0
  35. package/skills/ghostget/references/reddit-flair.md +78 -0
  36. package/skills/ghostget/references/safety-and-state.md +214 -0
  37. package/skills/ghostget/references/settlement-and-duplicate-cleanup.md +79 -0
  38. package/skills/ghostget/references/social-platform-routing.md +66 -0
  39. package/skills/ghostget/references/social-profile-stats.md +195 -0
  40. package/skills/ghostget/references/social-video-platform-routing.md +89 -0
  41. package/skills/ghostget/references/whatsapp-adapter.md +101 -0
  42. package/skills/ghostget/references/x-adapter.md +332 -0
  43. package/skills/ghostget/references/x-ai-disclosure.md +71 -0
  44. package/src/apple-photos-cli.ts +639 -0
  45. package/src/apple-photos-client-types.ts +168 -0
  46. package/src/apple-photos-client.ts +201 -0
  47. package/src/apple-photos-contact-evidence.ts +838 -0
  48. package/src/apple-photos-local-source.ts +1131 -0
  49. package/src/args.ts +2053 -0
  50. package/src/article-draft-document.ts +417 -0
  51. package/src/article-draft-embeds.ts +123 -0
  52. package/src/article-draft-images.ts +214 -0
  53. package/src/assets/adapter-template/wrench-adapter.json +40 -0
  54. package/src/assets/adapters/beeper/wrench-web-adapter.json +1500 -0
  55. package/src/assets/adapters/beeper/wrench-web-adapter.v1.0.0.json +129 -0
  56. package/src/assets/adapters/beeper/wrench-web-adapter.v1.1.0.json +207 -0
  57. package/src/assets/adapters/beeper/wrench-web-adapter.v2.0.0.json +1463 -0
  58. package/src/assets/adapters/beeper/wrench-web-adapter.v2.1.0.json +1463 -0
  59. package/src/assets/adapters/beeper/wrench-web-adapter.v2.2.0.json +1475 -0
  60. package/src/assets/adapters/beeper/wrench-web-adapter.v2.3.0.json +1488 -0
  61. package/src/assets/adapters/bluesky/wrench-web-adapter.json +684 -0
  62. package/src/assets/adapters/bluesky/wrench-web-adapter.v1.0.0.json +581 -0
  63. package/src/assets/adapters/bluesky/wrench-web-adapter.v1.1.0.json +581 -0
  64. package/src/assets/adapters/bluesky/wrench-web-adapter.v1.2.0.json +581 -0
  65. package/src/assets/adapters/bluesky/wrench-web-adapter.v1.3.0.json +615 -0
  66. package/src/assets/adapters/bluesky/wrench-web-adapter.v1.4.0.json +684 -0
  67. package/src/assets/adapters/bluesky/wrench-web-adapter.v1.5.0.json +684 -0
  68. package/src/assets/adapters/bluesky/wrench-web-adapter.v1.6.0.json +684 -0
  69. package/src/assets/adapters/clasificados/wrench-web-adapter.json +54 -0
  70. package/src/assets/adapters/facebook/wrench-web-adapter.json +750 -0
  71. package/src/assets/adapters/facebook/wrench-web-adapter.v1.0.0.json +706 -0
  72. package/src/assets/adapters/facebook/wrench-web-adapter.v1.1.0.json +703 -0
  73. package/src/assets/adapters/facebook/wrench-web-adapter.v1.2.0.json +750 -0
  74. package/src/assets/adapters/facebook-group/wrench-web-adapter.json +682 -0
  75. package/src/assets/adapters/facebook-group/wrench-web-adapter.v1.0.0.json +583 -0
  76. package/src/assets/adapters/facebook-group/wrench-web-adapter.v1.1.0.json +682 -0
  77. package/src/assets/adapters/facebook-marketplace/wrench-web-adapter.json +437 -0
  78. package/src/assets/adapters/facebook-marketplace/wrench-web-adapter.v1.0.0.json +383 -0
  79. package/src/assets/adapters/facebook-marketplace/wrench-web-adapter.v1.1.0.json +437 -0
  80. package/src/assets/adapters/facebook-marketplace/wrench-web-adapter.v1.1.1.json +437 -0
  81. package/src/assets/adapters/facebook-page/wrench-web-adapter.json +880 -0
  82. package/src/assets/adapters/facebook-page/wrench-web-adapter.v1.0.0.json +740 -0
  83. package/src/assets/adapters/facebook-page/wrench-web-adapter.v1.1.0.json +880 -0
  84. package/src/assets/adapters/github/wrench-web-adapter.json +69 -0
  85. package/src/assets/adapters/github/wrench-web-adapter.v1.0.0.json +42 -0
  86. package/src/assets/adapters/github/wrench-web-adapter.v1.1.0.json +69 -0
  87. package/src/assets/adapters/gmail/wrench-adapter.json +161 -0
  88. package/src/assets/adapters/gmail/wrench-adapter.v1.2.0.json +157 -0
  89. package/src/assets/adapters/hacker-news/wrench-web-adapter.json +315 -0
  90. package/src/assets/adapters/hacker-news/wrench-web-adapter.v1.0.0.json +315 -0
  91. package/src/assets/adapters/imessage/wrench-web-adapter.json +236 -0
  92. package/src/assets/adapters/instagram/wrench-web-adapter.json +719 -0
  93. package/src/assets/adapters/instagram/wrench-web-adapter.v1.0.0.json +627 -0
  94. package/src/assets/adapters/instagram/wrench-web-adapter.v1.1.0.json +609 -0
  95. package/src/assets/adapters/instagram/wrench-web-adapter.v1.2.0.json +640 -0
  96. package/src/assets/adapters/instagram/wrench-web-adapter.v1.3.0.json +671 -0
  97. package/src/assets/adapters/instagram/wrench-web-adapter.v1.4.0.json +710 -0
  98. package/src/assets/adapters/instagram/wrench-web-adapter.v1.5.0.json +710 -0
  99. package/src/assets/adapters/instagram/wrench-web-adapter.v1.6.0.json +719 -0
  100. package/src/assets/adapters/instagram/wrench-web-adapter.v1.7.0.json +719 -0
  101. package/src/assets/adapters/linkedin/wrench-adapter.json +442 -0
  102. package/src/assets/adapters/linkedin/wrench-adapter.v0.4.0.json +124 -0
  103. package/src/assets/adapters/linkedin/wrench-adapter.v1.0.0.json +411 -0
  104. package/src/assets/adapters/linkedin/wrench-web-adapter.json +914 -0
  105. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.0.0.json +604 -0
  106. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.1.0.json +604 -0
  107. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.10.0.json +809 -0
  108. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.11.0.json +809 -0
  109. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.12.0.json +820 -0
  110. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.13.0.json +819 -0
  111. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.14.0.json +819 -0
  112. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.15.0.json +819 -0
  113. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.16.0.json +874 -0
  114. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.17.0.json +874 -0
  115. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.18.0.json +874 -0
  116. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.19.0.json +874 -0
  117. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.2.0.json +731 -0
  118. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.3.0.json +768 -0
  119. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.4.0.json +808 -0
  120. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.5.0.json +808 -0
  121. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.6.0.json +808 -0
  122. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.7.0.json +825 -0
  123. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.8.0.json +792 -0
  124. package/src/assets/adapters/linkedin/wrench-web-adapter.v1.9.0.json +809 -0
  125. package/src/assets/adapters/reddit/wrench-web-adapter.json +855 -0
  126. package/src/assets/adapters/reddit/wrench-web-adapter.v1.0.0.json +577 -0
  127. package/src/assets/adapters/reddit/wrench-web-adapter.v1.1.0.json +604 -0
  128. package/src/assets/adapters/reddit/wrench-web-adapter.v1.10.0.json +712 -0
  129. package/src/assets/adapters/reddit/wrench-web-adapter.v1.11.0.json +712 -0
  130. package/src/assets/adapters/reddit/wrench-web-adapter.v1.12.0.json +712 -0
  131. package/src/assets/adapters/reddit/wrench-web-adapter.v1.2.0.json +653 -0
  132. package/src/assets/adapters/reddit/wrench-web-adapter.v1.3.0.json +712 -0
  133. package/src/assets/adapters/reddit/wrench-web-adapter.v1.4.0.json +713 -0
  134. package/src/assets/adapters/reddit/wrench-web-adapter.v1.5.0.json +712 -0
  135. package/src/assets/adapters/reddit/wrench-web-adapter.v1.6.0.json +713 -0
  136. package/src/assets/adapters/reddit/wrench-web-adapter.v1.7.0.json +713 -0
  137. package/src/assets/adapters/reddit/wrench-web-adapter.v1.8.0.json +713 -0
  138. package/src/assets/adapters/reddit/wrench-web-adapter.v1.9.0.json +713 -0
  139. package/src/assets/adapters/substack/wrench-web-adapter.json +936 -0
  140. package/src/assets/adapters/substack/wrench-web-adapter.v1.0.0.json +817 -0
  141. package/src/assets/adapters/substack/wrench-web-adapter.v1.1.0.json +812 -0
  142. package/src/assets/adapters/substack/wrench-web-adapter.v1.2.0.json +812 -0
  143. package/src/assets/adapters/substack/wrench-web-adapter.v1.3.0.json +902 -0
  144. package/src/assets/adapters/substack/wrench-web-adapter.v1.4.0.json +936 -0
  145. package/src/assets/adapters/substack/wrench-web-adapter.v1.5.0.json +936 -0
  146. package/src/assets/adapters/substack/wrench-web-adapter.v1.6.0.json +936 -0
  147. package/src/assets/adapters/threads/wrench-web-adapter.json +692 -0
  148. package/src/assets/adapters/threads/wrench-web-adapter.v1.0.0.json +629 -0
  149. package/src/assets/adapters/threads/wrench-web-adapter.v1.1.0.json +623 -0
  150. package/src/assets/adapters/threads/wrench-web-adapter.v1.2.0.json +622 -0
  151. package/src/assets/adapters/threads/wrench-web-adapter.v1.3.0.json +622 -0
  152. package/src/assets/adapters/threads/wrench-web-adapter.v1.4.0.json +622 -0
  153. package/src/assets/adapters/threads/wrench-web-adapter.v1.5.0.json +699 -0
  154. package/src/assets/adapters/threads/wrench-web-adapter.v1.6.0.json +693 -0
  155. package/src/assets/adapters/threads/wrench-web-adapter.v1.7.0.json +692 -0
  156. package/src/assets/adapters/tiktok/wrench-web-adapter.json +762 -0
  157. package/src/assets/adapters/tiktok/wrench-web-adapter.v1.0.0.json +681 -0
  158. package/src/assets/adapters/tiktok/wrench-web-adapter.v1.1.0.json +708 -0
  159. package/src/assets/adapters/tiktok/wrench-web-adapter.v1.2.0.json +762 -0
  160. package/src/assets/adapters/tiktok/wrench-web-adapter.v1.3.0.json +762 -0
  161. package/src/assets/adapters/twitch/wrench-web-adapter.json +42 -0
  162. package/src/assets/adapters/twitch/wrench-web-adapter.v1.0.0.json +42 -0
  163. package/src/assets/adapters/whatsapp/wrench-web-adapter.json +400 -0
  164. package/src/assets/adapters/whatsapp/wrench-web-adapter.v1.0.0.json +355 -0
  165. package/src/assets/adapters/whatsapp/wrench-web-adapter.v1.1.0.json +386 -0
  166. package/src/assets/adapters/whatsapp/wrench-web-adapter.v1.2.0.json +386 -0
  167. package/src/assets/adapters/whatsapp/wrench-web-adapter.v1.3.0.json +400 -0
  168. package/src/assets/adapters/x/wrench-adapter.json +749 -0
  169. package/src/assets/adapters/x/wrench-adapter.v1.0.0.json +700 -0
  170. package/src/assets/adapters/x/wrench-adapter.v1.1.0.json +707 -0
  171. package/src/assets/adapters/x/wrench-web-adapter.json +712 -0
  172. package/src/assets/adapters/x/wrench-web-adapter.v1.1.0.json +579 -0
  173. package/src/assets/adapters/x/wrench-web-adapter.v1.10.0.json +685 -0
  174. package/src/assets/adapters/x/wrench-web-adapter.v1.11.0.json +712 -0
  175. package/src/assets/adapters/x/wrench-web-adapter.v1.12.0.json +712 -0
  176. package/src/assets/adapters/x/wrench-web-adapter.v1.13.0.json +712 -0
  177. package/src/assets/adapters/x/wrench-web-adapter.v1.2.0.json +578 -0
  178. package/src/assets/adapters/x/wrench-web-adapter.v1.3.0.json +610 -0
  179. package/src/assets/adapters/x/wrench-web-adapter.v1.4.0.json +617 -0
  180. package/src/assets/adapters/x/wrench-web-adapter.v1.5.0.json +634 -0
  181. package/src/assets/adapters/x/wrench-web-adapter.v1.6.0.json +632 -0
  182. package/src/assets/adapters/x/wrench-web-adapter.v1.7.0.json +649 -0
  183. package/src/assets/adapters/x/wrench-web-adapter.v1.8.0.json +649 -0
  184. package/src/assets/adapters/x/wrench-web-adapter.v1.9.0.json +683 -0
  185. package/src/assets/adapters/youtube/wrench-web-adapter.json +561 -0
  186. package/src/assets/adapters/youtube/wrench-web-adapter.v1.0.0.json +465 -0
  187. package/src/assets/adapters/youtube/wrench-web-adapter.v1.1.0.json +519 -0
  188. package/src/assets/adapters/youtube/wrench-web-adapter.v1.2.0.json +561 -0
  189. package/src/assets/adapters/youtube/wrench-web-adapter.v1.3.0.json +561 -0
  190. package/src/assets/code-owned-provider-template/plugin.test.ts.template +54 -0
  191. package/src/assets/code-owned-provider-template/plugin.ts.template +102 -0
  192. package/src/assets/code-owned-provider-template/runtime.internal.test.ts.template +44 -0
  193. package/src/assets/code-owned-provider-template/runtime.ts.template +59 -0
  194. package/src/assets/code-owned-provider-template/wrench-adapter.json.template +33 -0
  195. package/src/assets/fonts/nebula-sans/LICENSE.txt +96 -0
  196. package/src/assets/fonts/nebula-sans/NebulaSans-Book.woff2 +0 -0
  197. package/src/assets/fonts/nebula-sans/PROVENANCE.md +14 -0
  198. package/src/assets.d.ts +4 -0
  199. package/src/auth.ts +1157 -0
  200. package/src/beeper-client-types.ts +169 -0
  201. package/src/beeper-client.ts +250 -0
  202. package/src/beeper-contact-interactions-cli.ts +180 -0
  203. package/src/beeper-contact-interactions.ts +1612 -0
  204. package/src/beeper-message-bundle-v1.ts +257 -0
  205. package/src/beeper-message-like-me-cli.ts +84 -0
  206. package/src/beeper-message-like-me-export.ts +2274 -0
  207. package/src/beeper-message-like-me-recovery.ts +931 -0
  208. package/src/beeper-message-like-me-source.ts +4034 -0
  209. package/src/browser-admission.ts +928 -0
  210. package/src/browser-snapshots.ts +260 -0
  211. package/src/browser.ts +3873 -0
  212. package/src/canonical-json.ts +60 -0
  213. package/src/catalog-cli.ts +638 -0
  214. package/src/cli.ts +208 -0
  215. package/src/client-types.ts +301 -0
  216. package/src/client.ts +2726 -0
  217. package/src/confirmed-write-failure.ts +44 -0
  218. package/src/confirmed-write-model.ts +72 -0
  219. package/src/confirmed-write-platform.ts +1055 -0
  220. package/src/confirmed-write-program.ts +224 -0
  221. package/src/confirmed-write-runtime.ts +16 -0
  222. package/src/cursor-token.ts +228 -0
  223. package/src/derivation-dnr-readiness.ts +367 -0
  224. package/src/derivation-file-chooser.ts +384 -0
  225. package/src/derivation-network-boundary.ts +835 -0
  226. package/src/derivation-network-guard.ts +782 -0
  227. package/src/derivation-network-proxy-helper.ts +440 -0
  228. package/src/derivation-network-proxy.ts +385 -0
  229. package/src/derive-command-helper.ts +693 -0
  230. package/src/derive-fixtures.ts +343 -0
  231. package/src/derive-review.ts +980 -0
  232. package/src/derive.ts +4754 -0
  233. package/src/fixtures/beeper-message-like-me-v1/accounts.ndjson +2 -0
  234. package/src/fixtures/beeper-message-like-me-v1/conversations.ndjson +1 -0
  235. package/src/fixtures/beeper-message-like-me-v1/manifest.json +1 -0
  236. package/src/fixtures/beeper-message-like-me-v1/messages.ndjson +2 -0
  237. package/src/fixtures/beeper-message-like-me-v1/participants.ndjson +3 -0
  238. package/src/fixtures/beeper-message-like-me-v1/reactions.ndjson +1 -0
  239. package/src/fixtures/beeper-message-like-me-v1/tombstones.ndjson +1 -0
  240. package/src/ghostget.ts +3672 -0
  241. package/src/gmail-capture.ts +1244 -0
  242. package/src/har-internal.ts +1242 -0
  243. package/src/har.ts +743 -0
  244. package/src/index.ts +218 -0
  245. package/src/invocation-read-platform.ts +55 -0
  246. package/src/invocation-read-program.ts +93 -0
  247. package/src/invocation-read-runtime.ts +11 -0
  248. package/src/linked-device-lifecycle-admission.ts +450 -0
  249. package/src/linked-device-lifecycle-journal.ts +1560 -0
  250. package/src/linked-device-lifecycle-runtime.ts +1602 -0
  251. package/src/local-cli-admission.ts +135 -0
  252. package/src/local-cli-contracts.ts +271 -0
  253. package/src/local-cli-execution.ts +98 -0
  254. package/src/local-cli-surface-contract.ts +1510 -0
  255. package/src/local-cli-tool-identity.ts +336 -0
  256. package/src/media/archive.ts +2325 -0
  257. package/src/media/args.ts +303 -0
  258. package/src/media/cli.ts +287 -0
  259. package/src/media/doctor.ts +475 -0
  260. package/src/media/ffmpeg.ts +1330 -0
  261. package/src/media/http-capture.ts +711 -0
  262. package/src/media/http-probe.ts +593 -0
  263. package/src/media/http.ts +387 -0
  264. package/src/media/index.ts +10 -0
  265. package/src/media/local-transcription.ts +613 -0
  266. package/src/media/lock.ts +321 -0
  267. package/src/media/manifest.ts +1712 -0
  268. package/src/media/metadata.ts +906 -0
  269. package/src/media/process.ts +723 -0
  270. package/src/media/revision.ts +166 -0
  271. package/src/media/runtime-closure.ts +1063 -0
  272. package/src/media/source-router.ts +187 -0
  273. package/src/media/transcriber-config.ts +1122 -0
  274. package/src/media/transcript-persistence-model.ts +15 -0
  275. package/src/media/transcript-persistence-platform.ts +89 -0
  276. package/src/media/transcript-persistence-program.ts +39 -0
  277. package/src/media/transcript-persistence-runtime.ts +24 -0
  278. package/src/media/transcript.ts +616 -0
  279. package/src/media/utf8-order.ts +30 -0
  280. package/src/media/whisper-cpp.ts +464 -0
  281. package/src/media/whisper-language.ts +58 -0
  282. package/src/media/yt-dlp.ts +439 -0
  283. package/src/message-like-me-agentic-messaging.ts +882 -0
  284. package/src/messaging-action-store.ts +793 -0
  285. package/src/messaging-runtime.ts +2136 -0
  286. package/src/messaging-store.ts +539 -0
  287. package/src/messaging-types.ts +1663 -0
  288. package/src/messaging.ts +334 -0
  289. package/src/model.ts +2671 -0
  290. package/src/oauth-google.ts +888 -0
  291. package/src/omni-client-types.ts +306 -0
  292. package/src/omni-client.ts +2225 -0
  293. package/src/omni-limits.ts +34 -0
  294. package/src/omni-model.ts +1614 -0
  295. package/src/omni-request.ts +379 -0
  296. package/src/omni-runtime.ts +1632 -0
  297. package/src/operation-deadline.ts +189 -0
  298. package/src/path-helper.ts +1656 -0
  299. package/src/pinned-https.ts +194 -0
  300. package/src/plan-assets.ts +832 -0
  301. package/src/platform-catalog.ts +1832 -0
  302. package/src/plugins/beeper-linked-device/plugin.ts +310 -0
  303. package/src/plugins/bluesky-web/plugin.ts +178 -0
  304. package/src/plugins/clasificados-web/plugin.ts +66 -0
  305. package/src/plugins/github-web/plugin.ts +80 -0
  306. package/src/plugins/gmail-official/plugin.ts +110 -0
  307. package/src/plugins/hacker-news-web/plugin.ts +52 -0
  308. package/src/plugins/imessage-direct/plugin.ts +195 -0
  309. package/src/plugins/imessage-direct/vendor/0001-fix-keep-AppleScript-send-payloads-out-of-child-argv.patch +1430 -0
  310. package/src/plugins/imessage-direct/vendor/0002-feat-rpc-add-exact-chat-lookup.patch +225 -0
  311. package/src/plugins/imessage-direct/vendor/provenance.json +80 -0
  312. package/src/plugins/linkedin-official/plugin.ts +84 -0
  313. package/src/plugins/linkedin-web/plugin.ts +412 -0
  314. package/src/plugins/meta-web/plugin.ts +317 -0
  315. package/src/plugins/reddit-web/flair.ts +492 -0
  316. package/src/plugins/reddit-web/plugin.ts +477 -0
  317. package/src/plugins/substack-web/plugin.ts +124 -0
  318. package/src/plugins/tiktok-web/plugin.ts +67 -0
  319. package/src/plugins/twitch-web/plugin.ts +54 -0
  320. package/src/plugins/whatsapp-linked-device/plugin.ts +105 -0
  321. package/src/plugins/x-official/plugin.ts +64 -0
  322. package/src/plugins/x-web/plugin.ts +488 -0
  323. package/src/plugins/youtube-web/plugin.ts +101 -0
  324. package/src/portable-run-recovery.ts +466 -0
  325. package/src/process-identity.ts +501 -0
  326. package/src/profile-clone-helper.ts +104 -0
  327. package/src/provider-catalog-views.ts +51 -0
  328. package/src/provider-context.ts +69 -0
  329. package/src/provider-contract-definitions-x.ts +45 -0
  330. package/src/provider-contract-definitions.ts +948 -0
  331. package/src/provider-contract-input-gmail.ts +176 -0
  332. package/src/provider-contract-input-linkedin.ts +77 -0
  333. package/src/provider-contract-input-x.ts +304 -0
  334. package/src/provider-contract-planning.ts +23 -0
  335. package/src/provider-contract-semantic-identity.ts +54 -0
  336. package/src/provider-contracts.ts +251 -0
  337. package/src/provider-http.ts +723 -0
  338. package/src/provider-plugin-auth.ts +36 -0
  339. package/src/provider-plugin-builtins.ts +229 -0
  340. package/src/provider-plugin-cleanup-barrier.ts +229 -0
  341. package/src/provider-plugin-cleanup-execution.ts +79 -0
  342. package/src/provider-plugin-cleanup-resource.ts +470 -0
  343. package/src/provider-plugin-contract-identity.ts +707 -0
  344. package/src/provider-plugin-host.ts +1972 -0
  345. package/src/provider-plugin-identifiers.ts +60 -0
  346. package/src/provider-plugin-invocation-lease.ts +889 -0
  347. package/src/provider-plugin-lifecycle-kernel.ts +566 -0
  348. package/src/provider-plugin-lifecycle.ts +1455 -0
  349. package/src/provider-plugin-module-analysis.ts +336 -0
  350. package/src/provider-plugin-package.ts +2530 -0
  351. package/src/provider-plugin-portable-authority.ts +106 -0
  352. package/src/provider-plugin-portable-catalog.ts +94 -0
  353. package/src/provider-plugin-portable-identity.ts +315 -0
  354. package/src/provider-plugin-portable-runtime.ts +2057 -0
  355. package/src/provider-plugin-protocol.ts +1625 -0
  356. package/src/provider-plugin-registry.ts +3342 -0
  357. package/src/provider-plugin-store.ts +2155 -0
  358. package/src/provider-plugin-test-fixture.ts +5 -0
  359. package/src/provider-plugin.ts +4907 -0
  360. package/src/provider-plugins.generated.ts +43 -0
  361. package/src/provider-plugins.ts +8 -0
  362. package/src/provider-subject.ts +41 -0
  363. package/src/provider.ts +315 -0
  364. package/src/providers/beeper-local-runtime.ts +5426 -0
  365. package/src/providers/beeper-local.ts +2739 -0
  366. package/src/providers/beeper-messaging.ts +462 -0
  367. package/src/providers/beeper-omni.ts +1159 -0
  368. package/src/providers/bluesky-web-runtime.ts +2895 -0
  369. package/src/providers/bluesky-web.ts +1614 -0
  370. package/src/providers/clasificados-web-runtime.ts +255 -0
  371. package/src/providers/clasificados-web.ts +503 -0
  372. package/src/providers/contact-projection.ts +301 -0
  373. package/src/providers/github-read-model.ts +94 -0
  374. package/src/providers/github-read-platform.ts +165 -0
  375. package/src/providers/github-read-program.ts +97 -0
  376. package/src/providers/github-web-runtime.ts +320 -0
  377. package/src/providers/github-web.ts +403 -0
  378. package/src/providers/gmail-api.ts +2834 -0
  379. package/src/providers/gmail-omni.ts +830 -0
  380. package/src/providers/gmail.ts +1130 -0
  381. package/src/providers/hacker-news-web-runtime.ts +220 -0
  382. package/src/providers/hacker-news-web.ts +809 -0
  383. package/src/providers/imessage-direct-install.ts +354 -0
  384. package/src/providers/imessage-direct-messaging.ts +532 -0
  385. package/src/providers/imessage-direct-omni.ts +400 -0
  386. package/src/providers/imessage-direct-runtime.ts +1498 -0
  387. package/src/providers/imessage-direct.ts +351 -0
  388. package/src/providers/instagram-video-foundations.ts +913 -0
  389. package/src/providers/instagram-web-profile-browser.ts +600 -0
  390. package/src/providers/iso-bmff.ts +338 -0
  391. package/src/providers/linkedin-company-platform.ts +42 -0
  392. package/src/providers/linkedin-company-program.ts +88 -0
  393. package/src/providers/linkedin-contact-failure.ts +84 -0
  394. package/src/providers/linkedin-contact-platform.ts +45 -0
  395. package/src/providers/linkedin-contact-program.ts +91 -0
  396. package/src/providers/linkedin-profile-activity-failure.ts +76 -0
  397. package/src/providers/linkedin-profile-activity-platform.ts +41 -0
  398. package/src/providers/linkedin-profile-activity-program.ts +67 -0
  399. package/src/providers/linkedin-read-failure.ts +52 -0
  400. package/src/providers/linkedin-self-platform.ts +53 -0
  401. package/src/providers/linkedin-self-program.ts +122 -0
  402. package/src/providers/linkedin-web-article-browser.ts +794 -0
  403. package/src/providers/linkedin-web-bootstrap.ts +146 -0
  404. package/src/providers/linkedin-web-contact.ts +830 -0
  405. package/src/providers/linkedin-web-feed-browser.ts +832 -0
  406. package/src/providers/linkedin-web-feed.ts +864 -0
  407. package/src/providers/linkedin-web-post-browser.ts +653 -0
  408. package/src/providers/linkedin-web-profile-browser.ts +683 -0
  409. package/src/providers/linkedin-web-runtime.ts +2388 -0
  410. package/src/providers/linkedin-web.ts +3305 -0
  411. package/src/providers/linkedin.ts +1885 -0
  412. package/src/providers/meta-bootstrap.ts +1043 -0
  413. package/src/providers/meta-facebook-group.ts +690 -0
  414. package/src/providers/meta-marketplace-relay.ts +747 -0
  415. package/src/providers/meta-omni.ts +373 -0
  416. package/src/providers/meta-relay-bundle.ts +1049 -0
  417. package/src/providers/meta-web-descriptors.ts +1740 -0
  418. package/src/providers/meta-web-runtime.ts +3388 -0
  419. package/src/providers/meta-web.ts +2931 -0
  420. package/src/providers/read-failure.ts +139 -0
  421. package/src/providers/reddit-omni.ts +462 -0
  422. package/src/providers/reddit-web-runtime.ts +1929 -0
  423. package/src/providers/reddit-web.ts +1611 -0
  424. package/src/providers/rental-listings.ts +460 -0
  425. package/src/providers/substack-omni.ts +406 -0
  426. package/src/providers/substack-video-mp4.ts +33 -0
  427. package/src/providers/substack-web-runtime.ts +2812 -0
  428. package/src/providers/substack-web.ts +1502 -0
  429. package/src/providers/tiktok-video-mp4.ts +33 -0
  430. package/src/providers/tiktok-web-runtime.ts +770 -0
  431. package/src/providers/tiktok-web.ts +2786 -0
  432. package/src/providers/twitch-web-runtime.ts +226 -0
  433. package/src/providers/twitch-web.ts +274 -0
  434. package/src/providers/whatsapp-account-identity.ts +55 -0
  435. package/src/providers/whatsapp-contact-projection-helper.ts +874 -0
  436. package/src/providers/whatsapp-contact-projection-protocol.ts +403 -0
  437. package/src/providers/whatsapp-interaction-projection-helper.ts +1452 -0
  438. package/src/providers/whatsapp-interaction-projection-protocol.ts +462 -0
  439. package/src/providers/whatsapp-message-export-projection-protocol.ts +532 -0
  440. package/src/providers/whatsapp-messaging.ts +132 -0
  441. package/src/providers/whatsapp-omni.ts +586 -0
  442. package/src/providers/whatsapp-web-runtime.ts +3108 -0
  443. package/src/providers/whatsapp-web.ts +1037 -0
  444. package/src/providers/x-image-provenance.ts +523 -0
  445. package/src/providers/x-made-with-ai.ts +106 -0
  446. package/src/providers/x-transaction-id.ts +413 -0
  447. package/src/providers/x-web-runtime.ts +3485 -0
  448. package/src/providers/x-web.ts +2332 -0
  449. package/src/providers/x.ts +1889 -0
  450. package/src/providers/youtube-web-runtime.ts +1400 -0
  451. package/src/providers/youtube-web.ts +1221 -0
  452. package/src/read-admission-runtime.ts +91 -0
  453. package/src/read-client.ts +521 -0
  454. package/src/read-effect-platform.ts +7 -0
  455. package/src/read-effect-runtime.ts +14 -0
  456. package/src/read-effect.ts +52 -0
  457. package/src/read-projection-admission.ts +866 -0
  458. package/src/read-projections.ts +3151 -0
  459. package/src/recovery.ts +1492 -0
  460. package/src/reviewed-template.ts +146 -0
  461. package/src/run-journal.ts +1272 -0
  462. package/src/runtime.ts +5116 -0
  463. package/src/scripts/generate-provider-plugin-catalog.ts +121 -0
  464. package/src/scripts/install-whatsapp-protocol.sh +232 -0
  465. package/src/scripts/recover-install-stages.ts +1491 -0
  466. package/src/scripts/resolve-state-home.ts +30 -0
  467. package/src/scripts/scaffold-web-provider.ts +973 -0
  468. package/src/scripts/sync-bundled-adapters.ts +695 -0
  469. package/src/session-secrets.ts +1183 -0
  470. package/src/state-helper.bunfig.toml +2 -0
  471. package/src/state-helper.ts +2914 -0
  472. package/src/storage.ts +3842 -0
  473. package/src/transport-policy.ts +2 -0
  474. package/src/usage.ts +182 -0
  475. package/src/version.ts +2 -0
  476. package/src/web-session-authentication-policy.ts +136 -0
  477. package/src/web-session-cleanup-admission.ts +2344 -0
  478. package/src/web-session-cleanup-join.ts +99 -0
  479. package/src/web-session-client.ts +996 -0
  480. package/src/web-session-contract-definitions.ts +820 -0
  481. package/src/web-session-contract-planning.ts +42 -0
  482. package/src/web-session-contracts.ts +228 -0
  483. package/src/web-session-cookies.ts +500 -0
  484. package/src/web-session-execution.ts +385 -0
  485. package/src/web-session-http.ts +373 -0
  486. package/src/web-session-read-errors.ts +19 -0
  487. package/src/web-session-read-runtime.ts +124 -0
  488. package/src/web-session-recovery.ts +818 -0
  489. package/src/web-session-sites.ts +58 -0
  490. package/src/web-session-template.ts +994 -0
  491. package/src/web-session.ts +93 -0
  492. package/src/whatsapp-client-binding.ts +21 -0
  493. package/src/whatsapp-client-types.ts +75 -0
  494. package/src/whatsapp-client.ts +395 -0
  495. package/src/whatsapp-export-coordinate.ts +17 -0
  496. package/src/whatsapp-message-bundle-v2.ts +195 -0
  497. package/src/whatsapp-message-like-me-cli.ts +195 -0
  498. package/src/whatsapp-message-like-me-export.ts +1072 -0
  499. package/src/whatsapp-message-like-me-source.ts +1012 -0
  500. package/tsconfig.json +67 -0
@@ -0,0 +1,4602 @@
1
+ // @bun
2
+ import {
3
+ isProviderPluginOperationName
4
+ } from "./index-26yq8q16.js";
5
+ import {
6
+ GHOSTGET_VERSION
7
+ } from "./index-axwm9b3v.js";
8
+ import {
9
+ canonicalJson,
10
+ sha256
11
+ } from "./index-gwk7rbyj.js";
12
+
13
+ // src/beeper-client.ts
14
+ import { spawnSync } from "child_process";
15
+ import { existsSync } from "fs";
16
+ import { fileURLToPath } from "url";
17
+ import { types as nodeTypes3 } from "util";
18
+
19
+ // src/beeper-contact-interactions.ts
20
+ import { types as nodeTypes2 } from "util";
21
+ import {
22
+ LOCAL_MESSAGE_BUNDLE_V1_LIMITS,
23
+ LOCAL_MESSAGE_BUNDLE_V1_SOURCE_TRANSFORM_VERSION
24
+ } from "@hraness/message-like-me/message-bundle-v1";
25
+ // src/assets/adapters/beeper/wrench-web-adapter.json
26
+ var wrench_web_adapter_default = {
27
+ schemaVersion: 6,
28
+ id: "beeper-local",
29
+ version: "2.4.0",
30
+ displayName: "Beeper (Pinned Local CLI)",
31
+ surfaceId: "beeper",
32
+ origins: [
33
+ "https://www.beeper.com"
34
+ ],
35
+ browserDomains: [
36
+ "www.beeper.com"
37
+ ],
38
+ operations: {
39
+ "accounts.list": {
40
+ description: "List the exact account realm bound to the fixed local Beeper Desktop target.",
41
+ risk: "R1",
42
+ sideEffect: "none",
43
+ idempotency: "none",
44
+ dedupeWindowMs: 0,
45
+ input: {
46
+ properties: {},
47
+ required: []
48
+ },
49
+ localCli: {
50
+ surface: "beeper",
51
+ action: "accounts.list",
52
+ contractVersion: 2,
53
+ timeoutMs: 120000,
54
+ maxOutputBytes: 10485760
55
+ }
56
+ },
57
+ "accounts.read": {
58
+ description: "Read one exact connected Beeper account.",
59
+ risk: "R1",
60
+ sideEffect: "none",
61
+ idempotency: "none",
62
+ dedupeWindowMs: 0,
63
+ input: {
64
+ properties: {
65
+ account_id: {
66
+ type: "string",
67
+ description: "Exact Beeper account ID returned by this adapter",
68
+ minLength: 1,
69
+ maxLength: 512
70
+ }
71
+ },
72
+ required: [
73
+ "account_id"
74
+ ]
75
+ },
76
+ localCli: {
77
+ surface: "beeper",
78
+ action: "accounts.read",
79
+ contractVersion: 1,
80
+ timeoutMs: 120000,
81
+ maxOutputBytes: 10485760
82
+ }
83
+ },
84
+ "bridges.list": {
85
+ description: "List one bounded, secret-free bridge capability catalog.",
86
+ risk: "R1",
87
+ sideEffect: "none",
88
+ idempotency: "none",
89
+ dedupeWindowMs: 0,
90
+ input: {
91
+ properties: {
92
+ provider: {
93
+ type: "string",
94
+ description: "Optional exact bridge provider class",
95
+ minLength: 1,
96
+ maxLength: 32,
97
+ enum: [
98
+ "local",
99
+ "cloud",
100
+ "self-hosted",
101
+ "platform-sdk"
102
+ ]
103
+ },
104
+ available: {
105
+ type: "boolean",
106
+ description: "Optionally require current availability"
107
+ },
108
+ limit: {
109
+ type: "number",
110
+ description: "Maximum projected bridges",
111
+ minimum: 1,
112
+ maximum: 128
113
+ }
114
+ },
115
+ required: []
116
+ },
117
+ localCli: {
118
+ surface: "beeper",
119
+ action: "bridges.list",
120
+ contractVersion: 2,
121
+ timeoutMs: 120000,
122
+ maxOutputBytes: 10485760
123
+ }
124
+ },
125
+ "bridges.read": {
126
+ description: "Read one exact bridge and its secret-free capabilities.",
127
+ risk: "R1",
128
+ sideEffect: "none",
129
+ idempotency: "none",
130
+ dedupeWindowMs: 0,
131
+ input: {
132
+ properties: {
133
+ bridge_id: {
134
+ type: "string",
135
+ description: "Exact bridge ID returned by this adapter",
136
+ minLength: 1,
137
+ maxLength: 512
138
+ }
139
+ },
140
+ required: [
141
+ "bridge_id"
142
+ ]
143
+ },
144
+ localCli: {
145
+ surface: "beeper",
146
+ action: "bridges.read",
147
+ contractVersion: 1,
148
+ timeoutMs: 120000,
149
+ maxOutputBytes: 10485760
150
+ }
151
+ },
152
+ "contacts.list": {
153
+ description: "List one bounded account-aware contact projection through Desktop contact pages.",
154
+ risk: "R1",
155
+ sideEffect: "none",
156
+ idempotency: "none",
157
+ dedupeWindowMs: 0,
158
+ input: {
159
+ properties: {
160
+ account_id: {
161
+ type: "string",
162
+ description: "Exact Beeper account ID returned by this adapter",
163
+ minLength: 1,
164
+ maxLength: 512
165
+ },
166
+ query: {
167
+ type: "string",
168
+ description: "Optional normalized provider contact-lookup query of at most 256 UTF-8 bytes",
169
+ minLength: 1,
170
+ maxLength: 256
171
+ },
172
+ before_cursor: {
173
+ type: "string",
174
+ description: "Exact opaque provider cursor returned by a prior older-results page",
175
+ minLength: 1,
176
+ maxLength: 2048
177
+ },
178
+ after_cursor: {
179
+ type: "string",
180
+ description: "Exact opaque provider cursor returned by a prior newer-results page",
181
+ minLength: 1,
182
+ maxLength: 2048
183
+ },
184
+ limit: {
185
+ type: "number",
186
+ description: "Maximum projected contacts",
187
+ minimum: 1,
188
+ maximum: 200
189
+ }
190
+ },
191
+ required: []
192
+ },
193
+ localCli: {
194
+ surface: "beeper",
195
+ action: "contacts.list",
196
+ contractVersion: 3,
197
+ timeoutMs: 120000,
198
+ maxOutputBytes: 10485760
199
+ }
200
+ },
201
+ "contacts.search": {
202
+ description: "Search one bounded contact candidate window.",
203
+ risk: "R1",
204
+ sideEffect: "none",
205
+ idempotency: "none",
206
+ dedupeWindowMs: 0,
207
+ input: {
208
+ properties: {
209
+ query: {
210
+ type: "string",
211
+ description: "Normalized bounded contact lookup text",
212
+ minLength: 1,
213
+ maxLength: 256
214
+ },
215
+ account_id: {
216
+ type: "string",
217
+ description: "Exact Beeper account ID returned by this adapter",
218
+ minLength: 1,
219
+ maxLength: 512
220
+ },
221
+ limit: {
222
+ type: "number",
223
+ description: "Maximum candidate contacts",
224
+ minimum: 1,
225
+ maximum: 20
226
+ }
227
+ },
228
+ required: [
229
+ "query"
230
+ ]
231
+ },
232
+ localCli: {
233
+ surface: "beeper",
234
+ action: "contacts.search",
235
+ contractVersion: 1,
236
+ timeoutMs: 120000,
237
+ maxOutputBytes: 10485760
238
+ }
239
+ },
240
+ "contacts.read": {
241
+ description: "Read one exact account-bound contact identity.",
242
+ risk: "R1",
243
+ sideEffect: "none",
244
+ idempotency: "none",
245
+ dedupeWindowMs: 0,
246
+ input: {
247
+ properties: {
248
+ account_id: {
249
+ type: "string",
250
+ description: "Exact Beeper account ID returned by this adapter",
251
+ minLength: 1,
252
+ maxLength: 512
253
+ },
254
+ contact_id: {
255
+ type: "string",
256
+ description: "Exact contact ID returned by this adapter",
257
+ minLength: 1,
258
+ maxLength: 2048
259
+ }
260
+ },
261
+ required: [
262
+ "account_id",
263
+ "contact_id"
264
+ ]
265
+ },
266
+ localCli: {
267
+ surface: "beeper",
268
+ action: "contacts.read",
269
+ contractVersion: 1,
270
+ timeoutMs: 120000,
271
+ maxOutputBytes: 10485760
272
+ }
273
+ },
274
+ "messaging.list": {
275
+ description: "List one bounded account-aware conversation projection.",
276
+ risk: "R1",
277
+ sideEffect: "none",
278
+ idempotency: "none",
279
+ dedupeWindowMs: 0,
280
+ input: {
281
+ properties: {
282
+ account_id: {
283
+ type: "string",
284
+ description: "Exact Beeper account ID returned by this adapter",
285
+ minLength: 1,
286
+ maxLength: 512
287
+ },
288
+ limit: {
289
+ type: "number",
290
+ description: "Maximum projected conversations",
291
+ minimum: 1,
292
+ maximum: 200
293
+ },
294
+ archived: {
295
+ type: "boolean",
296
+ description: "Filter by archived state"
297
+ },
298
+ pinned: {
299
+ type: "boolean",
300
+ description: "Filter by pinned state"
301
+ },
302
+ muted: {
303
+ type: "boolean",
304
+ description: "Filter by muted state"
305
+ },
306
+ unread: {
307
+ type: "boolean",
308
+ description: "Filter by unread state"
309
+ },
310
+ low_priority: {
311
+ type: "boolean",
312
+ description: "Filter by low-priority state"
313
+ }
314
+ },
315
+ required: []
316
+ },
317
+ localCli: {
318
+ surface: "beeper",
319
+ action: "messaging.list",
320
+ contractVersion: 1,
321
+ timeoutMs: 120000,
322
+ maxOutputBytes: 10485760
323
+ }
324
+ },
325
+ "messaging.search": {
326
+ description: "Search one bounded conversation candidate window.",
327
+ risk: "R1",
328
+ sideEffect: "none",
329
+ idempotency: "none",
330
+ dedupeWindowMs: 0,
331
+ input: {
332
+ properties: {
333
+ query: {
334
+ type: "string",
335
+ description: "Normalized bounded conversation lookup text",
336
+ minLength: 1,
337
+ maxLength: 256
338
+ },
339
+ account_id: {
340
+ type: "string",
341
+ description: "Exact Beeper account ID returned by this adapter",
342
+ minLength: 1,
343
+ maxLength: 512
344
+ },
345
+ limit: {
346
+ type: "number",
347
+ description: "Maximum candidate conversations",
348
+ minimum: 1,
349
+ maximum: 20
350
+ }
351
+ },
352
+ required: [
353
+ "query"
354
+ ]
355
+ },
356
+ localCli: {
357
+ surface: "beeper",
358
+ action: "messaging.search",
359
+ contractVersion: 2,
360
+ timeoutMs: 120000,
361
+ maxOutputBytes: 10485760
362
+ }
363
+ },
364
+ "conversations.read": {
365
+ description: "Read one exact account-bound conversation.",
366
+ risk: "R1",
367
+ sideEffect: "none",
368
+ idempotency: "none",
369
+ dedupeWindowMs: 0,
370
+ input: {
371
+ properties: {
372
+ account_id: {
373
+ type: "string",
374
+ description: "Exact Beeper account ID returned by this adapter",
375
+ minLength: 1,
376
+ maxLength: 512
377
+ },
378
+ conversation_id: {
379
+ type: "string",
380
+ description: "Canonical full Beeper/Matrix chat ID returned by this adapter",
381
+ minLength: 3,
382
+ maxLength: 2048
383
+ },
384
+ max_participants: {
385
+ type: "number",
386
+ description: "Maximum projected participants",
387
+ minimum: 1,
388
+ maximum: 500
389
+ }
390
+ },
391
+ required: [
392
+ "account_id",
393
+ "conversation_id"
394
+ ]
395
+ },
396
+ localCli: {
397
+ surface: "beeper",
398
+ action: "conversations.read",
399
+ contractVersion: 2,
400
+ timeoutMs: 120000,
401
+ maxOutputBytes: 10485760
402
+ }
403
+ },
404
+ "messaging.read": {
405
+ description: "Read one bounded page from one exact conversation.",
406
+ risk: "R1",
407
+ sideEffect: "none",
408
+ idempotency: "none",
409
+ dedupeWindowMs: 0,
410
+ input: {
411
+ properties: {
412
+ account_id: {
413
+ type: "string",
414
+ description: "Exact Beeper account ID returned by this adapter",
415
+ minLength: 1,
416
+ maxLength: 512
417
+ },
418
+ conversation_id: {
419
+ type: "string",
420
+ description: "Canonical full Beeper/Matrix chat ID returned by this adapter",
421
+ minLength: 3,
422
+ maxLength: 2048
423
+ },
424
+ before_cursor: {
425
+ type: "string",
426
+ description: "Exact opaque provider cursor returned by a prior page",
427
+ minLength: 1,
428
+ maxLength: 2048
429
+ },
430
+ after_cursor: {
431
+ type: "string",
432
+ description: "Exact opaque provider cursor returned by a prior page",
433
+ minLength: 1,
434
+ maxLength: 2048
435
+ },
436
+ sender: {
437
+ type: "string",
438
+ description: "Exact sender filter: me, others, or one bounded opaque provider user ID",
439
+ minLength: 1,
440
+ maxLength: 2048
441
+ },
442
+ limit: {
443
+ type: "number",
444
+ description: "Maximum projected messages",
445
+ minimum: 1,
446
+ maximum: 200
447
+ }
448
+ },
449
+ required: [
450
+ "account_id",
451
+ "conversation_id"
452
+ ]
453
+ },
454
+ localCli: {
455
+ surface: "beeper",
456
+ action: "messaging.read",
457
+ contractVersion: 3,
458
+ timeoutMs: 120000,
459
+ maxOutputBytes: 10485760
460
+ }
461
+ },
462
+ "messaging.content.search": {
463
+ description: "Search and paginate one bounded message-content candidate window through the exact local provider index.",
464
+ risk: "R1",
465
+ sideEffect: "none",
466
+ idempotency: "none",
467
+ dedupeWindowMs: 0,
468
+ input: {
469
+ properties: {
470
+ query: {
471
+ type: "string",
472
+ description: "Normalized bounded message lookup text",
473
+ minLength: 1,
474
+ maxLength: 256
475
+ },
476
+ account_id: {
477
+ type: "string",
478
+ description: "Exact Beeper account ID returned by this adapter",
479
+ minLength: 1,
480
+ maxLength: 512
481
+ },
482
+ conversation_id: {
483
+ type: "string",
484
+ description: "Canonical full Beeper/Matrix chat ID returned by this adapter",
485
+ minLength: 3,
486
+ maxLength: 2048
487
+ },
488
+ chat_type: {
489
+ type: "string",
490
+ description: "Exact chat type filter",
491
+ minLength: 1,
492
+ maxLength: 16,
493
+ enum: [
494
+ "group",
495
+ "single"
496
+ ]
497
+ },
498
+ after: {
499
+ type: "string",
500
+ description: "Canonical UTC ISO timestamp",
501
+ minLength: 20,
502
+ maxLength: 64
503
+ },
504
+ before: {
505
+ type: "string",
506
+ description: "Canonical UTC ISO timestamp",
507
+ minLength: 20,
508
+ maxLength: 64
509
+ },
510
+ before_cursor: {
511
+ type: "string",
512
+ description: "Exact opaque provider cursor returned by a prior older-results page",
513
+ minLength: 1,
514
+ maxLength: 2048
515
+ },
516
+ after_cursor: {
517
+ type: "string",
518
+ description: "Exact opaque provider cursor returned by a prior newer-results page",
519
+ minLength: 1,
520
+ maxLength: 2048
521
+ },
522
+ exclude_low_priority: {
523
+ type: "boolean",
524
+ description: "Exclude low-priority chats"
525
+ },
526
+ include_muted: {
527
+ type: "boolean",
528
+ description: "Include muted chats"
529
+ },
530
+ media: {
531
+ type: "array",
532
+ description: "Exact media-kind filters",
533
+ items: {
534
+ type: "string",
535
+ description: "One exact media kind",
536
+ minLength: 1,
537
+ maxLength: 16,
538
+ enum: [
539
+ "any",
540
+ "video",
541
+ "image",
542
+ "link",
543
+ "file"
544
+ ]
545
+ },
546
+ minItems: 0,
547
+ maxItems: 5
548
+ },
549
+ sender: {
550
+ type: "string",
551
+ description: "Exact sender selector returned by this adapter",
552
+ minLength: 1,
553
+ maxLength: 2048
554
+ },
555
+ limit: {
556
+ type: "number",
557
+ description: "Maximum projected message candidates",
558
+ minimum: 1,
559
+ maximum: 200
560
+ }
561
+ },
562
+ required: []
563
+ },
564
+ localCli: {
565
+ surface: "beeper",
566
+ action: "messaging.content.search",
567
+ contractVersion: 2,
568
+ timeoutMs: 120000,
569
+ maxOutputBytes: 10485760
570
+ }
571
+ },
572
+ "messaging.message.read": {
573
+ description: "Read one exact message from one exact conversation.",
574
+ risk: "R1",
575
+ sideEffect: "none",
576
+ idempotency: "none",
577
+ dedupeWindowMs: 0,
578
+ input: {
579
+ properties: {
580
+ account_id: {
581
+ type: "string",
582
+ description: "Exact Beeper account ID returned by this adapter",
583
+ minLength: 1,
584
+ maxLength: 512
585
+ },
586
+ conversation_id: {
587
+ type: "string",
588
+ description: "Canonical full Beeper/Matrix chat ID returned by this adapter",
589
+ minLength: 3,
590
+ maxLength: 2048
591
+ },
592
+ message_id: {
593
+ type: "string",
594
+ description: "Exact message ID returned by this adapter",
595
+ minLength: 1,
596
+ maxLength: 2048
597
+ }
598
+ },
599
+ required: [
600
+ "account_id",
601
+ "conversation_id",
602
+ "message_id"
603
+ ]
604
+ },
605
+ localCli: {
606
+ surface: "beeper",
607
+ action: "messaging.message.read",
608
+ contractVersion: 1,
609
+ timeoutMs: 120000,
610
+ maxOutputBytes: 10485760
611
+ }
612
+ },
613
+ "messaging.context.read": {
614
+ description: "Read bounded context around one exact message.",
615
+ risk: "R1",
616
+ sideEffect: "none",
617
+ idempotency: "none",
618
+ dedupeWindowMs: 0,
619
+ input: {
620
+ properties: {
621
+ account_id: {
622
+ type: "string",
623
+ description: "Exact Beeper account ID returned by this adapter",
624
+ minLength: 1,
625
+ maxLength: 512
626
+ },
627
+ conversation_id: {
628
+ type: "string",
629
+ description: "Canonical full Beeper/Matrix chat ID returned by this adapter",
630
+ minLength: 3,
631
+ maxLength: 2048
632
+ },
633
+ message_id: {
634
+ type: "string",
635
+ description: "Exact message ID returned by this adapter",
636
+ minLength: 1,
637
+ maxLength: 2048
638
+ },
639
+ before: {
640
+ type: "number",
641
+ description: "Messages before the exact target",
642
+ minimum: 0,
643
+ maximum: 100
644
+ },
645
+ after: {
646
+ type: "number",
647
+ description: "Messages after the exact target",
648
+ minimum: 0,
649
+ maximum: 100
650
+ }
651
+ },
652
+ required: [
653
+ "account_id",
654
+ "conversation_id",
655
+ "message_id"
656
+ ]
657
+ },
658
+ localCli: {
659
+ surface: "beeper",
660
+ action: "messaging.context.read",
661
+ contractVersion: 1,
662
+ timeoutMs: 120000,
663
+ maxOutputBytes: 10485760
664
+ }
665
+ },
666
+ "messaging.send": {
667
+ description: "Submit one confirmed text, file, sticker, or voice request to Beeper Desktop; network delivery is not asserted.",
668
+ risk: "R3",
669
+ sideEffect: "externally visible provider or Desktop mutation",
670
+ idempotency: "local-at-most-once",
671
+ dedupeWindowMs: 86400000,
672
+ input: {
673
+ properties: {
674
+ account_id: {
675
+ type: "string",
676
+ description: "Exact Beeper account ID returned by this adapter",
677
+ minLength: 1,
678
+ maxLength: 512
679
+ },
680
+ conversation_id: {
681
+ type: "string",
682
+ description: "Canonical full Beeper/Matrix chat ID returned by this adapter",
683
+ minLength: 3,
684
+ maxLength: 2048
685
+ },
686
+ kind: {
687
+ type: "string",
688
+ description: "Exact bounded send kind",
689
+ minLength: 1,
690
+ maxLength: 16,
691
+ enum: [
692
+ "text",
693
+ "file",
694
+ "sticker",
695
+ "voice"
696
+ ]
697
+ },
698
+ text: {
699
+ type: "string",
700
+ description: "Message text or optional file caption",
701
+ minLength: 0,
702
+ maxLength: 65536
703
+ },
704
+ file: {
705
+ type: "file",
706
+ description: "Plan-bound file, sticker, or voice-note bytes",
707
+ maxBytes: 524288000
708
+ },
709
+ filename: {
710
+ type: "string",
711
+ description: "Provider-visible filename",
712
+ minLength: 1,
713
+ maxLength: 512
714
+ },
715
+ mime_type: {
716
+ type: "string",
717
+ description: "Exact media type",
718
+ minLength: 1,
719
+ maxLength: 128
720
+ },
721
+ duration_seconds: {
722
+ type: "number",
723
+ description: "Voice-note duration in seconds",
724
+ minimum: 1,
725
+ maximum: 86400
726
+ },
727
+ reply_to: {
728
+ type: "string",
729
+ description: "Exact message ID returned by this adapter",
730
+ minLength: 1,
731
+ maxLength: 2048
732
+ },
733
+ mentions: {
734
+ type: "array",
735
+ description: "Canonical Matrix/Beeper participant IDs",
736
+ items: {
737
+ type: "string",
738
+ description: "Canonical Matrix/Beeper user ID",
739
+ minLength: 3,
740
+ maxLength: 2048
741
+ },
742
+ minItems: 0,
743
+ maxItems: 25
744
+ },
745
+ no_preview: {
746
+ type: "boolean",
747
+ description: "Disable link previews for text"
748
+ }
749
+ },
750
+ required: [
751
+ "account_id",
752
+ "conversation_id",
753
+ "kind"
754
+ ]
755
+ },
756
+ localCli: {
757
+ surface: "beeper",
758
+ action: "messaging.send",
759
+ contractVersion: 1,
760
+ timeoutMs: 300000,
761
+ maxOutputBytes: 10485760
762
+ }
763
+ },
764
+ "reactions.set": {
765
+ description: "Set one exact reaction desired state.",
766
+ risk: "R2",
767
+ sideEffect: "reversible provider or private desired-state mutation",
768
+ idempotency: "local-at-most-once",
769
+ dedupeWindowMs: 86400000,
770
+ input: {
771
+ properties: {
772
+ account_id: {
773
+ type: "string",
774
+ description: "Exact Beeper account ID returned by this adapter",
775
+ minLength: 1,
776
+ maxLength: 512
777
+ },
778
+ conversation_id: {
779
+ type: "string",
780
+ description: "Canonical full Beeper/Matrix chat ID returned by this adapter",
781
+ minLength: 3,
782
+ maxLength: 2048
783
+ },
784
+ message_id: {
785
+ type: "string",
786
+ description: "Exact message ID returned by this adapter",
787
+ minLength: 1,
788
+ maxLength: 2048
789
+ },
790
+ reaction: {
791
+ type: "string",
792
+ description: "Exact reaction text",
793
+ minLength: 1,
794
+ maxLength: 256
795
+ },
796
+ enabled: {
797
+ type: "boolean",
798
+ description: "Desired reaction presence"
799
+ }
800
+ },
801
+ required: [
802
+ "account_id",
803
+ "conversation_id",
804
+ "message_id",
805
+ "reaction",
806
+ "enabled"
807
+ ]
808
+ },
809
+ localCli: {
810
+ surface: "beeper",
811
+ action: "reactions.set",
812
+ contractVersion: 1,
813
+ timeoutMs: 120000,
814
+ maxOutputBytes: 10485760
815
+ }
816
+ },
817
+ "messaging.edit": {
818
+ description: "Edit one exact message authored by the bound account.",
819
+ risk: "R3",
820
+ sideEffect: "externally visible provider or Desktop mutation",
821
+ idempotency: "local-at-most-once",
822
+ dedupeWindowMs: 86400000,
823
+ input: {
824
+ properties: {
825
+ account_id: {
826
+ type: "string",
827
+ description: "Exact Beeper account ID returned by this adapter",
828
+ minLength: 1,
829
+ maxLength: 512
830
+ },
831
+ conversation_id: {
832
+ type: "string",
833
+ description: "Canonical full Beeper/Matrix chat ID returned by this adapter",
834
+ minLength: 3,
835
+ maxLength: 2048
836
+ },
837
+ message_id: {
838
+ type: "string",
839
+ description: "Exact message ID returned by this adapter",
840
+ minLength: 1,
841
+ maxLength: 2048
842
+ },
843
+ text: {
844
+ type: "string",
845
+ description: "Replacement message text",
846
+ minLength: 1,
847
+ maxLength: 65536
848
+ }
849
+ },
850
+ required: [
851
+ "account_id",
852
+ "conversation_id",
853
+ "message_id",
854
+ "text"
855
+ ]
856
+ },
857
+ localCli: {
858
+ surface: "beeper",
859
+ action: "messaging.edit",
860
+ contractVersion: 1,
861
+ timeoutMs: 120000,
862
+ maxOutputBytes: 10485760
863
+ }
864
+ },
865
+ "conversations.start": {
866
+ description: "Start one conversation with one exact account-bound user.",
867
+ risk: "R3",
868
+ sideEffect: "externally visible provider or Desktop mutation",
869
+ idempotency: "local-at-most-once",
870
+ dedupeWindowMs: 86400000,
871
+ input: {
872
+ properties: {
873
+ account_id: {
874
+ type: "string",
875
+ description: "Exact Beeper account ID returned by this adapter",
876
+ minLength: 1,
877
+ maxLength: 512
878
+ },
879
+ user_id: {
880
+ type: "string",
881
+ description: "Canonical Matrix/Beeper user ID",
882
+ minLength: 3,
883
+ maxLength: 2048
884
+ }
885
+ },
886
+ required: [
887
+ "account_id",
888
+ "user_id"
889
+ ]
890
+ },
891
+ localCli: {
892
+ surface: "beeper",
893
+ action: "conversations.start",
894
+ contractVersion: 1,
895
+ timeoutMs: 120000,
896
+ maxOutputBytes: 10485760
897
+ }
898
+ },
899
+ "conversations.archive.set": {
900
+ description: "Set one conversation archive desired state.",
901
+ risk: "R2",
902
+ sideEffect: "reversible provider or private desired-state mutation",
903
+ idempotency: "local-at-most-once",
904
+ dedupeWindowMs: 86400000,
905
+ input: {
906
+ properties: {
907
+ account_id: {
908
+ type: "string",
909
+ description: "Exact Beeper account ID returned by this adapter",
910
+ minLength: 1,
911
+ maxLength: 512
912
+ },
913
+ conversation_id: {
914
+ type: "string",
915
+ description: "Canonical full Beeper/Matrix chat ID returned by this adapter",
916
+ minLength: 3,
917
+ maxLength: 2048
918
+ },
919
+ enabled: {
920
+ type: "boolean",
921
+ description: "Desired archived state"
922
+ }
923
+ },
924
+ required: [
925
+ "account_id",
926
+ "conversation_id",
927
+ "enabled"
928
+ ]
929
+ },
930
+ localCli: {
931
+ surface: "beeper",
932
+ action: "conversations.archive.set",
933
+ contractVersion: 1,
934
+ timeoutMs: 120000,
935
+ maxOutputBytes: 10485760
936
+ }
937
+ },
938
+ "conversations.pin.set": {
939
+ description: "Set one conversation pin desired state.",
940
+ risk: "R2",
941
+ sideEffect: "reversible provider or private desired-state mutation",
942
+ idempotency: "local-at-most-once",
943
+ dedupeWindowMs: 86400000,
944
+ input: {
945
+ properties: {
946
+ account_id: {
947
+ type: "string",
948
+ description: "Exact Beeper account ID returned by this adapter",
949
+ minLength: 1,
950
+ maxLength: 512
951
+ },
952
+ conversation_id: {
953
+ type: "string",
954
+ description: "Canonical full Beeper/Matrix chat ID returned by this adapter",
955
+ minLength: 3,
956
+ maxLength: 2048
957
+ },
958
+ enabled: {
959
+ type: "boolean",
960
+ description: "Desired pinned state"
961
+ }
962
+ },
963
+ required: [
964
+ "account_id",
965
+ "conversation_id",
966
+ "enabled"
967
+ ]
968
+ },
969
+ localCli: {
970
+ surface: "beeper",
971
+ action: "conversations.pin.set",
972
+ contractVersion: 1,
973
+ timeoutMs: 120000,
974
+ maxOutputBytes: 10485760
975
+ }
976
+ },
977
+ "conversations.mute.set": {
978
+ description: "Set one conversation mute desired state.",
979
+ risk: "R2",
980
+ sideEffect: "reversible provider or private desired-state mutation",
981
+ idempotency: "local-at-most-once",
982
+ dedupeWindowMs: 86400000,
983
+ input: {
984
+ properties: {
985
+ account_id: {
986
+ type: "string",
987
+ description: "Exact Beeper account ID returned by this adapter",
988
+ minLength: 1,
989
+ maxLength: 512
990
+ },
991
+ conversation_id: {
992
+ type: "string",
993
+ description: "Canonical full Beeper/Matrix chat ID returned by this adapter",
994
+ minLength: 3,
995
+ maxLength: 2048
996
+ },
997
+ enabled: {
998
+ type: "boolean",
999
+ description: "Desired muted state"
1000
+ }
1001
+ },
1002
+ required: [
1003
+ "account_id",
1004
+ "conversation_id",
1005
+ "enabled"
1006
+ ]
1007
+ },
1008
+ localCli: {
1009
+ surface: "beeper",
1010
+ action: "conversations.mute.set",
1011
+ contractVersion: 1,
1012
+ timeoutMs: 120000,
1013
+ maxOutputBytes: 10485760
1014
+ }
1015
+ },
1016
+ "conversations.read-state.set": {
1017
+ description: "Set one conversation read marker, potentially emitting a network receipt.",
1018
+ risk: "R3",
1019
+ sideEffect: "externally visible provider or Desktop mutation",
1020
+ idempotency: "local-at-most-once",
1021
+ dedupeWindowMs: 86400000,
1022
+ input: {
1023
+ properties: {
1024
+ account_id: {
1025
+ type: "string",
1026
+ description: "Exact Beeper account ID returned by this adapter",
1027
+ minLength: 1,
1028
+ maxLength: 512
1029
+ },
1030
+ conversation_id: {
1031
+ type: "string",
1032
+ description: "Canonical full Beeper/Matrix chat ID returned by this adapter",
1033
+ minLength: 3,
1034
+ maxLength: 2048
1035
+ },
1036
+ unread: {
1037
+ type: "boolean",
1038
+ description: "Desired marked-unread state"
1039
+ },
1040
+ message_id: {
1041
+ type: "string",
1042
+ description: "Exact message ID returned by this adapter",
1043
+ minLength: 1,
1044
+ maxLength: 2048
1045
+ }
1046
+ },
1047
+ required: [
1048
+ "account_id",
1049
+ "conversation_id",
1050
+ "unread"
1051
+ ]
1052
+ },
1053
+ localCli: {
1054
+ surface: "beeper",
1055
+ action: "conversations.read-state.set",
1056
+ contractVersion: 1,
1057
+ timeoutMs: 120000,
1058
+ maxOutputBytes: 10485760
1059
+ }
1060
+ },
1061
+ "conversations.priority.set": {
1062
+ description: "Set one conversation inbox priority desired state.",
1063
+ risk: "R2",
1064
+ sideEffect: "reversible provider or private desired-state mutation",
1065
+ idempotency: "local-at-most-once",
1066
+ dedupeWindowMs: 86400000,
1067
+ input: {
1068
+ properties: {
1069
+ account_id: {
1070
+ type: "string",
1071
+ description: "Exact Beeper account ID returned by this adapter",
1072
+ minLength: 1,
1073
+ maxLength: 512
1074
+ },
1075
+ conversation_id: {
1076
+ type: "string",
1077
+ description: "Canonical full Beeper/Matrix chat ID returned by this adapter",
1078
+ minLength: 3,
1079
+ maxLength: 2048
1080
+ },
1081
+ level: {
1082
+ type: "string",
1083
+ description: "Desired inbox priority",
1084
+ minLength: 1,
1085
+ maxLength: 16,
1086
+ enum: [
1087
+ "inbox",
1088
+ "low"
1089
+ ]
1090
+ }
1091
+ },
1092
+ required: [
1093
+ "account_id",
1094
+ "conversation_id",
1095
+ "level"
1096
+ ]
1097
+ },
1098
+ localCli: {
1099
+ surface: "beeper",
1100
+ action: "conversations.priority.set",
1101
+ contractVersion: 1,
1102
+ timeoutMs: 120000,
1103
+ maxOutputBytes: 10485760
1104
+ }
1105
+ },
1106
+ "conversations.notify": {
1107
+ description: "Send one explicit iMessage Notify Anyway alert.",
1108
+ risk: "R3",
1109
+ sideEffect: "externally visible provider or Desktop mutation",
1110
+ idempotency: "local-at-most-once",
1111
+ dedupeWindowMs: 86400000,
1112
+ input: {
1113
+ properties: {
1114
+ account_id: {
1115
+ type: "string",
1116
+ description: "Exact Beeper account ID returned by this adapter",
1117
+ minLength: 1,
1118
+ maxLength: 512
1119
+ },
1120
+ conversation_id: {
1121
+ type: "string",
1122
+ description: "Canonical full Beeper/Matrix chat ID returned by this adapter",
1123
+ minLength: 3,
1124
+ maxLength: 2048
1125
+ }
1126
+ },
1127
+ required: [
1128
+ "account_id",
1129
+ "conversation_id"
1130
+ ]
1131
+ },
1132
+ localCli: {
1133
+ surface: "beeper",
1134
+ action: "conversations.notify",
1135
+ contractVersion: 1,
1136
+ timeoutMs: 120000,
1137
+ maxOutputBytes: 10485760
1138
+ }
1139
+ },
1140
+ "conversations.title.set": {
1141
+ description: "Set one exact group-conversation title.",
1142
+ risk: "R3",
1143
+ sideEffect: "externally visible provider or Desktop mutation",
1144
+ idempotency: "local-at-most-once",
1145
+ dedupeWindowMs: 86400000,
1146
+ input: {
1147
+ properties: {
1148
+ account_id: {
1149
+ type: "string",
1150
+ description: "Exact Beeper account ID returned by this adapter",
1151
+ minLength: 1,
1152
+ maxLength: 512
1153
+ },
1154
+ conversation_id: {
1155
+ type: "string",
1156
+ description: "Canonical full Beeper/Matrix chat ID returned by this adapter",
1157
+ minLength: 3,
1158
+ maxLength: 2048
1159
+ },
1160
+ title: {
1161
+ type: "string",
1162
+ description: "Replacement group title",
1163
+ minLength: 1,
1164
+ maxLength: 1024
1165
+ }
1166
+ },
1167
+ required: [
1168
+ "account_id",
1169
+ "conversation_id",
1170
+ "title"
1171
+ ]
1172
+ },
1173
+ localCli: {
1174
+ surface: "beeper",
1175
+ action: "conversations.title.set",
1176
+ contractVersion: 1,
1177
+ timeoutMs: 120000,
1178
+ maxOutputBytes: 10485760
1179
+ }
1180
+ },
1181
+ "conversations.description.set": {
1182
+ description: "Set or clear one exact group-conversation description.",
1183
+ risk: "R3",
1184
+ sideEffect: "externally visible provider or Desktop mutation",
1185
+ idempotency: "local-at-most-once",
1186
+ dedupeWindowMs: 86400000,
1187
+ input: {
1188
+ properties: {
1189
+ account_id: {
1190
+ type: "string",
1191
+ description: "Exact Beeper account ID returned by this adapter",
1192
+ minLength: 1,
1193
+ maxLength: 512
1194
+ },
1195
+ conversation_id: {
1196
+ type: "string",
1197
+ description: "Canonical full Beeper/Matrix chat ID returned by this adapter",
1198
+ minLength: 3,
1199
+ maxLength: 2048
1200
+ },
1201
+ clear: {
1202
+ type: "boolean",
1203
+ description: "Clear the description"
1204
+ },
1205
+ description: {
1206
+ type: "string",
1207
+ description: "Replacement group description",
1208
+ minLength: 1,
1209
+ maxLength: 65536
1210
+ }
1211
+ },
1212
+ required: [
1213
+ "account_id",
1214
+ "conversation_id",
1215
+ "clear"
1216
+ ]
1217
+ },
1218
+ localCli: {
1219
+ surface: "beeper",
1220
+ action: "conversations.description.set",
1221
+ contractVersion: 1,
1222
+ timeoutMs: 120000,
1223
+ maxOutputBytes: 10485760
1224
+ }
1225
+ },
1226
+ "conversations.avatar.set": {
1227
+ description: "Set or clear one exact group-conversation avatar.",
1228
+ risk: "R3",
1229
+ sideEffect: "externally visible provider or Desktop mutation",
1230
+ idempotency: "local-at-most-once",
1231
+ dedupeWindowMs: 86400000,
1232
+ input: {
1233
+ properties: {
1234
+ account_id: {
1235
+ type: "string",
1236
+ description: "Exact Beeper account ID returned by this adapter",
1237
+ minLength: 1,
1238
+ maxLength: 512
1239
+ },
1240
+ conversation_id: {
1241
+ type: "string",
1242
+ description: "Canonical full Beeper/Matrix chat ID returned by this adapter",
1243
+ minLength: 3,
1244
+ maxLength: 2048
1245
+ },
1246
+ clear: {
1247
+ type: "boolean",
1248
+ description: "Clear the avatar"
1249
+ },
1250
+ avatar: {
1251
+ type: "file",
1252
+ description: "Plan-bound replacement avatar bytes",
1253
+ maxBytes: 16777216
1254
+ }
1255
+ },
1256
+ required: [
1257
+ "account_id",
1258
+ "conversation_id",
1259
+ "clear"
1260
+ ]
1261
+ },
1262
+ localCli: {
1263
+ surface: "beeper",
1264
+ action: "conversations.avatar.set",
1265
+ contractVersion: 1,
1266
+ timeoutMs: 120000,
1267
+ maxOutputBytes: 10485760
1268
+ }
1269
+ },
1270
+ "conversations.draft.set": {
1271
+ description: "Set or clear one private Desktop draft.",
1272
+ risk: "R2",
1273
+ sideEffect: "reversible provider or private desired-state mutation",
1274
+ idempotency: "local-at-most-once",
1275
+ dedupeWindowMs: 86400000,
1276
+ input: {
1277
+ properties: {
1278
+ account_id: {
1279
+ type: "string",
1280
+ description: "Exact Beeper account ID returned by this adapter",
1281
+ minLength: 1,
1282
+ maxLength: 512
1283
+ },
1284
+ conversation_id: {
1285
+ type: "string",
1286
+ description: "Canonical full Beeper/Matrix chat ID returned by this adapter",
1287
+ minLength: 3,
1288
+ maxLength: 2048
1289
+ },
1290
+ clear: {
1291
+ type: "boolean",
1292
+ description: "Clear the draft"
1293
+ },
1294
+ text: {
1295
+ type: "string",
1296
+ description: "Replacement private draft text",
1297
+ minLength: 0,
1298
+ maxLength: 65536
1299
+ },
1300
+ attachment: {
1301
+ type: "file",
1302
+ description: "Plan-bound private draft attachment",
1303
+ maxBytes: 524288000
1304
+ },
1305
+ filename: {
1306
+ type: "string",
1307
+ description: "Attachment filename",
1308
+ minLength: 1,
1309
+ maxLength: 512
1310
+ },
1311
+ mime_type: {
1312
+ type: "string",
1313
+ description: "Attachment media type",
1314
+ minLength: 1,
1315
+ maxLength: 128
1316
+ }
1317
+ },
1318
+ required: [
1319
+ "account_id",
1320
+ "conversation_id",
1321
+ "clear"
1322
+ ]
1323
+ },
1324
+ localCli: {
1325
+ surface: "beeper",
1326
+ action: "conversations.draft.set",
1327
+ contractVersion: 1,
1328
+ timeoutMs: 120000,
1329
+ maxOutputBytes: 10485760
1330
+ }
1331
+ },
1332
+ "conversations.disappearing.set": {
1333
+ description: "Set one disappearing-message retention interval.",
1334
+ risk: "R3",
1335
+ sideEffect: "externally visible provider or Desktop mutation",
1336
+ idempotency: "local-at-most-once",
1337
+ dedupeWindowMs: 86400000,
1338
+ input: {
1339
+ properties: {
1340
+ account_id: {
1341
+ type: "string",
1342
+ description: "Exact Beeper account ID returned by this adapter",
1343
+ minLength: 1,
1344
+ maxLength: 512
1345
+ },
1346
+ conversation_id: {
1347
+ type: "string",
1348
+ description: "Canonical full Beeper/Matrix chat ID returned by this adapter",
1349
+ minLength: 3,
1350
+ maxLength: 2048
1351
+ },
1352
+ seconds: {
1353
+ type: "number",
1354
+ description: "Desired disappearing-message interval; zero disables",
1355
+ minimum: 0,
1356
+ maximum: 31536000
1357
+ }
1358
+ },
1359
+ required: [
1360
+ "account_id",
1361
+ "conversation_id",
1362
+ "seconds"
1363
+ ]
1364
+ },
1365
+ localCli: {
1366
+ surface: "beeper",
1367
+ action: "conversations.disappearing.set",
1368
+ contractVersion: 1,
1369
+ timeoutMs: 120000,
1370
+ maxOutputBytes: 10485760
1371
+ }
1372
+ },
1373
+ "conversations.reminder.set": {
1374
+ description: "Set or clear one private Desktop reminder.",
1375
+ risk: "R2",
1376
+ sideEffect: "reversible provider or private desired-state mutation",
1377
+ idempotency: "local-at-most-once",
1378
+ dedupeWindowMs: 86400000,
1379
+ input: {
1380
+ properties: {
1381
+ account_id: {
1382
+ type: "string",
1383
+ description: "Exact Beeper account ID returned by this adapter",
1384
+ minLength: 1,
1385
+ maxLength: 512
1386
+ },
1387
+ conversation_id: {
1388
+ type: "string",
1389
+ description: "Canonical full Beeper/Matrix chat ID returned by this adapter",
1390
+ minLength: 3,
1391
+ maxLength: 2048
1392
+ },
1393
+ clear: {
1394
+ type: "boolean",
1395
+ description: "Clear the reminder"
1396
+ },
1397
+ when: {
1398
+ type: "string",
1399
+ description: "Canonical UTC ISO timestamp",
1400
+ minLength: 20,
1401
+ maxLength: 64
1402
+ },
1403
+ dismiss_on_message: {
1404
+ type: "boolean",
1405
+ description: "Dismiss when a message arrives"
1406
+ }
1407
+ },
1408
+ required: [
1409
+ "account_id",
1410
+ "conversation_id",
1411
+ "clear"
1412
+ ]
1413
+ },
1414
+ localCli: {
1415
+ surface: "beeper",
1416
+ action: "conversations.reminder.set",
1417
+ contractVersion: 1,
1418
+ timeoutMs: 120000,
1419
+ maxOutputBytes: 10485760
1420
+ }
1421
+ },
1422
+ "conversations.focus": {
1423
+ description: "Focus one exact Desktop conversation with optional plan-bound draft state.",
1424
+ risk: "R2",
1425
+ sideEffect: "reversible provider or private desired-state mutation",
1426
+ idempotency: "local-at-most-once",
1427
+ dedupeWindowMs: 86400000,
1428
+ input: {
1429
+ properties: {
1430
+ account_id: {
1431
+ type: "string",
1432
+ description: "Exact Beeper account ID returned by this adapter",
1433
+ minLength: 1,
1434
+ maxLength: 512
1435
+ },
1436
+ conversation_id: {
1437
+ type: "string",
1438
+ description: "Canonical full Beeper/Matrix chat ID returned by this adapter",
1439
+ minLength: 3,
1440
+ maxLength: 2048
1441
+ },
1442
+ message_id: {
1443
+ type: "string",
1444
+ description: "Exact message ID returned by this adapter",
1445
+ minLength: 1,
1446
+ maxLength: 2048
1447
+ },
1448
+ draft: {
1449
+ type: "string",
1450
+ description: "Plan-bound Desktop draft text",
1451
+ minLength: 0,
1452
+ maxLength: 65536
1453
+ },
1454
+ attachment: {
1455
+ type: "file",
1456
+ description: "Plan-bound Desktop draft attachment",
1457
+ maxBytes: 524288000
1458
+ }
1459
+ },
1460
+ required: [
1461
+ "account_id",
1462
+ "conversation_id"
1463
+ ]
1464
+ },
1465
+ localCli: {
1466
+ surface: "beeper",
1467
+ action: "conversations.focus",
1468
+ contractVersion: 1,
1469
+ timeoutMs: 120000,
1470
+ maxOutputBytes: 10485760
1471
+ }
1472
+ },
1473
+ "presence.set": {
1474
+ description: "Send one bounded typing or paused presence indication.",
1475
+ risk: "R3",
1476
+ sideEffect: "externally visible provider or Desktop mutation",
1477
+ idempotency: "local-at-most-once",
1478
+ dedupeWindowMs: 86400000,
1479
+ input: {
1480
+ properties: {
1481
+ account_id: {
1482
+ type: "string",
1483
+ description: "Exact Beeper account ID returned by this adapter",
1484
+ minLength: 1,
1485
+ maxLength: 512
1486
+ },
1487
+ conversation_id: {
1488
+ type: "string",
1489
+ description: "Canonical full Beeper/Matrix chat ID returned by this adapter",
1490
+ minLength: 3,
1491
+ maxLength: 2048
1492
+ },
1493
+ state: {
1494
+ type: "string",
1495
+ description: "Exact presence state",
1496
+ minLength: 1,
1497
+ maxLength: 16,
1498
+ enum: [
1499
+ "typing",
1500
+ "paused"
1501
+ ]
1502
+ },
1503
+ duration_seconds: {
1504
+ type: "number",
1505
+ description: "Bounded typing duration before a separately journaled paused dispatch",
1506
+ minimum: 1,
1507
+ maximum: 30
1508
+ }
1509
+ },
1510
+ required: [
1511
+ "account_id",
1512
+ "conversation_id",
1513
+ "state"
1514
+ ]
1515
+ },
1516
+ localCli: {
1517
+ surface: "beeper",
1518
+ action: "presence.set",
1519
+ contractVersion: 1,
1520
+ timeoutMs: 120000,
1521
+ maxOutputBytes: 10485760
1522
+ }
1523
+ }
1524
+ }
1525
+ };
1526
+
1527
+ // src/local-cli-surface-contract.ts
1528
+ import { types as nodeTypes } from "util";
1529
+ var LOCAL_CLI_SURFACE_DISPOSITIONS = Object.freeze([
1530
+ "supported",
1531
+ "fixed",
1532
+ "absorbed",
1533
+ "replaced",
1534
+ "internal",
1535
+ "R4",
1536
+ "unsupported"
1537
+ ]);
1538
+ var LOCAL_CLI_SURFACE_PROVENANCE_KINDS = Object.freeze([
1539
+ "built-in-canonical",
1540
+ "built-in-hidden",
1541
+ "built-in-alias",
1542
+ "source-only-private",
1543
+ "jit-plugin",
1544
+ "dynamic-plugin",
1545
+ "documented-only"
1546
+ ]);
1547
+ function hasWellFormedUnicode(value) {
1548
+ for (let index = 0;index < value.length; index += 1) {
1549
+ const code = value.charCodeAt(index);
1550
+ if (code >= 55296 && code <= 56319) {
1551
+ const next = value.charCodeAt(index + 1);
1552
+ if (!(next >= 56320 && next <= 57343))
1553
+ return false;
1554
+ index += 1;
1555
+ } else if (code >= 56320 && code <= 57343)
1556
+ return false;
1557
+ }
1558
+ return true;
1559
+ }
1560
+ function record(value, label) {
1561
+ if (nodeTypes.isProxy(value) || typeof value !== "object" || value === null || Array.isArray(value) || Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null)
1562
+ throw new Error(`${label} must be a plain data object`);
1563
+ const descriptors = Object.getOwnPropertyDescriptors(value);
1564
+ const result = Object.create(null);
1565
+ for (const key of Reflect.ownKeys(descriptors)) {
1566
+ if (typeof key !== "string")
1567
+ throw new Error(`${label} must not contain symbols`);
1568
+ const descriptor = descriptors[key];
1569
+ if (descriptor === undefined || !("value" in descriptor) || !descriptor.enumerable || !hasWellFormedUnicode(key))
1570
+ throw new Error(`${label} must contain only enumerable Unicode data fields`);
1571
+ result[key] = descriptor.value;
1572
+ }
1573
+ return Object.freeze(result);
1574
+ }
1575
+ function exactKeys(value, required, optional, label) {
1576
+ const allowed = new Set([...required, ...optional]);
1577
+ for (const key of Object.keys(value)) {
1578
+ if (!allowed.has(key))
1579
+ throw new Error(`${label} contains unsupported field ${key}`);
1580
+ }
1581
+ for (const key of required) {
1582
+ if (!Object.hasOwn(value, key))
1583
+ throw new Error(`${label}.${key} is required`);
1584
+ }
1585
+ }
1586
+ function array(value, label, maximum) {
1587
+ if (nodeTypes.isProxy(value) || !Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype || value.length > maximum || Reflect.ownKeys(value).length !== value.length + 1)
1588
+ throw new Error(`${label} must be a dense array of at most ${maximum} items`);
1589
+ const result = [];
1590
+ for (let index = 0;index < value.length; index += 1) {
1591
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
1592
+ if (descriptor === undefined || !("value" in descriptor) || !descriptor.enumerable) {
1593
+ throw new Error(`${label} must contain only enumerable data items`);
1594
+ }
1595
+ result.push(descriptor.value);
1596
+ }
1597
+ return Object.freeze(result);
1598
+ }
1599
+ function string(value, label, maximum = 1024) {
1600
+ if (typeof value !== "string" || value.length < 1 || value.length > maximum || !hasWellFormedUnicode(value) || /[\u0000-\u001f\u007f-\u009f]/u.test(value))
1601
+ throw new Error(`${label} must be bounded Unicode text`);
1602
+ return value;
1603
+ }
1604
+ function nullableString(value, label) {
1605
+ return value === null ? null : string(value, label);
1606
+ }
1607
+ function parseVersionKind(value, versionValue, label) {
1608
+ if (versionValue === null) {
1609
+ if (value !== null)
1610
+ throw new Error(`${label} requires a package version`);
1611
+ return null;
1612
+ }
1613
+ return exactEnum(value, label, ["exact", "range"]);
1614
+ }
1615
+ function boolean(value, label) {
1616
+ if (typeof value !== "boolean")
1617
+ throw new Error(`${label} must be boolean`);
1618
+ return value;
1619
+ }
1620
+ function integer(value, label, minimum, maximum) {
1621
+ if (!Number.isSafeInteger(value) || value < minimum || value > maximum) {
1622
+ throw new Error(`${label} must be a bounded integer`);
1623
+ }
1624
+ return value;
1625
+ }
1626
+ function exactEnum(value, label, values) {
1627
+ if (typeof value !== "string" || !values.includes(value)) {
1628
+ throw new Error(`${label} is unsupported`);
1629
+ }
1630
+ return value;
1631
+ }
1632
+ function sha(value, label) {
1633
+ if (typeof value !== "string" || !/^[a-f0-9]{64}$/u.test(value)) {
1634
+ throw new Error(`${label} must be one SHA-256 digest`);
1635
+ }
1636
+ return value;
1637
+ }
1638
+ function commitSha(value, label) {
1639
+ if (typeof value !== "string" || !/^[a-f0-9]{40}$/u.test(value)) {
1640
+ throw new Error(`${label} must be one full Git commit ID`);
1641
+ }
1642
+ return value;
1643
+ }
1644
+ function canonicalDate(value, label) {
1645
+ if (typeof value !== "string" || !/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/u.test(value)) {
1646
+ throw new Error(`${label} must be a canonical YYYY-MM-DD date`);
1647
+ }
1648
+ const milliseconds = Date.parse(`${value}T00:00:00.000Z`);
1649
+ if (!Number.isFinite(milliseconds) || new Date(milliseconds).toISOString().slice(0, 10) !== value)
1650
+ throw new Error(`${label} must be a canonical YYYY-MM-DD date`);
1651
+ return value;
1652
+ }
1653
+ function scalar(value, label) {
1654
+ if (value === null || typeof value === "string" || typeof value === "boolean") {
1655
+ if (typeof value === "string")
1656
+ string(value, label, 4096);
1657
+ return value;
1658
+ }
1659
+ if (typeof value === "number" && Number.isFinite(value) && !Object.is(value, -0))
1660
+ return value;
1661
+ throw new Error(`${label} must be a finite JSON scalar`);
1662
+ }
1663
+ function stringList(value, label, maximum) {
1664
+ const result = array(value, label, maximum).map((item, index) => string(item, `${label}[${index}]`, 512));
1665
+ if (new Set(result).size !== result.length)
1666
+ throw new Error(`${label} repeats a value`);
1667
+ return Object.freeze(result);
1668
+ }
1669
+ function commandPath(value, label) {
1670
+ const path = stringList(value, label, 16);
1671
+ if (path.length < 1 || path.some((segment) => /\s/u.test(segment))) {
1672
+ throw new Error(`${label} must contain nonempty whitespace-free command segments`);
1673
+ }
1674
+ return path;
1675
+ }
1676
+ function codePointCompare(left, right) {
1677
+ const leftCodePoints = [...left];
1678
+ const rightCodePoints = [...right];
1679
+ const length = Math.min(leftCodePoints.length, rightCodePoints.length);
1680
+ for (let index = 0;index < length; index += 1) {
1681
+ const leftCodePoint = leftCodePoints[index].codePointAt(0);
1682
+ const rightCodePoint = rightCodePoints[index].codePointAt(0);
1683
+ if (leftCodePoint !== rightCodePoint)
1684
+ return leftCodePoint < rightCodePoint ? -1 : 1;
1685
+ }
1686
+ return leftCodePoints.length < rightCodePoints.length ? -1 : leftCodePoints.length > rightCodePoints.length ? 1 : 0;
1687
+ }
1688
+ function surfaceCanonicalJson(value) {
1689
+ if (value === null)
1690
+ return "null";
1691
+ if (typeof value === "string" || typeof value === "boolean") {
1692
+ return JSON.stringify(value);
1693
+ }
1694
+ if (typeof value === "number") {
1695
+ if (!Number.isFinite(value) || Object.is(value, -0)) {
1696
+ throw new Error("local CLI surface canonical JSON contains an invalid number");
1697
+ }
1698
+ return JSON.stringify(value);
1699
+ }
1700
+ if (Array.isArray(value)) {
1701
+ return `[${value.map((item) => surfaceCanonicalJson(item)).join(",")}]`;
1702
+ }
1703
+ if (typeof value !== "object" || value === null) {
1704
+ throw new Error("local CLI surface canonical JSON contains a non-JSON value");
1705
+ }
1706
+ const entries = Object.entries(value).sort(([left], [right]) => codePointCompare(left, right));
1707
+ return `{${entries.map(([key, item]) => `${JSON.stringify(key)}:${surfaceCanonicalJson(item)}`).join(",")}}`;
1708
+ }
1709
+ function parseDefault(value, label) {
1710
+ const source = record(value, label);
1711
+ const kind = exactEnum(source.kind, `${label}.kind`, [
1712
+ "none",
1713
+ "literal",
1714
+ "derived",
1715
+ "environment"
1716
+ ]);
1717
+ if (kind === "none") {
1718
+ exactKeys(source, ["kind"], [], label);
1719
+ return Object.freeze({ kind });
1720
+ }
1721
+ if (kind === "literal") {
1722
+ exactKeys(source, ["kind", "value", "authority"], [], label);
1723
+ const value2 = scalar(source.value, `${label}.value`);
1724
+ if (value2 === null)
1725
+ throw new Error(`${label}.literal null is ambiguous with kind none`);
1726
+ return Object.freeze({
1727
+ kind,
1728
+ value: value2,
1729
+ authority: exactEnum(source.authority, `${label}.authority`, [
1730
+ "tagged-source",
1731
+ "jit-plugin-source",
1732
+ "sdk-openapi"
1733
+ ])
1734
+ });
1735
+ }
1736
+ if (kind === "derived") {
1737
+ exactKeys(source, ["kind", "description"], [], label);
1738
+ return Object.freeze({ kind, description: string(source.description, `${label}.description`, 500) });
1739
+ }
1740
+ exactKeys(source, ["kind", "name"], [], label);
1741
+ const name = string(source.name, `${label}.name`, 128);
1742
+ if (!/^[A-Z][A-Z0-9_]*$/u.test(name))
1743
+ throw new Error(`${label}.name must be an environment variable`);
1744
+ return Object.freeze({ kind, name });
1745
+ }
1746
+ function parseDecision(value, label) {
1747
+ const source = record(value, label);
1748
+ exactKeys(source, [
1749
+ "disposition",
1750
+ "rationale",
1751
+ "operation",
1752
+ "replacement",
1753
+ "fixedValue"
1754
+ ], [], label);
1755
+ const disposition = exactEnum(source.disposition, `${label}.disposition`, LOCAL_CLI_SURFACE_DISPOSITIONS);
1756
+ const operation = nullableString(source.operation, `${label}.operation`);
1757
+ const replacement = nullableString(source.replacement, `${label}.replacement`);
1758
+ const fixedValue = scalar(source.fixedValue, `${label}.fixedValue`);
1759
+ if (operation !== null && !isProviderPluginOperationName(operation))
1760
+ throw new Error(`${label}.operation must be a semantic operation name`);
1761
+ if (disposition === "supported" && operation === null) {
1762
+ throw new Error(`${label} supported disposition requires an operation`);
1763
+ }
1764
+ if (disposition === "fixed" && fixedValue === null) {
1765
+ throw new Error(`${label}.fixedValue is required for fixed disposition`);
1766
+ }
1767
+ if (disposition !== "fixed" && fixedValue !== null) {
1768
+ throw new Error(`${label}.fixedValue requires fixed disposition`);
1769
+ }
1770
+ return Object.freeze({
1771
+ disposition,
1772
+ rationale: string(source.rationale, `${label}.rationale`, 1000),
1773
+ operation,
1774
+ replacement,
1775
+ fixedValue
1776
+ });
1777
+ }
1778
+ function parsePathSemanticInputs(value, label) {
1779
+ const source = record(value, label);
1780
+ const entries = Object.entries(source);
1781
+ if (entries.length > 128) {
1782
+ throw new Error(`${label} exceeds its semantic input bound`);
1783
+ }
1784
+ const parsed = Object.create(null);
1785
+ for (const [field, fieldValue] of entries) {
1786
+ if (!/^[a-z][a-z0-9_]{0,127}$/u.test(field)) {
1787
+ throw new Error(`${label} contains an invalid semantic input field ${field}`);
1788
+ }
1789
+ parsed[field] = scalar(fieldValue, `${label}.${field}`);
1790
+ }
1791
+ return Object.freeze(parsed);
1792
+ }
1793
+ function parsePredicate(value, label, traversal, depth = 0) {
1794
+ if (depth > 8)
1795
+ throw new Error(`${label} exceeds the predicate depth bound`);
1796
+ if (typeof value !== "object" || value === null) {
1797
+ throw new Error(`${label} must be a predicate data object`);
1798
+ }
1799
+ if (traversal.seen.has(value)) {
1800
+ throw new Error(`${label} repeats a predicate object identity`);
1801
+ }
1802
+ traversal.seen.add(value);
1803
+ traversal.nodes += 1;
1804
+ if (traversal.nodes > 1e4) {
1805
+ throw new Error("local CLI surface predicates exceed the whole-contract node bound");
1806
+ }
1807
+ const source = record(value, label);
1808
+ const op = exactEnum(source.op, `${label}.op`, [
1809
+ "true",
1810
+ "present",
1811
+ "eq",
1812
+ "not",
1813
+ "and",
1814
+ "or"
1815
+ ]);
1816
+ if (op === "true") {
1817
+ exactKeys(source, ["op"], [], label);
1818
+ return Object.freeze({ op });
1819
+ }
1820
+ if (op === "present") {
1821
+ exactKeys(source, ["op", "field"], [], label);
1822
+ return Object.freeze({ op, field: string(source.field, `${label}.field`, 128) });
1823
+ }
1824
+ if (op === "eq") {
1825
+ exactKeys(source, ["op", "field", "value"], [], label);
1826
+ return Object.freeze({
1827
+ op,
1828
+ field: string(source.field, `${label}.field`, 128),
1829
+ value: scalar(source.value, `${label}.value`)
1830
+ });
1831
+ }
1832
+ if (op === "not") {
1833
+ exactKeys(source, ["op", "predicate"], [], label);
1834
+ return Object.freeze({
1835
+ op,
1836
+ predicate: parsePredicate(source.predicate, `${label}.predicate`, traversal, depth + 1)
1837
+ });
1838
+ }
1839
+ exactKeys(source, ["op", "predicates"], [], label);
1840
+ const predicates = array(source.predicates, `${label}.predicates`, 32).map((item, index) => parsePredicate(item, `${label}.predicates[${index}]`, traversal, depth + 1));
1841
+ if (predicates.length < 1)
1842
+ throw new Error(`${label}.predicates must not be empty`);
1843
+ return Object.freeze({ op, predicates: Object.freeze(predicates) });
1844
+ }
1845
+ function parseRule(value, label, predicateTraversal) {
1846
+ const source = record(value, label);
1847
+ exactKeys(source, [
1848
+ "namespace",
1849
+ "when",
1850
+ "require",
1851
+ "requireAny",
1852
+ "exactlyOne",
1853
+ "forbid",
1854
+ "rationale"
1855
+ ], [], label);
1856
+ const requiredFields = stringList(source.require, `${label}.require`, 64);
1857
+ const requireAny = stringList(source.requireAny, `${label}.requireAny`, 64);
1858
+ const exactlyOne = stringList(source.exactlyOne, `${label}.exactlyOne`, 64);
1859
+ const forbid = stringList(source.forbid, `${label}.forbid`, 64);
1860
+ if ([...requiredFields, ...requireAny, ...exactlyOne].some((field) => forbid.includes(field))) {
1861
+ throw new Error(`${label} cannot require and forbid the same field`);
1862
+ }
1863
+ return Object.freeze({
1864
+ namespace: exactEnum(source.namespace, `${label}.namespace`, [
1865
+ "semantic-operation",
1866
+ "upstream-command"
1867
+ ]),
1868
+ when: parsePredicate(source.when, `${label}.when`, predicateTraversal),
1869
+ require: requiredFields,
1870
+ requireAny,
1871
+ exactlyOne,
1872
+ forbid,
1873
+ rationale: string(source.rationale, `${label}.rationale`, 1000)
1874
+ });
1875
+ }
1876
+ function parseArgument(value, label) {
1877
+ const source = record(value, label);
1878
+ exactKeys(source, [
1879
+ "name",
1880
+ "position",
1881
+ "required",
1882
+ "multiple",
1883
+ "valueType",
1884
+ "enum",
1885
+ "default",
1886
+ "decision"
1887
+ ], [], label);
1888
+ const valueType = exactEnum(source.valueType, `${label}.valueType`, ["string", "number", "boolean"]);
1889
+ const enumValues = stringList(source.enum, `${label}.enum`, 128);
1890
+ const defaultValue = parseDefault(source.default, `${label}.default`);
1891
+ const decision = parseDecision(source.decision, `${label}.decision`);
1892
+ if (enumValues.length > 0 && valueType !== "string") {
1893
+ throw new Error(`${label}.enum requires a string argument`);
1894
+ }
1895
+ if (defaultValue.kind === "literal" && enumValues.length > 0 && !enumValues.includes(defaultValue.value))
1896
+ throw new Error(`${label}.default must belong to the declared enum`);
1897
+ if (defaultValue.kind === "literal" && defaultValue.value !== null && typeof defaultValue.value !== valueType)
1898
+ throw new Error(`${label}.default must match the argument value type`);
1899
+ if (decision.disposition === "fixed" && typeof decision.fixedValue !== valueType)
1900
+ throw new Error(`${label}.fixedValue must match the argument value type`);
1901
+ if (decision.disposition === "fixed" && enumValues.length > 0 && !enumValues.includes(decision.fixedValue))
1902
+ throw new Error(`${label}.fixedValue must belong to the declared enum`);
1903
+ return Object.freeze({
1904
+ name: string(source.name, `${label}.name`, 128),
1905
+ position: integer(source.position, `${label}.position`, 0, 255),
1906
+ required: boolean(source.required, `${label}.required`),
1907
+ multiple: boolean(source.multiple, `${label}.multiple`),
1908
+ valueType,
1909
+ enum: enumValues,
1910
+ default: defaultValue,
1911
+ decision
1912
+ });
1913
+ }
1914
+ function parseFlag(value, label) {
1915
+ const source = record(value, label);
1916
+ exactKeys(source, [
1917
+ "name",
1918
+ "aliases",
1919
+ "source",
1920
+ "valueType",
1921
+ "allowNo",
1922
+ "required",
1923
+ "multiple",
1924
+ "enum",
1925
+ "default",
1926
+ "decision"
1927
+ ], [], label);
1928
+ const name = string(source.name, `${label}.name`, 128);
1929
+ if (!/^--[a-z0-9][a-z0-9-]*$/u.test(name))
1930
+ throw new Error(`${label}.name must be a long flag`);
1931
+ const aliases = stringList(source.aliases, `${label}.aliases`, 8);
1932
+ if (aliases.some((alias) => !/^-[a-zA-Z]$/u.test(alias))) {
1933
+ throw new Error(`${label}.aliases must be one-character flags`);
1934
+ }
1935
+ const valueType = exactEnum(source.valueType, `${label}.valueType`, ["string", "number", "boolean"]);
1936
+ const allowNo = boolean(source.allowNo, `${label}.allowNo`);
1937
+ const defaultValue = parseDefault(source.default, `${label}.default`);
1938
+ const enumValues = stringList(source.enum, `${label}.enum`, 128);
1939
+ const decision = parseDecision(source.decision, `${label}.decision`);
1940
+ if (allowNo && valueType !== "boolean") {
1941
+ throw new Error(`${label}.allowNo requires a boolean flag`);
1942
+ }
1943
+ if (enumValues.length > 0 && valueType !== "string") {
1944
+ throw new Error(`${label}.enum requires a string flag`);
1945
+ }
1946
+ if (defaultValue.kind === "literal" && enumValues.length > 0 && !enumValues.includes(defaultValue.value))
1947
+ throw new Error(`${label}.default must belong to the declared enum`);
1948
+ if (defaultValue.kind === "literal" && defaultValue.value !== null && typeof defaultValue.value !== valueType)
1949
+ throw new Error(`${label}.default must match the flag value type`);
1950
+ if (decision.disposition === "fixed" && typeof decision.fixedValue !== valueType)
1951
+ throw new Error(`${label}.fixedValue must match the flag value type`);
1952
+ if (decision.disposition === "fixed" && enumValues.length > 0 && !enumValues.includes(decision.fixedValue))
1953
+ throw new Error(`${label}.fixedValue must belong to the declared enum`);
1954
+ return Object.freeze({
1955
+ name,
1956
+ aliases,
1957
+ source: exactEnum(source.source, `${label}.source`, ["command", "global"]),
1958
+ valueType,
1959
+ allowNo,
1960
+ required: boolean(source.required, `${label}.required`),
1961
+ multiple: boolean(source.multiple, `${label}.multiple`),
1962
+ enum: enumValues,
1963
+ default: defaultValue,
1964
+ decision
1965
+ });
1966
+ }
1967
+ function parseOutput(value, label) {
1968
+ const source = record(value, label);
1969
+ exactKeys(source, [
1970
+ "shape",
1971
+ "completeness",
1972
+ "maxBytes",
1973
+ "privateArtifact",
1974
+ "truncation"
1975
+ ], [], label);
1976
+ const maxBytes = source.maxBytes === null ? null : integer(source.maxBytes, `${label}.maxBytes`, 1, 4 * 1024 * 1024 * 1024);
1977
+ return Object.freeze({
1978
+ shape: string(source.shape, `${label}.shape`, 1000),
1979
+ completeness: exactEnum(source.completeness, `${label}.completeness`, [
1980
+ "complete",
1981
+ "bounded",
1982
+ "candidate-window",
1983
+ "input-dependent",
1984
+ "internal",
1985
+ "unavailable"
1986
+ ]),
1987
+ maxBytes,
1988
+ privateArtifact: boolean(source.privateArtifact, `${label}.privateArtifact`),
1989
+ truncation: nullableString(source.truncation, `${label}.truncation`)
1990
+ });
1991
+ }
1992
+ function parseReconciliation(value, label, predicateTraversal) {
1993
+ const source = record(value, label);
1994
+ exactKeys(source, ["availability", "namespace", "predicate", "rationale"], [], label);
1995
+ const availability = exactEnum(source.availability, `${label}.availability`, [
1996
+ "none",
1997
+ "always",
1998
+ "input-dependent"
1999
+ ]);
2000
+ const predicate = source.predicate === null ? null : parsePredicate(source.predicate, `${label}.predicate`, predicateTraversal);
2001
+ if (availability === "input-dependent" !== (predicate !== null)) {
2002
+ throw new Error(`${label}.predicate must exactly match input-dependent availability`);
2003
+ }
2004
+ const namespace = source.namespace === null ? null : exactEnum(source.namespace, `${label}.namespace`, ["semantic-operation"]);
2005
+ if (availability === "input-dependent" !== (namespace !== null)) {
2006
+ throw new Error(`${label}.namespace must exactly match input-dependent availability`);
2007
+ }
2008
+ return Object.freeze({
2009
+ availability,
2010
+ namespace,
2011
+ predicate,
2012
+ rationale: string(source.rationale, `${label}.rationale`, 1000)
2013
+ });
2014
+ }
2015
+ function parseCommand(value, label, predicateTraversal) {
2016
+ const source = record(value, label);
2017
+ exactKeys(source, [
2018
+ "path",
2019
+ "provenance",
2020
+ "profileAuthority",
2021
+ "package",
2022
+ "version",
2023
+ "versionKind",
2024
+ "registered",
2025
+ "publicManual",
2026
+ "generatedCanonical",
2027
+ "upstreamReportedMutates",
2028
+ "reviewedEffect",
2029
+ "arguments",
2030
+ "flags",
2031
+ "decision",
2032
+ "pathSemanticInputs",
2033
+ "output",
2034
+ "conditionalInputs",
2035
+ "reconciliation"
2036
+ ], ["semanticProfileSha256"], label);
2037
+ const path = commandPath(source.path, `${label}.path`);
2038
+ const args = array(source.arguments, `${label}.arguments`, 32).map((item, index) => parseArgument(item, `${label}.arguments[${index}]`));
2039
+ const normalizedArgumentNames = args.map((argument) => argument.name.replaceAll("-", "_"));
2040
+ if (new Set(normalizedArgumentNames).size !== normalizedArgumentNames.length) {
2041
+ throw new Error(`${label}.arguments repeat a normalized name`);
2042
+ }
2043
+ const positions = args.map((argument) => argument.position);
2044
+ if (positions.some((position, index) => position !== index)) {
2045
+ throw new Error(`${label}.arguments positions must be contiguous from zero`);
2046
+ }
2047
+ const flags = array(source.flags, `${label}.flags`, 128).map((item, index) => parseFlag(item, `${label}.flags[${index}]`));
2048
+ if (new Set(flags.map((flag) => flag.name)).size !== flags.length) {
2049
+ throw new Error(`${label}.flags repeat a long name`);
2050
+ }
2051
+ if (flags.some((flag) => flag.source !== "command")) {
2052
+ throw new Error(`${label}.flags must be command flags`);
2053
+ }
2054
+ const normalizedFlagNames = flags.map((flag) => flag.name.slice(2).replaceAll("-", "_"));
2055
+ if (normalizedFlagNames.some((name) => normalizedArgumentNames.includes(name))) {
2056
+ throw new Error(`${label} repeats a normalized argument/flag field`);
2057
+ }
2058
+ const conditionalInputs = array(source.conditionalInputs, `${label}.conditionalInputs`, 64).map((item, index) => parseRule(item, `${label}.conditionalInputs[${index}]`, predicateTraversal));
2059
+ const upstreamReportedMutates = source.upstreamReportedMutates === null ? null : boolean(source.upstreamReportedMutates, `${label}.upstreamReportedMutates`);
2060
+ return Object.freeze({
2061
+ path,
2062
+ provenance: exactEnum(source.provenance, `${label}.provenance`, LOCAL_CLI_SURFACE_PROVENANCE_KINDS),
2063
+ profileAuthority: exactEnum(source.profileAuthority, `${label}.profileAuthority`, [
2064
+ "tagged-source",
2065
+ "jit-plugin-source"
2066
+ ]),
2067
+ package: nullableString(source.package, `${label}.package`),
2068
+ version: nullableString(source.version, `${label}.version`),
2069
+ versionKind: parseVersionKind(source.versionKind, source.version, `${label}.versionKind`),
2070
+ registered: boolean(source.registered, `${label}.registered`),
2071
+ publicManual: boolean(source.publicManual, `${label}.publicManual`),
2072
+ generatedCanonical: boolean(source.generatedCanonical, `${label}.generatedCanonical`),
2073
+ upstreamReportedMutates,
2074
+ reviewedEffect: exactEnum(source.reviewedEffect, `${label}.reviewedEffect`, [
2075
+ "read",
2076
+ "write",
2077
+ "input-dependent"
2078
+ ]),
2079
+ arguments: Object.freeze(args),
2080
+ flags: Object.freeze(flags),
2081
+ decision: parseDecision(source.decision, `${label}.decision`),
2082
+ pathSemanticInputs: parsePathSemanticInputs(source.pathSemanticInputs, `${label}.pathSemanticInputs`),
2083
+ output: parseOutput(source.output, `${label}.output`),
2084
+ conditionalInputs: Object.freeze(conditionalInputs),
2085
+ reconciliation: parseReconciliation(source.reconciliation, `${label}.reconciliation`, predicateTraversal)
2086
+ });
2087
+ }
2088
+ function parseAdditionalEntry(value, label) {
2089
+ const source = record(value, label);
2090
+ exactKeys(source, [
2091
+ "path",
2092
+ "provenance",
2093
+ "profileAuthority",
2094
+ "canonicalTarget",
2095
+ "package",
2096
+ "version",
2097
+ "versionKind",
2098
+ "registered",
2099
+ "publicManual",
2100
+ "rationale",
2101
+ "decision"
2102
+ ], [], label);
2103
+ const path = commandPath(source.path, `${label}.path`);
2104
+ const canonicalTarget = source.canonicalTarget === null ? null : commandPath(source.canonicalTarget, `${label}.canonicalTarget`);
2105
+ return Object.freeze({
2106
+ path,
2107
+ provenance: exactEnum(source.provenance, `${label}.provenance`, LOCAL_CLI_SURFACE_PROVENANCE_KINDS),
2108
+ profileAuthority: exactEnum(source.profileAuthority, `${label}.profileAuthority`, [
2109
+ "tagged-source",
2110
+ "framework-runtime",
2111
+ "documentation"
2112
+ ]),
2113
+ canonicalTarget,
2114
+ package: nullableString(source.package, `${label}.package`),
2115
+ version: nullableString(source.version, `${label}.version`),
2116
+ versionKind: parseVersionKind(source.versionKind, source.version, `${label}.versionKind`),
2117
+ registered: boolean(source.registered, `${label}.registered`),
2118
+ publicManual: boolean(source.publicManual, `${label}.publicManual`),
2119
+ rationale: string(source.rationale, `${label}.rationale`, 1000),
2120
+ decision: parseDecision(source.decision, `${label}.decision`)
2121
+ });
2122
+ }
2123
+ function flagSpellings(flag) {
2124
+ return Object.freeze([
2125
+ flag.name,
2126
+ ...flag.allowNo ? [`--no-${flag.name.slice(2)}`] : [],
2127
+ ...flag.aliases
2128
+ ]);
2129
+ }
2130
+ function predicateFieldNames(predicate) {
2131
+ if (predicate.op === "true")
2132
+ return Object.freeze([]);
2133
+ if (predicate.op === "present" || predicate.op === "eq") {
2134
+ return Object.freeze([predicate.field]);
2135
+ }
2136
+ if (predicate.op === "not")
2137
+ return predicateFieldNames(predicate.predicate);
2138
+ return Object.freeze(predicate.predicates.flatMap(predicateFieldNames));
2139
+ }
2140
+ function validatePredicateTypes(predicate, fieldTypes, label) {
2141
+ if (predicate.op === "true" || predicate.op === "present")
2142
+ return;
2143
+ if (predicate.op === "eq") {
2144
+ const expected = fieldTypes[predicate.field];
2145
+ if (expected === undefined || predicate.value !== null && expected !== "file" && expected !== "array" && typeof predicate.value !== expected || (expected === "file" || expected === "array") && predicate.value !== null)
2146
+ throw new Error(`${label} equality value does not match field ${predicate.field}`);
2147
+ return;
2148
+ }
2149
+ if (predicate.op === "not") {
2150
+ validatePredicateTypes(predicate.predicate, fieldTypes, `${label}.predicate`);
2151
+ return;
2152
+ }
2153
+ predicate.predicates.forEach((item, index) => validatePredicateTypes(item, fieldTypes, `${label}.predicates[${index}]`));
2154
+ }
2155
+ function ruleFieldNames(rule) {
2156
+ return Object.freeze([
2157
+ ...predicateFieldNames(rule.when),
2158
+ ...rule.require,
2159
+ ...rule.requireAny,
2160
+ ...rule.exactlyOne,
2161
+ ...rule.forbid
2162
+ ]);
2163
+ }
2164
+ function parseArtifact(value, label) {
2165
+ const source = record(value, label);
2166
+ exactKeys(source, ["platform", "arch", "archiveSha256", "executableSha256"], [], label);
2167
+ return Object.freeze({
2168
+ platform: string(source.platform, `${label}.platform`, 32),
2169
+ arch: string(source.arch, `${label}.arch`, 32),
2170
+ archiveSha256: sha(source.archiveSha256, `${label}.archiveSha256`),
2171
+ executableSha256: sha(source.executableSha256, `${label}.executableSha256`)
2172
+ });
2173
+ }
2174
+ function parseDefinition(value) {
2175
+ const source = record(value, "local CLI surface contract");
2176
+ exactKeys(source, [
2177
+ "schemaVersion",
2178
+ "format",
2179
+ "surface",
2180
+ "executable",
2181
+ "source",
2182
+ "sdk",
2183
+ "runtime",
2184
+ "globalFlags",
2185
+ "commands",
2186
+ "additionalEntries"
2187
+ ], ["digests"], "local CLI surface contract");
2188
+ if (source.schemaVersion !== 1 || source.format !== "wrench.local-cli-surface") {
2189
+ throw new Error("local CLI surface contract version is unsupported");
2190
+ }
2191
+ const executable = record(source.executable, "local CLI surface executable");
2192
+ exactKeys(executable, [
2193
+ "id",
2194
+ "implementation",
2195
+ "releaseVersion",
2196
+ "releaseDate",
2197
+ "releaseTag",
2198
+ "releaseCommit",
2199
+ "releaseManifestSha256",
2200
+ "runtimeReportedName",
2201
+ "runtimeReportedVersion",
2202
+ "artifacts"
2203
+ ], [], "local CLI surface executable");
2204
+ const sourceIdentity = record(source.source, "local CLI surface source");
2205
+ exactKeys(sourceIdentity, [
2206
+ "package",
2207
+ "packagePath",
2208
+ "packageDeclaredVersion",
2209
+ "versionDiscrepancy",
2210
+ "generatedManualSha256",
2211
+ "generatedManualIncludesFlagsAndDefaults",
2212
+ "generatedManualEntries",
2213
+ "generatedCanonicalEntries",
2214
+ "registeredKeys"
2215
+ ], [], "local CLI surface source");
2216
+ const sdk = record(source.sdk, "local CLI surface SDK");
2217
+ exactKeys(sdk, ["package", "version", "commit"], [], "local CLI surface SDK");
2218
+ const runtime = record(source.runtime, "local CLI surface runtime");
2219
+ exactKeys(runtime, [
2220
+ "providerPluginId",
2221
+ "providerPluginVersion",
2222
+ "adapterId",
2223
+ "adapterVersion",
2224
+ "operationContractVersions",
2225
+ "operationInputTypes",
2226
+ "target",
2227
+ "realm",
2228
+ "compatibility"
2229
+ ], [], "local CLI surface runtime");
2230
+ const rawOperationContractVersions = record(runtime.operationContractVersions, "local CLI surface runtime.operationContractVersions");
2231
+ const operationContractVersionKeys = Object.keys(rawOperationContractVersions).sort(codePointCompare);
2232
+ if (operationContractVersionKeys.length < 1 || operationContractVersionKeys.length > 1000) {
2233
+ throw new Error("local CLI surface runtime.operationContractVersions must contain 1 to 1000 operations");
2234
+ }
2235
+ const operationContractVersions = Object.freeze(Object.fromEntries(operationContractVersionKeys.map((operation) => {
2236
+ if (!isProviderPluginOperationName(operation)) {
2237
+ throw new Error(`local CLI surface runtime operation ${operation} is not a bounded semantic name`);
2238
+ }
2239
+ return [
2240
+ operation,
2241
+ integer(rawOperationContractVersions[operation], `local CLI surface runtime.operationContractVersions.${operation}`, 1, 1e6)
2242
+ ];
2243
+ })));
2244
+ const rawOperationInputTypes = record(runtime.operationInputTypes, "local CLI surface runtime.operationInputTypes");
2245
+ const operationInputTypeKeys = Object.keys(rawOperationInputTypes).sort(codePointCompare);
2246
+ if (operationInputTypeKeys.length !== operationContractVersionKeys.length || operationInputTypeKeys.some((operation, index) => operation !== operationContractVersionKeys[index]))
2247
+ throw new Error("local CLI surface runtime input fields must exactly cover operation versions");
2248
+ const operationInputTypes = Object.freeze(Object.fromEntries(operationInputTypeKeys.map((operation) => {
2249
+ const rawFields = record(rawOperationInputTypes[operation], `local CLI surface runtime.operationInputTypes.${operation}`);
2250
+ const fields = Object.keys(rawFields).sort(codePointCompare);
2251
+ if (fields.length > 256 || fields.some((field) => !/^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$/u.test(field)))
2252
+ throw new Error("local CLI surface runtime contains invalid semantic input fields");
2253
+ return [operation, Object.freeze(Object.fromEntries(fields.map((field) => [
2254
+ field,
2255
+ exactEnum(rawFields[field], `local CLI surface runtime.operationInputTypes.${operation}.${field}`, ["string", "number", "boolean", "array", "file"])
2256
+ ])))];
2257
+ })));
2258
+ const predicateTraversal = {
2259
+ seen: new WeakSet,
2260
+ nodes: 0
2261
+ };
2262
+ const commands = array(source.commands, "local CLI surface commands", 1000).map((item, index) => parseCommand(item, `local CLI surface commands[${index}]`, predicateTraversal));
2263
+ const commandPaths = commands.map((command) => command.path.join(" "));
2264
+ if (new Set(commandPaths).size !== commandPaths.length) {
2265
+ throw new Error("local CLI surface commands repeat a normalized path");
2266
+ }
2267
+ const globalFlags = array(source.globalFlags, "local CLI surface globalFlags", 128).map((item, index) => parseFlag(item, `local CLI surface globalFlags[${index}]`));
2268
+ if (globalFlags.some((flag) => flag.source !== "global") || new Set(globalFlags.map((flag) => flag.name)).size !== globalFlags.length)
2269
+ throw new Error("local CLI surface globalFlags must be unique global flags");
2270
+ if (globalFlags.some((flag) => flag.default.kind === "literal" && flag.default.authority === "jit-plugin-source")) {
2271
+ throw new Error("local CLI surface global flags cannot use JIT plugin default authority");
2272
+ }
2273
+ const globalSpellings = new Set;
2274
+ for (const flag of globalFlags) {
2275
+ for (const spelling of flagSpellings(flag)) {
2276
+ if (globalSpellings.has(spelling)) {
2277
+ throw new Error("local CLI surface globalFlags repeat a flag spelling");
2278
+ }
2279
+ globalSpellings.add(spelling);
2280
+ }
2281
+ }
2282
+ for (const command of commands) {
2283
+ const commandSpellings = new Set;
2284
+ for (const flag of command.flags) {
2285
+ for (const spelling of flagSpellings(flag)) {
2286
+ if (commandSpellings.has(spelling)) {
2287
+ throw new Error(`local CLI surface command ${command.path.join(" ")} repeats a flag spelling`);
2288
+ }
2289
+ if (spelling.startsWith("-") && !spelling.startsWith("--") && globalSpellings.has(spelling)) {
2290
+ throw new Error(`local CLI surface command ${command.path.join(" ")} shadows a global short alias`);
2291
+ }
2292
+ commandSpellings.add(spelling);
2293
+ }
2294
+ }
2295
+ }
2296
+ const additionalEntries = array(source.additionalEntries, "local CLI surface additionalEntries", 1000).map((item, index) => parseAdditionalEntry(item, `local CLI surface additionalEntries[${index}]`));
2297
+ const allPaths = [...commandPaths, ...additionalEntries.map((entry) => entry.path.join(" "))];
2298
+ if (new Set(allPaths).size !== allPaths.length) {
2299
+ throw new Error("local CLI surface entries repeat a normalized path");
2300
+ }
2301
+ const allPathSet = new Set(allPaths);
2302
+ for (const entry of additionalEntries) {
2303
+ if (entry.canonicalTarget !== null && !allPathSet.has(entry.canonicalTarget.join(" ")))
2304
+ throw new Error("local CLI surface entry has a dangling canonical target");
2305
+ }
2306
+ const additionalByPath = new Map(additionalEntries.map((entry) => [
2307
+ entry.path.join(" "),
2308
+ entry
2309
+ ]));
2310
+ const aliasVisitState = new Map;
2311
+ for (const entry of additionalEntries) {
2312
+ const chain = [];
2313
+ let path = entry.path.join(" ");
2314
+ while (true) {
2315
+ const state = aliasVisitState.get(path);
2316
+ if (state === "visiting") {
2317
+ throw new Error("local CLI surface canonical target graph contains an alias cycle");
2318
+ }
2319
+ if (state === "visited")
2320
+ break;
2321
+ aliasVisitState.set(path, "visiting");
2322
+ chain.push(path);
2323
+ const target = additionalByPath.get(path)?.canonicalTarget?.join(" ") ?? null;
2324
+ if (target === null || !additionalByPath.has(target))
2325
+ break;
2326
+ path = target;
2327
+ }
2328
+ for (const visited of chain)
2329
+ aliasVisitState.set(visited, "visited");
2330
+ }
2331
+ for (const command of commands) {
2332
+ if (command.profileAuthority === "tagged-source" && (!["built-in-canonical", "source-only-private"].includes(command.provenance) || command.package !== sourceIdentity.package || command.version !== sourceIdentity.packageDeclaredVersion || command.versionKind !== "exact"))
2333
+ throw new Error("local CLI surface tagged command profile has inconsistent source authority");
2334
+ if (command.profileAuthority === "jit-plugin-source" && (command.provenance !== "jit-plugin" || command.package === null || command.version === null || command.versionKind !== "range"))
2335
+ throw new Error("local CLI surface JIT command profile has inconsistent package authority");
2336
+ for (const item of [...command.arguments, ...command.flags]) {
2337
+ if (item.default.kind !== "literal")
2338
+ continue;
2339
+ if (command.profileAuthority === "jit-plugin-source" && item.default.authority !== "jit-plugin-source")
2340
+ throw new Error("local CLI surface JIT command literal default has inconsistent authority");
2341
+ if (command.profileAuthority === "tagged-source" && item.default.authority === "jit-plugin-source")
2342
+ throw new Error("local CLI surface tagged command literal default has inconsistent authority");
2343
+ }
2344
+ }
2345
+ for (const entry of additionalEntries) {
2346
+ if (entry.profileAuthority === "tagged-source" && (entry.package !== sourceIdentity.package || entry.version !== sourceIdentity.packageDeclaredVersion || entry.versionKind !== "exact"))
2347
+ throw new Error("local CLI surface tagged additional entry has inconsistent source authority");
2348
+ if (entry.profileAuthority === "documentation" && (entry.provenance !== "documented-only" || entry.package !== null || entry.version !== null))
2349
+ throw new Error("local CLI surface documented entry has inconsistent authority");
2350
+ }
2351
+ const artifacts = array(executable.artifacts, "local CLI surface executable.artifacts", 32).map((item, index) => parseArtifact(item, `local CLI surface executable.artifacts[${index}]`));
2352
+ const artifactCoordinates = artifacts.map((artifact) => `${artifact.platform}/${artifact.arch}`);
2353
+ if (artifacts.length < 1 || new Set(artifactCoordinates).size !== artifacts.length) {
2354
+ throw new Error("local CLI surface executable artifacts must be unique and nonempty");
2355
+ }
2356
+ const surface = string(source.surface, "local CLI surface contract.surface", 63);
2357
+ if (!/^[a-z][a-z0-9-]{0,62}$/u.test(surface)) {
2358
+ throw new Error("local CLI surface contract.surface must be a normalized surface ID");
2359
+ }
2360
+ const generatedManualEntries = integer(sourceIdentity.generatedManualEntries, "local CLI surface source.generatedManualEntries", 1, 1e4);
2361
+ const generatedCanonicalEntries = integer(sourceIdentity.generatedCanonicalEntries, "local CLI surface source.generatedCanonicalEntries", 1, 1e4);
2362
+ const registeredKeys = integer(sourceIdentity.registeredKeys, "local CLI surface source.registeredKeys", 1, 1e5);
2363
+ if (commands.filter((command) => command.publicManual).length !== generatedManualEntries || commands.filter((command) => command.generatedCanonical).length + additionalEntries.filter((entry) => entry.provenance === "built-in-hidden" && entry.profileAuthority === "tagged-source").length !== generatedCanonicalEntries || [
2364
+ ...commands,
2365
+ ...additionalEntries
2366
+ ].filter((entry) => entry.registered && entry.package === sourceIdentity.package).length !== registeredKeys)
2367
+ throw new Error("local CLI surface source counts do not match normalized entries");
2368
+ const installedOperations = new Set(operationContractVersionKeys);
2369
+ for (const decision of [
2370
+ ...globalFlags.map((flag) => flag.decision),
2371
+ ...commands.flatMap((command) => [
2372
+ command.decision,
2373
+ ...command.arguments.map((argument) => argument.decision),
2374
+ ...command.flags.map((flag) => flag.decision)
2375
+ ]),
2376
+ ...additionalEntries.map((entry) => entry.decision)
2377
+ ]) {
2378
+ if (decision.operation !== null && !installedOperations.has(decision.operation)) {
2379
+ throw new Error(`local CLI surface decision references uninstalled operation ${decision.operation}`);
2380
+ }
2381
+ }
2382
+ for (const command of commands) {
2383
+ if (command.decision.disposition === "supported" !== (command.decision.operation !== null)) {
2384
+ throw new Error(`local CLI surface command ${command.path.join(" ")} must bind an operation exactly when supported`);
2385
+ }
2386
+ for (const item of [...command.arguments, ...command.flags]) {
2387
+ if (item.decision.operation !== null && item.decision.operation !== command.decision.operation) {
2388
+ throw new Error(`local CLI surface command ${command.path.join(" ")} item operation differs from its command`);
2389
+ }
2390
+ }
2391
+ const upstreamFieldTypes = Object.freeze(Object.fromEntries([
2392
+ ...command.arguments.map((argument) => [
2393
+ argument.name.replaceAll("-", "_"),
2394
+ argument.valueType
2395
+ ]),
2396
+ ...command.flags.map((flag) => [
2397
+ flag.name.slice(2).replaceAll("-", "_"),
2398
+ flag.valueType
2399
+ ])
2400
+ ]));
2401
+ const semanticFieldTypes = command.decision.operation === null ? null : operationInputTypes[command.decision.operation] ?? null;
2402
+ for (const [field, value2] of Object.entries(command.pathSemanticInputs)) {
2403
+ if (semanticFieldTypes === null || !Object.hasOwn(semanticFieldTypes, field)) {
2404
+ throw new Error(`local CLI surface command ${command.path.join(" ")} path semantic input references unknown field ${field}`);
2405
+ }
2406
+ const expected = semanticFieldTypes[field];
2407
+ if (value2 !== null && (expected === "file" || expected === "array" || typeof value2 !== expected)) {
2408
+ throw new Error(`local CLI surface command ${command.path.join(" ")} path semantic input ${field} has the wrong type`);
2409
+ }
2410
+ }
2411
+ for (const [index, rule] of command.conditionalInputs.entries()) {
2412
+ const allowed = rule.namespace === "semantic-operation" ? semanticFieldTypes : upstreamFieldTypes;
2413
+ if (allowed === null) {
2414
+ throw new Error(`local CLI surface command ${command.path.join(" ")} has no semantic input namespace`);
2415
+ }
2416
+ for (const field of ruleFieldNames(rule)) {
2417
+ if (!Object.hasOwn(allowed, field)) {
2418
+ throw new Error(`local CLI surface command ${command.path.join(" ")} rule references unknown ${rule.namespace} field ${field}`);
2419
+ }
2420
+ }
2421
+ validatePredicateTypes(rule.when, allowed, `local CLI surface command ${command.path.join(" ")} conditionalInputs[${index}].when`);
2422
+ }
2423
+ if (command.reconciliation.predicate !== null) {
2424
+ if (semanticFieldTypes === null) {
2425
+ throw new Error(`local CLI surface command ${command.path.join(" ")} has no reconciliation input namespace`);
2426
+ }
2427
+ for (const field of predicateFieldNames(command.reconciliation.predicate)) {
2428
+ if (!Object.hasOwn(semanticFieldTypes, field)) {
2429
+ throw new Error(`local CLI surface command ${command.path.join(" ")} reconciliation references unknown semantic field ${field}`);
2430
+ }
2431
+ }
2432
+ validatePredicateTypes(command.reconciliation.predicate, semanticFieldTypes, `local CLI surface command ${command.path.join(" ")} reconciliation.predicate`);
2433
+ }
2434
+ }
2435
+ const releaseVersion = string(executable.releaseVersion, "local CLI surface executable.releaseVersion", 128);
2436
+ const runtimeReportedVersion = string(executable.runtimeReportedVersion, "local CLI surface executable.runtimeReportedVersion", 128);
2437
+ if (releaseVersion !== runtimeReportedVersion) {
2438
+ throw new Error("local CLI surface pinned release and runtime-reported versions must match");
2439
+ }
2440
+ const packageDeclaredVersion = string(sourceIdentity.packageDeclaredVersion, "local CLI surface source.packageDeclaredVersion", 128);
2441
+ const versionDiscrepancy = nullableString(sourceIdentity.versionDiscrepancy, "local CLI surface source.versionDiscrepancy");
2442
+ if (packageDeclaredVersion !== releaseVersion !== (versionDiscrepancy !== null)) {
2443
+ throw new Error("local CLI surface source version discrepancy must exactly match version divergence");
2444
+ }
2445
+ return Object.freeze({
2446
+ schemaVersion: 1,
2447
+ format: "wrench.local-cli-surface",
2448
+ surface,
2449
+ executable: Object.freeze({
2450
+ id: string(executable.id, "local CLI surface executable.id", 128),
2451
+ implementation: string(executable.implementation, "local CLI surface executable.implementation", 512),
2452
+ releaseVersion,
2453
+ releaseDate: canonicalDate(executable.releaseDate, "local CLI surface executable.releaseDate"),
2454
+ releaseTag: string(executable.releaseTag, "local CLI surface executable.releaseTag", 128),
2455
+ releaseCommit: commitSha(executable.releaseCommit, "local CLI surface executable.releaseCommit"),
2456
+ releaseManifestSha256: sha(executable.releaseManifestSha256, "local CLI surface executable.releaseManifestSha256"),
2457
+ runtimeReportedName: string(executable.runtimeReportedName, "local CLI surface executable.runtimeReportedName", 128),
2458
+ runtimeReportedVersion,
2459
+ artifacts: Object.freeze(artifacts)
2460
+ }),
2461
+ source: Object.freeze({
2462
+ package: string(sourceIdentity.package, "local CLI surface source.package", 128),
2463
+ packagePath: string(sourceIdentity.packagePath, "local CLI surface source.packagePath", 512),
2464
+ packageDeclaredVersion,
2465
+ versionDiscrepancy,
2466
+ generatedManualSha256: sha(sourceIdentity.generatedManualSha256, "local CLI surface source.generatedManualSha256"),
2467
+ generatedManualIncludesFlagsAndDefaults: boolean(sourceIdentity.generatedManualIncludesFlagsAndDefaults, "local CLI surface source.generatedManualIncludesFlagsAndDefaults"),
2468
+ generatedManualEntries,
2469
+ generatedCanonicalEntries,
2470
+ registeredKeys
2471
+ }),
2472
+ sdk: Object.freeze({
2473
+ package: string(sdk.package, "local CLI surface SDK.package", 128),
2474
+ version: string(sdk.version, "local CLI surface SDK.version", 128),
2475
+ commit: commitSha(sdk.commit, "local CLI surface SDK.commit")
2476
+ }),
2477
+ runtime: Object.freeze({
2478
+ providerPluginId: string(runtime.providerPluginId, "local CLI surface runtime.providerPluginId", 128),
2479
+ providerPluginVersion: string(runtime.providerPluginVersion, "local CLI surface runtime.providerPluginVersion", 128),
2480
+ adapterId: string(runtime.adapterId, "local CLI surface runtime.adapterId", 128),
2481
+ adapterVersion: string(runtime.adapterVersion, "local CLI surface runtime.adapterVersion", 128),
2482
+ operationContractVersions,
2483
+ operationInputTypes,
2484
+ target: string(runtime.target, "local CLI surface runtime.target", 128),
2485
+ realm: string(runtime.realm, "local CLI surface runtime.realm", 1000),
2486
+ compatibility: string(runtime.compatibility, "local CLI surface runtime.compatibility", 1000)
2487
+ }),
2488
+ globalFlags: Object.freeze(globalFlags),
2489
+ commands: Object.freeze(commands),
2490
+ additionalEntries: Object.freeze(additionalEntries)
2491
+ });
2492
+ }
2493
+ function upstreamProjection(definition) {
2494
+ return {
2495
+ executable: definition.executable,
2496
+ source: {
2497
+ package: definition.source.package,
2498
+ packagePath: definition.source.packagePath,
2499
+ packageDeclaredVersion: definition.source.packageDeclaredVersion,
2500
+ generatedManualSha256: definition.source.generatedManualSha256,
2501
+ generatedManualIncludesFlagsAndDefaults: definition.source.generatedManualIncludesFlagsAndDefaults,
2502
+ generatedManualEntries: definition.source.generatedManualEntries,
2503
+ generatedCanonicalEntries: definition.source.generatedCanonicalEntries,
2504
+ registeredKeys: definition.source.registeredKeys
2505
+ },
2506
+ sdk: definition.sdk,
2507
+ globalFlags: definition.globalFlags.map(({ decision: _decision, ...flag }) => flag),
2508
+ commands: definition.commands.map((command) => ({
2509
+ path: command.path,
2510
+ provenance: command.provenance,
2511
+ profileAuthority: command.profileAuthority,
2512
+ package: command.package,
2513
+ version: command.version,
2514
+ versionKind: command.versionKind,
2515
+ registered: command.registered,
2516
+ publicManual: command.publicManual,
2517
+ generatedCanonical: command.generatedCanonical,
2518
+ upstreamReportedMutates: command.upstreamReportedMutates,
2519
+ arguments: command.arguments.map(({ decision: _decision, ...argument }) => argument),
2520
+ flags: command.flags.map(({ decision: _decision, ...flag }) => flag)
2521
+ })),
2522
+ additionalEntries: definition.additionalEntries.map((entry) => ({
2523
+ path: entry.path,
2524
+ provenance: entry.provenance,
2525
+ profileAuthority: entry.profileAuthority,
2526
+ canonicalTarget: entry.canonicalTarget,
2527
+ package: entry.package,
2528
+ version: entry.version,
2529
+ versionKind: entry.versionKind,
2530
+ registered: entry.registered,
2531
+ publicManual: entry.publicManual
2532
+ }))
2533
+ };
2534
+ }
2535
+ function classificationProjection(definition) {
2536
+ return {
2537
+ runtime: {
2538
+ operationContractVersions: definition.runtime.operationContractVersions,
2539
+ operationInputTypes: definition.runtime.operationInputTypes
2540
+ },
2541
+ globalFlags: definition.globalFlags.map((flag) => ({
2542
+ name: flag.name,
2543
+ source: flag.source,
2544
+ decision: flag.decision
2545
+ })),
2546
+ commands: definition.commands.map((command) => ({
2547
+ path: command.path,
2548
+ provenance: command.provenance,
2549
+ reviewedEffect: command.reviewedEffect,
2550
+ decision: command.decision,
2551
+ pathSemanticInputs: command.pathSemanticInputs,
2552
+ arguments: command.arguments.map((argument) => ({ name: argument.name, decision: argument.decision })),
2553
+ flags: command.flags.map((flag) => ({ name: flag.name, source: flag.source, decision: flag.decision }))
2554
+ })),
2555
+ additionalEntries: definition.additionalEntries.map((entry) => ({
2556
+ path: entry.path,
2557
+ provenance: entry.provenance,
2558
+ decision: entry.decision
2559
+ }))
2560
+ };
2561
+ }
2562
+ function semanticProfile(command) {
2563
+ return {
2564
+ path: command.path,
2565
+ provenance: command.provenance,
2566
+ profileAuthority: command.profileAuthority,
2567
+ package: command.package,
2568
+ version: command.version,
2569
+ versionKind: command.versionKind,
2570
+ registered: command.registered,
2571
+ upstreamReportedMutates: command.upstreamReportedMutates,
2572
+ reviewedEffect: command.reviewedEffect,
2573
+ arguments: command.arguments,
2574
+ flags: command.flags,
2575
+ decision: command.decision,
2576
+ pathSemanticInputs: command.pathSemanticInputs,
2577
+ output: command.output,
2578
+ conditionalInputs: command.conditionalInputs,
2579
+ reconciliation: command.reconciliation
2580
+ };
2581
+ }
2582
+ function buildContract(definitionValue) {
2583
+ const definition = parseDefinition(definitionValue);
2584
+ const commands = definition.commands.map((command) => Object.freeze({
2585
+ ...command,
2586
+ semanticProfileSha256: sha256(surfaceCanonicalJson(semanticProfile(command)))
2587
+ }));
2588
+ const semanticProfileMap = commands.map((command) => ({
2589
+ path: command.path,
2590
+ semanticProfileSha256: command.semanticProfileSha256
2591
+ }));
2592
+ return Object.freeze({
2593
+ ...definition,
2594
+ commands: Object.freeze(commands),
2595
+ digests: Object.freeze({
2596
+ upstreamSurfaceSha256: sha256(surfaceCanonicalJson(upstreamProjection(definition))),
2597
+ classificationSha256: sha256(surfaceCanonicalJson(classificationProjection(definition))),
2598
+ semanticProfilesSha256: sha256(surfaceCanonicalJson(semanticProfileMap)),
2599
+ wholeSurfaceSha256: sha256(surfaceCanonicalJson(definition))
2600
+ })
2601
+ });
2602
+ }
2603
+ function defineLocalCliSurfaceContractV1(definition) {
2604
+ return buildContract(definition);
2605
+ }
2606
+
2607
+ // src/providers/beeper-local.ts
2608
+ var BEEPER_CLI_DARWIN_ARM64_ARTIFACT_PIN = Object.freeze({
2609
+ platform: "darwin",
2610
+ arch: "arm64",
2611
+ archiveSha256: "688ccde7e7d044d33980cd06474bf1ae7215ccf8ca79967262fa3bfb85a2589a",
2612
+ executableSha256: "48aa895449129c793a212ea19f69a534adc34a8adc4037ca1d7da9e648716425",
2613
+ downloadUrl: "https://github.com/beeper/cli/releases/download/v0.6.2/beeper-cli-0.6.2-macos-arm64.zip"
2614
+ });
2615
+ var BEEPER_CLI_PIN = Object.freeze({
2616
+ id: "beeper-cli",
2617
+ implementation: "github.com/beeper/cli",
2618
+ version: "0.6.2",
2619
+ commit: "a416af06023449a87312dc11e54643fd9dc94b8c",
2620
+ releaseManifestSha256: "5c52b533180151b97e26138ef687b6b819170687b34a478184e5648335356950",
2621
+ releaseManifestUrl: "https://github.com/beeper/cli/releases/download/v0.6.2/binaries.json",
2622
+ releaseUrl: "https://github.com/beeper/cli/releases/tag/v0.6.2",
2623
+ sourceUrl: "https://github.com/beeper/cli/tree/a416af06023449a87312dc11e54643fd9dc94b8c",
2624
+ darwinArm64ArchiveSha256: BEEPER_CLI_DARWIN_ARM64_ARTIFACT_PIN.archiveSha256,
2625
+ darwinArm64BinarySha256: BEEPER_CLI_DARWIN_ARM64_ARTIFACT_PIN.executableSha256,
2626
+ downloadUrl: BEEPER_CLI_DARWIN_ARM64_ARTIFACT_PIN.downloadUrl,
2627
+ artifacts: Object.freeze([
2628
+ BEEPER_CLI_DARWIN_ARM64_ARTIFACT_PIN,
2629
+ Object.freeze({
2630
+ platform: "darwin",
2631
+ arch: "x64",
2632
+ archiveSha256: "4113a1979cfbd7839f14743158e70c12efa941313afb77ab2b11a08309196186",
2633
+ executableSha256: "83bb89edb6eeb9c61ebdb6ec940e0db30c90ecbca61d60a7408fe336e255f22e",
2634
+ downloadUrl: "https://github.com/beeper/cli/releases/download/v0.6.2/beeper-cli-0.6.2-macos-x64.zip"
2635
+ }),
2636
+ Object.freeze({
2637
+ platform: "linux",
2638
+ arch: "arm64",
2639
+ archiveSha256: "2bd37043a4ed863621edc59e28aaa652e8193e55abca0e9477f5aeae1c65d629",
2640
+ executableSha256: "102b8725bd99b03905dcff9fff645f3742e1697ce8d43ab9d8656896aafd12a8",
2641
+ downloadUrl: "https://github.com/beeper/cli/releases/download/v0.6.2/beeper-cli-0.6.2-linux-arm64.tar.gz"
2642
+ }),
2643
+ Object.freeze({
2644
+ platform: "linux",
2645
+ arch: "x64",
2646
+ archiveSha256: "a881e1d2bc91e31218b251716644ec5f8d161d5ccb30e7eab66cf2ba6410511d",
2647
+ executableSha256: "723cc3a6c556fa21b6ba11db8377d6a29776aca1660da48f0072883d6452ae3d",
2648
+ downloadUrl: "https://github.com/beeper/cli/releases/download/v0.6.2/beeper-cli-0.6.2-linux-x64.tar.gz"
2649
+ })
2650
+ ])
2651
+ });
2652
+ var BEEPER_DESKTOP_API_PIN = Object.freeze({
2653
+ package: "@beeper/desktop-api",
2654
+ version: "5.0.0",
2655
+ commit: "b9c1714410139c2139b597338cd002d785653e85"
2656
+ });
2657
+ var BEEPER_DESKTOP_TARGET = "desktop";
2658
+ var BEEPER_MAX_FILE_BYTES = 500 * 1024 * 1024;
2659
+ var BEEPER_DESKTOP_BUNDLE_IDS = Object.freeze([
2660
+ "com.automattic.beeper.desktop",
2661
+ "com.automattic.beeper.desktop.nightly"
2662
+ ]);
2663
+ var BEEPER_LOCAL_OPERATION_NAMES = Object.freeze([
2664
+ "accounts.list",
2665
+ "accounts.read",
2666
+ "bridges.list",
2667
+ "bridges.read",
2668
+ "contacts.list",
2669
+ "contacts.search",
2670
+ "contacts.read",
2671
+ "messaging.list",
2672
+ "messaging.search",
2673
+ "conversations.read",
2674
+ "messaging.read",
2675
+ "messaging.content.search",
2676
+ "messaging.message.read",
2677
+ "messaging.context.read",
2678
+ "messaging.send",
2679
+ "reactions.set",
2680
+ "messaging.edit",
2681
+ "conversations.start",
2682
+ "conversations.archive.set",
2683
+ "conversations.pin.set",
2684
+ "conversations.mute.set",
2685
+ "conversations.read-state.set",
2686
+ "conversations.priority.set",
2687
+ "conversations.notify",
2688
+ "conversations.title.set",
2689
+ "conversations.description.set",
2690
+ "conversations.avatar.set",
2691
+ "conversations.draft.set",
2692
+ "conversations.disappearing.set",
2693
+ "conversations.reminder.set",
2694
+ "conversations.focus",
2695
+ "presence.set"
2696
+ ]);
2697
+ var BEEPER_LOCAL_OPERATION_CONTRACT_VERSIONS = Object.freeze({
2698
+ "accounts.list": 2,
2699
+ "accounts.read": 1,
2700
+ "bridges.list": 2,
2701
+ "bridges.read": 1,
2702
+ "contacts.list": 3,
2703
+ "contacts.search": 1,
2704
+ "contacts.read": 1,
2705
+ "messaging.list": 1,
2706
+ "messaging.search": 2,
2707
+ "conversations.read": 2,
2708
+ "messaging.read": 3,
2709
+ "messaging.content.search": 2,
2710
+ "messaging.message.read": 1,
2711
+ "messaging.context.read": 1,
2712
+ "messaging.send": 1,
2713
+ "reactions.set": 1,
2714
+ "messaging.edit": 1,
2715
+ "conversations.start": 1,
2716
+ "conversations.archive.set": 1,
2717
+ "conversations.pin.set": 1,
2718
+ "conversations.mute.set": 1,
2719
+ "conversations.read-state.set": 1,
2720
+ "conversations.priority.set": 1,
2721
+ "conversations.notify": 1,
2722
+ "conversations.title.set": 1,
2723
+ "conversations.description.set": 1,
2724
+ "conversations.avatar.set": 1,
2725
+ "conversations.draft.set": 1,
2726
+ "conversations.disappearing.set": 1,
2727
+ "conversations.reminder.set": 1,
2728
+ "conversations.focus": 1,
2729
+ "presence.set": 1
2730
+ });
2731
+ var BEEPER_LOCAL_CONTRACT_V2_OPERATIONS = Object.freeze([
2732
+ "accounts.list",
2733
+ "bridges.list",
2734
+ "contacts.list",
2735
+ "messaging.search",
2736
+ "conversations.read",
2737
+ "messaging.read",
2738
+ "messaging.content.search"
2739
+ ]);
2740
+ var BEEPER_LOCAL_CONTRACT_V3_OPERATIONS = Object.freeze([
2741
+ "contacts.list",
2742
+ "messaging.read"
2743
+ ]);
2744
+ var BEEPER_DESKTOP_LOOPBACK_V2_OPERATIONS = Object.freeze([
2745
+ "accounts.list",
2746
+ "messaging.search",
2747
+ "conversations.read",
2748
+ "messaging.read",
2749
+ "messaging.content.search"
2750
+ ]);
2751
+ function isBeeperDesktopLoopbackOperationContract(action, contractVersion) {
2752
+ return contractVersion === 2 && BEEPER_DESKTOP_LOOPBACK_V2_OPERATIONS.includes(action) || contractVersion === 3 && BEEPER_LOCAL_CONTRACT_V3_OPERATIONS.includes(action);
2753
+ }
2754
+ var BEEPER_LOCAL_OPERATION_RUNTIME_TRANSPORTS = Object.freeze(Object.fromEntries(BEEPER_LOCAL_OPERATION_NAMES.map((operation) => [
2755
+ operation,
2756
+ isBeeperDesktopLoopbackOperationContract(operation, BEEPER_LOCAL_OPERATION_CONTRACT_VERSIONS[operation]) ? "desktop-loopback" : "official-cli"
2757
+ ])));
2758
+ function beeperLocalSurfaceInputType(value) {
2759
+ if (value !== "string" && value !== "number" && value !== "boolean" && value !== "array" && value !== "file")
2760
+ throw new Error("Beeper adapter contains an unsupported operation input type");
2761
+ return value;
2762
+ }
2763
+ var adapterOperations = wrench_web_adapter_default.operations;
2764
+ var BEEPER_LOCAL_OPERATION_INPUT_TYPES = Object.freeze(Object.fromEntries(Object.keys(adapterOperations).sort().map((operation) => [
2765
+ operation,
2766
+ Object.freeze(Object.fromEntries(Object.keys(adapterOperations[operation].input.properties).sort().map((field) => [
2767
+ field,
2768
+ beeperLocalSurfaceInputType(adapterOperations[operation].input.properties[field].type)
2769
+ ])))
2770
+ ])));
2771
+ var readPolicy = (reason) => Object.freeze({
2772
+ effect: "read",
2773
+ risk: "R1",
2774
+ state: "observed",
2775
+ reason
2776
+ });
2777
+ var reversiblePolicy = (reason) => Object.freeze({
2778
+ effect: "write",
2779
+ risk: "R2",
2780
+ state: "desired",
2781
+ reason
2782
+ });
2783
+ var visiblePolicy = (reason) => Object.freeze({
2784
+ effect: "write",
2785
+ risk: "R3",
2786
+ state: "desired",
2787
+ reason
2788
+ });
2789
+ var BEEPER_LOCAL_OPERATIONS = Object.freeze({
2790
+ "accounts.list": readPolicy("list the exact account realm bound to local Beeper Desktop"),
2791
+ "accounts.read": readPolicy("read one exact connected-account projection"),
2792
+ "bridges.list": readPolicy("list a bounded bridge capability catalog"),
2793
+ "bridges.read": readPolicy("read one exact bridge and its non-secret capabilities"),
2794
+ "contacts.list": readPolicy("list one bounded account-aware contact projection"),
2795
+ "contacts.search": readPolicy("search one bounded account-aware contact candidate window"),
2796
+ "contacts.read": readPolicy("read one exact account-bound contact identity"),
2797
+ "messaging.list": readPolicy("list one bounded account-aware conversation projection"),
2798
+ "messaging.search": readPolicy("search one bounded conversation candidate window"),
2799
+ "conversations.read": readPolicy("read one exact account-bound conversation"),
2800
+ "messaging.read": readPolicy("read one bounded page from an exact conversation"),
2801
+ "messaging.content.search": readPolicy("search one bounded message-content candidate window"),
2802
+ "messaging.message.read": readPolicy("read one exact message from an exact conversation"),
2803
+ "messaging.context.read": readPolicy("read bounded context around one exact message"),
2804
+ "messaging.send": visiblePolicy("submit one confirmed text, file, sticker, or voice request to Beeper Desktop; network delivery is not asserted"),
2805
+ "reactions.set": reversiblePolicy("set or clear one exact reaction desired state"),
2806
+ "messaging.edit": visiblePolicy("edit one exact message authored by the current account"),
2807
+ "conversations.start": visiblePolicy("start one conversation with an exact account-bound user"),
2808
+ "conversations.archive.set": reversiblePolicy("set one conversation archive desired state"),
2809
+ "conversations.pin.set": reversiblePolicy("set one conversation pin desired state"),
2810
+ "conversations.mute.set": reversiblePolicy("set one conversation mute desired state"),
2811
+ "conversations.read-state.set": visiblePolicy("set one conversation read marker, which may emit a network read receipt"),
2812
+ "conversations.priority.set": reversiblePolicy("set one conversation inbox priority desired state"),
2813
+ "conversations.notify": visiblePolicy("send one explicit iMessage Notify Anyway alert"),
2814
+ "conversations.title.set": visiblePolicy("set one group-conversation title"),
2815
+ "conversations.description.set": visiblePolicy("set or clear one group-conversation description"),
2816
+ "conversations.avatar.set": visiblePolicy("set or clear one group-conversation avatar"),
2817
+ "conversations.draft.set": reversiblePolicy("set or clear one private conversation draft"),
2818
+ "conversations.disappearing.set": visiblePolicy("set a retention timer whose effects cannot be undone after messages expire"),
2819
+ "conversations.reminder.set": reversiblePolicy("set or clear one private conversation reminder"),
2820
+ "conversations.focus": reversiblePolicy("focus local Beeper Desktop on one exact conversation"),
2821
+ "presence.set": visiblePolicy("send one bounded typing or paused indicator")
2822
+ });
2823
+ var supported = (operation) => Object.freeze({ state: "supported", operation });
2824
+ var internalPreflight = (purpose) => Object.freeze({
2825
+ state: "internal-preflight",
2826
+ purpose
2827
+ });
2828
+ var unavailable = (reason) => Object.freeze({ state: "unavailable", reason });
2829
+ var BEEPER_CLI_COMMAND_COVERAGE = Object.freeze({
2830
+ setup: unavailable("installation-lifecycle"),
2831
+ "install desktop": unavailable("installation-lifecycle"),
2832
+ "install server": unavailable("installation-lifecycle"),
2833
+ "targets list": unavailable("target-lifecycle"),
2834
+ "bridges list": supported("bridges.list"),
2835
+ "bridges show": supported("bridges.read"),
2836
+ "targets add desktop": unavailable("target-lifecycle"),
2837
+ "targets add server": unavailable("target-lifecycle"),
2838
+ "targets add remote": unavailable("target-lifecycle"),
2839
+ "targets use": unavailable("target-lifecycle"),
2840
+ "targets show": unavailable("target-lifecycle"),
2841
+ "targets status": internalPreflight("desktop-target-realm-proof"),
2842
+ "targets start": unavailable("target-lifecycle"),
2843
+ "targets stop": unavailable("target-lifecycle"),
2844
+ "targets restart": unavailable("target-lifecycle"),
2845
+ "targets logs": unavailable("target-lifecycle"),
2846
+ "targets enable": unavailable("target-lifecycle"),
2847
+ "targets disable": unavailable("target-lifecycle"),
2848
+ "targets remove": unavailable("target-lifecycle"),
2849
+ "targets tunnel": unavailable("target-lifecycle"),
2850
+ "auth status": unavailable("authentication-and-verification"),
2851
+ "auth logout": unavailable("authentication-and-verification"),
2852
+ "auth email start": unavailable("authentication-and-verification"),
2853
+ "auth email response": unavailable("authentication-and-verification"),
2854
+ verify: unavailable("authentication-and-verification"),
2855
+ "verify status": unavailable("authentication-and-verification"),
2856
+ "verify approve": unavailable("authentication-and-verification"),
2857
+ "verify recovery-key": unavailable("authentication-and-verification"),
2858
+ "verify reset-recovery-key": unavailable("authentication-and-verification"),
2859
+ "verify cancel": unavailable("authentication-and-verification"),
2860
+ "verify list": unavailable("authentication-and-verification"),
2861
+ "verify start": unavailable("authentication-and-verification"),
2862
+ "verify show": unavailable("authentication-and-verification"),
2863
+ "verify sas": unavailable("authentication-and-verification"),
2864
+ "verify sas-confirm": unavailable("authentication-and-verification"),
2865
+ "verify qr-scan": unavailable("authentication-and-verification"),
2866
+ "verify qr-confirm": unavailable("authentication-and-verification"),
2867
+ "accounts list": supported("accounts.list"),
2868
+ "accounts add": unavailable("account-lifecycle-r4"),
2869
+ "accounts show": supported("accounts.read"),
2870
+ "accounts remove": unavailable("account-lifecycle-r4"),
2871
+ "accounts use": unavailable("account-lifecycle-r4"),
2872
+ "chats list": supported("messaging.list"),
2873
+ "chats search": supported("messaging.search"),
2874
+ "chats show": supported("conversations.read"),
2875
+ "chats start": supported("conversations.start"),
2876
+ "chats archive": supported("conversations.archive.set"),
2877
+ "chats unarchive": supported("conversations.archive.set"),
2878
+ "chats pin": supported("conversations.pin.set"),
2879
+ "chats unpin": supported("conversations.pin.set"),
2880
+ "chats mute": supported("conversations.mute.set"),
2881
+ "chats unmute": supported("conversations.mute.set"),
2882
+ "chats mark-read": supported("conversations.read-state.set"),
2883
+ "chats mark-unread": supported("conversations.read-state.set"),
2884
+ "chats priority": supported("conversations.priority.set"),
2885
+ "chats notify-anyway": supported("conversations.notify"),
2886
+ "chats rename": supported("conversations.title.set"),
2887
+ "chats description": supported("conversations.description.set"),
2888
+ "chats avatar": supported("conversations.avatar.set"),
2889
+ "chats draft": supported("conversations.draft.set"),
2890
+ "chats disappear": supported("conversations.disappearing.set"),
2891
+ "chats remind": supported("conversations.reminder.set"),
2892
+ "chats unremind": supported("conversations.reminder.set"),
2893
+ "chats focus": supported("conversations.focus"),
2894
+ "messages list": supported("messaging.read"),
2895
+ "messages search": supported("messaging.content.search"),
2896
+ "messages show": supported("messaging.message.read"),
2897
+ "messages context": supported("messaging.context.read"),
2898
+ "messages edit": supported("messaging.edit"),
2899
+ "messages delete": unavailable("destructive-message-deletion-r4"),
2900
+ "messages export": unavailable("caller-path-media-or-export"),
2901
+ "send text": supported("messaging.send"),
2902
+ "send file": supported("messaging.send"),
2903
+ "send react": supported("reactions.set"),
2904
+ "send sticker": supported("messaging.send"),
2905
+ "send unreact": supported("reactions.set"),
2906
+ "send voice": supported("messaging.send"),
2907
+ presence: supported("presence.set"),
2908
+ "contacts list": supported("contacts.list"),
2909
+ "contacts search": supported("contacts.search"),
2910
+ "contacts show": supported("contacts.read"),
2911
+ "media download": unavailable("caller-path-media-or-export"),
2912
+ export: unavailable("caller-path-media-or-export"),
2913
+ watch: unavailable("unbounded-event-stream"),
2914
+ rpc: unavailable("raw-api-or-rpc"),
2915
+ man: unavailable("cli-maintenance-or-documentation"),
2916
+ doctor: unavailable("target-lifecycle"),
2917
+ status: unavailable("target-lifecycle"),
2918
+ docs: unavailable("cli-maintenance-or-documentation"),
2919
+ version: internalPreflight("pinned-tool-version-proof"),
2920
+ completion: unavailable("cli-maintenance-or-documentation"),
2921
+ plugins: unavailable("cli-extension-or-configuration"),
2922
+ "plugins available": unavailable("cli-extension-or-configuration"),
2923
+ update: unavailable("cli-extension-or-configuration"),
2924
+ "config get": unavailable("cli-extension-or-configuration"),
2925
+ "config set": unavailable("cli-extension-or-configuration"),
2926
+ "config path": unavailable("cli-extension-or-configuration"),
2927
+ "config reset": unavailable("cli-extension-or-configuration"),
2928
+ "api get": unavailable("raw-api-or-rpc"),
2929
+ "api post": unavailable("raw-api-or-rpc"),
2930
+ "api request": unavailable("raw-api-or-rpc")
2931
+ });
2932
+ var BEEPER_CLI_V062_COMMAND_PROFILES = Object.freeze([
2933
+ ["setup", true, "success", [], [["--channel", [], "string", false, false, ["stable", "nightly"], "stable"], ["--desktop", [], "boolean", false, false, [], null], ["--email", [], "string", false, false, [], null], ["--install", [], "boolean", false, false, [], null], ["--local", [], "boolean", false, false, [], null], ["--oauth", [], "boolean", false, false, [], null], ["--remote", [], "string", false, false, [], null], ["--server", [], "boolean", false, false, [], null], ["--server-env", [], "string", false, false, ["production", "staging"], "production"], ["--username", [], "string", false, false, [], null]]],
2934
+ ["install desktop", true, "success", [], [["--channel", [], "string", false, false, ["stable", "nightly"], "stable"]]],
2935
+ ["install server", true, "success", [], [["--channel", [], "string", false, false, ["stable", "nightly"], "stable"], ["--server-env", [], "string", false, false, ["production", "staging"], "production"]]],
2936
+ ["targets list", false, "list", [], []],
2937
+ ["bridges list", false, "list", [], [["--available", [], "boolean", false, false, [], null], ["--provider", [], "string", false, false, ["local", "cloud", "self-hosted"], null]]],
2938
+ ["bridges show", false, "data", [["bridge", true]], []],
2939
+ ["targets add desktop", true, "success", [["name", false]], [["--default", [], "boolean", false, false, [], null], ["--port", [], "number", false, false, [], null], ["--server-env", [], "string", false, false, ["production", "staging"], "production"]]],
2940
+ ["targets add server", true, "success", [["name", false]], [["--default", [], "boolean", false, false, [], null], ["--port", [], "number", false, false, [], null], ["--server-env", [], "string", false, false, ["production", "staging"], "production"]]],
2941
+ ["targets add remote", true, "success", [["name", true], ["url", true]], [["--default", [], "boolean", false, false, [], null]]],
2942
+ ["targets use", true, "success", [["name", true]], []],
2943
+ ["targets show", false, "data", [["name", false]], []],
2944
+ ["targets status", false, "data", [["name", false]], []],
2945
+ ["targets start", true, "success", [["name", false]], []],
2946
+ ["targets stop", true, "success", [["name", false]], []],
2947
+ ["targets restart", true, "success", [["name", false]], []],
2948
+ ["targets logs", false, "data", [["name", false]], [["--all", [], "boolean", false, false, [], null], ["--files", [], "number", false, false, [], 5], ["--lines", [], "number", false, false, [], 200]]],
2949
+ ["targets enable", true, "success", [["name", false]], []],
2950
+ ["targets disable", true, "success", [["name", false]], []],
2951
+ ["targets remove", true, "success", [["name", true]], []],
2952
+ ["targets tunnel", false, "data", [["name", false]], [["--install", [], "boolean", false, false, [], false], ["--cloudflared-path", [], "string", false, false, [], null], ["--retries", [], "number", false, false, [], 5], ["--url-only", [], "boolean", false, false, [], false]]],
2953
+ ["auth status", false, "data", [], []],
2954
+ ["auth logout", true, "success", [], []],
2955
+ ["auth email start", true, "success", [], [["--email", [], "string", true, false, [], null]]],
2956
+ ["auth email response", false, "data", [], [["--code", [], "string", true, false, [], null], ["--setup-request-id", [], "string", true, false, [], null], ["--username", [], "string", false, false, [], null], ["--yes", [], "boolean", false, false, [], false]]],
2957
+ ["verify", false, "data", [], [["--user", [], "string", false, false, [], null]]],
2958
+ ["verify status", false, "data", [], []],
2959
+ ["verify approve", true, "success", [], [["--id", [], "string", false, false, [], null]]],
2960
+ ["verify recovery-key", true, "success", [], [["--key", [], "string", true, false, [], null]]],
2961
+ ["verify reset-recovery-key", true, "success", [], []],
2962
+ ["verify cancel", true, "success", [], [["--id", [], "string", false, false, [], null]]],
2963
+ ["verify list", false, "list", [], []],
2964
+ ["verify start", true, "success", [], [["--user", [], "string", false, false, [], null]]],
2965
+ ["verify show", false, "data", [], []],
2966
+ ["verify sas", true, "success", [], [["--id", [], "string", false, false, [], null]]],
2967
+ ["verify sas-confirm", true, "success", [], [["--id", [], "string", false, false, [], null]]],
2968
+ ["verify qr-scan", true, "success", [], [["--id", [], "string", false, false, [], null], ["--payload", [], "string", true, false, [], null]]],
2969
+ ["verify qr-confirm", true, "success", [], [["--id", [], "string", false, false, [], null]]],
2970
+ ["accounts list", false, "list", [], [["--account", [], "string", false, true, [], null], ["--ids", [], "boolean", false, false, [], null]]],
2971
+ ["accounts add", true, "success", [["bridge", false]], [["--cookie", [], "string", false, true, [], null], ["--field", [], "string", false, true, [], null], ["--flow", [], "string", false, false, [], null], ["--guided", [], "boolean", false, false, [], true], ["--login-id", [], "string", false, false, [], null], ["--non-interactive", [], "boolean", false, false, [], null], ["--webview", [], "boolean", false, false, [], null], ["--webview-backend", [], "string", false, false, ["auto", "chrome", "webkit"], "chrome"], ["--webview-timeout", [], "number", false, false, [], 120]]],
2972
+ ["accounts show", false, "data", [["account", true]], []],
2973
+ ["accounts remove", true, "success", [["account", true]], []],
2974
+ ["accounts use", true, "success", [["account", true]], []],
2975
+ ["chats list", false, "list", [], [["--account", [], "string", false, true, [], null], ["--archived", [], "boolean", false, false, [], null], ["--ids", [], "boolean", false, false, [], null], ["--limit", [], "number", false, false, [], 20], ["--low-priority", [], "boolean", false, false, [], null], ["--muted", [], "boolean", false, false, [], null], ["--pinned", [], "boolean", false, false, [], null], ["--unread", [], "boolean", false, false, [], null]]],
2976
+ ["chats search", false, "list", [["query", true]], [["--account", [], "string", false, true, [], null], ["--ids", [], "boolean", false, false, [], null], ["--limit", [], "number", false, false, [], 20]]],
2977
+ ["chats show", false, "data", [], [["--chat", [], "string", true, false, [], null], ["--max-participants", [], "number", false, false, [], null], ["--pick", [], "number", false, false, [], null]]],
2978
+ ["chats start", true, "success", [["user", true]], [["--account", [], "string", false, false, [], null], ["--title", [], "string", false, false, [], null]]],
2979
+ ["chats archive", true, "success", [], [["--chat", [], "string", true, false, [], null], ["--pick", [], "number", false, false, [], null]]],
2980
+ ["chats unarchive", true, "success", [], [["--chat", [], "string", true, false, [], null], ["--pick", [], "number", false, false, [], null]]],
2981
+ ["chats pin", true, "success", [], [["--chat", [], "string", true, false, [], null], ["--pick", [], "number", false, false, [], null]]],
2982
+ ["chats unpin", true, "success", [], [["--chat", [], "string", true, false, [], null], ["--pick", [], "number", false, false, [], null]]],
2983
+ ["chats mute", true, "success", [], [["--chat", [], "string", true, false, [], null], ["--pick", [], "number", false, false, [], null]]],
2984
+ ["chats unmute", true, "success", [], [["--chat", [], "string", true, false, [], null], ["--pick", [], "number", false, false, [], null]]],
2985
+ ["chats mark-read", true, "success", [], [["--chat", [], "string", true, false, [], null], ["--message", [], "string", false, false, [], null], ["--pick", [], "number", false, false, [], null]]],
2986
+ ["chats mark-unread", true, "success", [], [["--chat", [], "string", true, false, [], null], ["--message", [], "string", false, false, [], null], ["--pick", [], "number", false, false, [], null]]],
2987
+ ["chats priority", true, "success", [], [["--chat", [], "string", true, false, [], null], ["--level", [], "string", true, false, ["inbox", "low"], null], ["--pick", [], "number", false, false, [], null]]],
2988
+ ["chats notify-anyway", true, "success", [], [["--chat", [], "string", true, false, [], null], ["--pick", [], "number", false, false, [], null]]],
2989
+ ["chats rename", true, "success", [], [["--chat", [], "string", true, false, [], null], ["--pick", [], "number", false, false, [], null], ["--title", [], "string", true, false, [], null]]],
2990
+ ["chats description", true, "success", [], [["--chat", [], "string", true, false, [], null], ["--clear", [], "boolean", false, false, [], null], ["--description", [], "string", false, false, [], null], ["--pick", [], "number", false, false, [], null]]],
2991
+ ["chats avatar", true, "success", [], [["--chat", [], "string", true, false, [], null], ["--clear", [], "boolean", false, false, [], null], ["--file", [], "string", false, false, [], null], ["--pick", [], "number", false, false, [], null]]],
2992
+ ["chats draft", true, "success", [], [["--chat", [], "string", true, false, [], null], ["--clear", [], "boolean", false, false, [], null], ["--file", [], "string", false, false, [], null], ["--filename", [], "string", false, false, [], null], ["--mime", [], "string", false, false, [], null], ["--pick", [], "number", false, false, [], null], ["--text", [], "string", false, false, [], null]]],
2993
+ ["chats disappear", true, "success", [], [["--chat", [], "string", true, false, [], null], ["--pick", [], "number", false, false, [], null], ["--seconds", [], "string", true, false, [], null]]],
2994
+ ["chats remind", true, "success", [], [["--chat", [], "string", true, false, [], null], ["--dismiss-on-message", [], "boolean", false, false, [], null], ["--pick", [], "number", false, false, [], null], ["--when", [], "string", true, false, [], null]]],
2995
+ ["chats unremind", true, "success", [], [["--chat", [], "string", true, false, [], null], ["--pick", [], "number", false, false, [], null]]],
2996
+ ["chats focus", true, "success", [], [["--attachment", [], "string", false, false, [], null], ["--chat", [], "string", true, false, [], null], ["--draft", [], "string", false, false, [], null], ["--message", [], "string", false, false, [], null], ["--pick", [], "number", false, false, [], null]]],
2997
+ ["messages list", false, "list", [], [["--after-cursor", [], "string", false, false, [], null], ["--asc", [], "boolean", false, false, [], null], ["--before-cursor", [], "string", false, false, [], null], ["--chat", [], "string", true, false, [], null], ["--ids", [], "boolean", false, false, [], null], ["--limit", [], "number", false, false, [], 50], ["--pick", [], "number", false, false, [], null], ["--sender", [], "string", false, false, [], null]]],
2998
+ ["messages search", false, "list", [["query", false]], [["--account", [], "string", false, true, [], null], ["--after", [], "string", false, false, [], null], ["--before", [], "string", false, false, [], null], ["--chat", [], "string", false, true, [], null], ["--chat-type", [], "string", false, false, ["group", "single"], null], ["--exclude-low-priority", [], "boolean", false, false, [], true], ["--ids", [], "boolean", false, false, [], null], ["--include-muted", [], "boolean", false, false, [], true], ["--limit", [], "number", false, false, [], 50], ["--media", [], "string", false, true, ["any", "video", "image", "link", "file"], null], ["--sender", [], "string", false, false, [], null]]],
2999
+ ["messages show", false, "data", [], [["--chat", [], "string", true, false, [], null], ["--id", [], "string", true, false, [], null], ["--pick", [], "number", false, false, [], null]]],
3000
+ ["messages context", false, "data", [], [["--after", [], "number", false, false, [], 10], ["--before", [], "number", false, false, [], 10], ["--chat", [], "string", true, false, [], null], ["--id", [], "string", true, false, [], null], ["--pick", [], "number", false, false, [], null]]],
3001
+ ["messages edit", true, "success", [], [["--chat", [], "string", true, false, [], null], ["--id", [], "string", true, false, [], null], ["--message", [], "string", true, false, [], null], ["--pick", [], "number", false, false, [], null]]],
3002
+ ["messages delete", true, "success", [], [["--chat", [], "string", true, false, [], null], ["--for-everyone", [], "boolean", false, false, [], null], ["--id", [], "string", true, false, [], null], ["--pick", [], "number", false, false, [], null]]],
3003
+ ["messages export", false, "data", [], [["--after", [], "string", false, false, [], null], ["--after-cursor", [], "string", false, false, [], null], ["--asc", [], "boolean", false, false, [], null], ["--before", [], "string", false, false, [], null], ["--before-cursor", [], "string", false, false, [], null], ["--chat", [], "string", true, false, [], null], ["--limit", [], "number", false, false, [], null], ["--output", ["-o"], "string", false, false, [], "-"], ["--pick", [], "number", false, false, [], null]]],
3004
+ ["send text", true, "send-result", [], [["--mention", [], "string", false, true, [], null], ["--message", [], "string", true, false, [], null], ["--no-preview", [], "boolean", false, false, [], null], ["--pick", [], "number", false, false, [], null], ["--reply-to", [], "string", false, false, [], null], ["--to", [], "string", true, false, [], null], ["--wait", [], "boolean", false, false, [], null], ["--wait-timeout", [], "number", false, false, [], 30000]]],
3005
+ ["send file", true, "send-result", [], [["--caption", [], "string", false, false, [], null], ["--file", [], "string", true, false, [], null], ["--filename", [], "string", false, false, [], null], ["--mime", [], "string", false, false, [], null], ["--pick", [], "number", false, false, [], null], ["--reply-to", [], "string", false, false, [], null], ["--to", [], "string", true, false, [], null], ["--wait", [], "boolean", false, false, [], null], ["--wait-timeout", [], "number", false, false, [], 30000]]],
3006
+ ["send react", true, "send-result", [], [["--id", [], "string", true, false, [], null], ["--pick", [], "number", false, false, [], null], ["--reaction", [], "string", true, false, [], null], ["--to", [], "string", true, false, [], null], ["--transaction", [], "string", false, false, [], null]]],
3007
+ ["send sticker", true, "send-result", [], [["--file", [], "string", true, false, [], null], ["--filename", [], "string", false, false, [], null], ["--mime", [], "string", false, false, [], "image/webp"], ["--pick", [], "number", false, false, [], null], ["--reply-to", [], "string", false, false, [], null], ["--to", [], "string", true, false, [], null], ["--wait", [], "boolean", false, false, [], null], ["--wait-timeout", [], "number", false, false, [], 30000]]],
3008
+ ["send unreact", true, "send-result", [], [["--id", [], "string", true, false, [], null], ["--pick", [], "number", false, false, [], null], ["--reaction", [], "string", true, false, [], null], ["--to", [], "string", true, false, [], null], ["--transaction", [], "string", false, false, [], null]]],
3009
+ ["send voice", true, "send-result", [], [["--duration", [], "number", false, false, [], null], ["--file", [], "string", true, false, [], null], ["--filename", [], "string", false, false, [], null], ["--mime", [], "string", false, false, [], "audio/ogg"], ["--pick", [], "number", false, false, [], null], ["--reply-to", [], "string", false, false, [], null], ["--to", [], "string", true, false, [], null], ["--wait", [], "boolean", false, false, [], null], ["--wait-timeout", [], "number", false, false, [], 30000]]],
3010
+ ["presence", false, "data", [], [["--chat", [], "string", true, false, [], null], ["--duration", [], "number", false, false, [], null], ["--pick", [], "number", false, false, [], null], ["--state", [], "string", false, false, ["typing", "paused"], "typing"]]],
3011
+ ["contacts list", false, "list", [], [["--account", [], "string", false, true, [], null], ["--ids", [], "boolean", false, false, [], null], ["--limit", [], "number", false, false, [], 50], ["--query", [], "string", false, false, [], null]]],
3012
+ ["contacts search", false, "list", [["query", true]], [["--account", [], "string", false, true, [], null]]],
3013
+ ["contacts show", false, "data", [["id", true]], [["--account", [], "string", false, true, [], null]]],
3014
+ ["media download", false, "data", [["url", true]], [["--out", ["-o"], "string", false, false, [], "."]]],
3015
+ ["export", false, "data", [], [["--account", [], "string", false, true, [], null], ["--chat", [], "string", false, true, [], null], ["--force", [], "boolean", false, false, [], null], ["--limit-chats", [], "number", false, false, [], null], ["--limit-messages", [], "number", false, false, [], null], ["--max-participants", [], "number", false, false, [], 500], ["--no-attachments", [], "boolean", false, false, [], null], ["--out", ["-o"], "string", false, false, [], "beeper-export"], ["--pick", [], "number", false, false, [], null], ["--quiet", [], "boolean", false, false, [], false]]],
3016
+ ["watch", false, "stream", [], [["--chat", ["-c"], "string", false, true, [], null], ["--exclude-type", [], "string", false, true, ["chat.upserted", "chat.deleted", "message.upserted", "message.deleted"], null], ["--include-type", [], "string", false, true, ["chat.upserted", "chat.deleted", "message.upserted", "message.deleted"], null], ["--json", [], "boolean", false, false, [], false], ["--webhook", [], "string", false, false, [], null], ["--webhook-queue", [], "number", false, false, [], 64], ["--webhook-secret", [], "string", false, false, [], null]]],
3017
+ ["rpc", false, "stream", [], []],
3018
+ ["man", false, "manual", [], []],
3019
+ ["doctor", false, "data", [], []],
3020
+ ["status", false, "data", [], []],
3021
+ ["docs", false, "data", [], []],
3022
+ ["version", false, "data", [], []],
3023
+ ["completion", false, "data", [["shell", false]], [["--refresh-cache", ["-r"], "boolean", false, false, [], null], ["--semantic", [], "boolean", false, false, [], null]]],
3024
+ ["plugins", false, "data", [], []],
3025
+ ["plugins available", false, "data", [], []],
3026
+ ["update", true, "success", [], [["--check", [], "boolean", false, false, [], null], ["--cli", [], "boolean", false, false, [], null], ["--desktop", [], "boolean", false, false, [], null], ["--server", [], "boolean", false, false, [], null]]],
3027
+ ["config get", false, "data", [["key", false, ["baseURL", "auth", "defaultTarget", "defaultAccount"]]], []],
3028
+ ["config set", true, "success", [["key", true, ["defaultTarget", "defaultAccount"]], ["value", true]], []],
3029
+ ["config path", false, "data", [], []],
3030
+ ["config reset", true, "success", [], []],
3031
+ ["api get", false, "data", [["path", true]], [["--json", [], "boolean", false, false, [], true], ["--no-auth", [], "boolean", false, false, [], false]]],
3032
+ ["api post", false, "data", [["path", true]], [["--body", [], "string", false, false, [], "{}"], ["--json", [], "boolean", false, false, [], true], ["--no-auth", [], "boolean", false, false, [], false]]],
3033
+ ["api request", false, "data", [["method", true, ["GET", "POST", "PUT", "PATCH", "DELETE"]], ["path", true]], [["--body", [], "string", false, false, [], null], ["--json", [], "boolean", false, false, [], true], ["--no-auth", [], "boolean", false, false, [], false]]]
3034
+ ]);
3035
+ var BEEPER_CLI_V062_PRIVATE_COMMAND_PROFILE = Object.freeze([
3036
+ "_complete",
3037
+ false,
3038
+ "list",
3039
+ [["kind", true, ["chat", "account", "contact", "target"]]],
3040
+ [
3041
+ ["--query", [], "string", false, false, [], null],
3042
+ ["--target", [], "string", false, false, [], null],
3043
+ ["--limit", [], "number", false, false, [], 25],
3044
+ ["--timeout-ms", [], "number", false, false, [], 1500]
3045
+ ]
3046
+ ]);
3047
+ var commandFlagCoordinate = (command, flag) => `${command}\x00${flag}`;
3048
+ var BEEPER_CLI_V062_ALLOW_NO_FLAGS = new Set([
3049
+ commandFlagCoordinate("accounts add", "--guided"),
3050
+ commandFlagCoordinate("api get", "--json"),
3051
+ commandFlagCoordinate("api post", "--json"),
3052
+ commandFlagCoordinate("api request", "--json"),
3053
+ commandFlagCoordinate("bridges list", "--available"),
3054
+ ...["--archived", "--low-priority", "--muted", "--pinned", "--unread"].map((flag) => commandFlagCoordinate("chats list", flag)),
3055
+ commandFlagCoordinate("messages search", "--exclude-low-priority"),
3056
+ commandFlagCoordinate("messages search", "--include-muted")
3057
+ ]);
3058
+ var BEEPER_CLI_V062_EXPLICIT_FALSE_BOOLEAN_FLAGS = new Set([
3059
+ ...["--desktop", "--install", "--local", "--oauth", "--server"].map((flag) => commandFlagCoordinate("setup", flag)),
3060
+ ...["targets add desktop", "targets add remote", "targets add server"].map((command) => commandFlagCoordinate(command, "--default")),
3061
+ commandFlagCoordinate("targets logs", "--all"),
3062
+ commandFlagCoordinate("accounts list", "--ids"),
3063
+ commandFlagCoordinate("accounts add", "--non-interactive"),
3064
+ commandFlagCoordinate("accounts add", "--webview"),
3065
+ commandFlagCoordinate("chats list", "--ids"),
3066
+ commandFlagCoordinate("chats search", "--ids"),
3067
+ commandFlagCoordinate("chats description", "--clear"),
3068
+ commandFlagCoordinate("chats avatar", "--clear"),
3069
+ commandFlagCoordinate("chats draft", "--clear"),
3070
+ commandFlagCoordinate("chats remind", "--dismiss-on-message"),
3071
+ commandFlagCoordinate("messages list", "--asc"),
3072
+ commandFlagCoordinate("messages list", "--ids"),
3073
+ commandFlagCoordinate("messages search", "--ids"),
3074
+ commandFlagCoordinate("messages delete", "--for-everyone"),
3075
+ commandFlagCoordinate("messages export", "--asc"),
3076
+ commandFlagCoordinate("send text", "--no-preview"),
3077
+ ...["send text", "send file", "send sticker", "send voice"].map((command) => commandFlagCoordinate(command, "--wait")),
3078
+ commandFlagCoordinate("contacts list", "--ids"),
3079
+ commandFlagCoordinate("export", "--force"),
3080
+ commandFlagCoordinate("export", "--no-attachments"),
3081
+ ...["--refresh-cache", "--semantic"].map((flag) => commandFlagCoordinate("completion", flag)),
3082
+ ...["--check", "--cli", "--desktop", "--server"].map((flag) => commandFlagCoordinate("update", flag))
3083
+ ]);
3084
+ function surfaceDecision(disposition, rationale, operation = null, replacement = null, fixedValue = null) {
3085
+ return Object.freeze({ disposition, rationale, operation, replacement, fixedValue });
3086
+ }
3087
+ var BEEPER_CLI_V062_GLOBAL_FLAGS = Object.freeze([
3088
+ Object.freeze({
3089
+ name: "--base-url",
3090
+ aliases: Object.freeze([]),
3091
+ source: "global",
3092
+ valueType: "string",
3093
+ allowNo: false,
3094
+ required: false,
3095
+ multiple: false,
3096
+ enum: Object.freeze([]),
3097
+ default: Object.freeze({ kind: "none" }),
3098
+ decision: surfaceDecision("fixed", "Wrench resolves and verifies the fixed Desktop loopback endpoint; callers cannot supply an endpoint.", null, null, "verified-desktop-loopback-endpoint")
3099
+ }),
3100
+ Object.freeze({
3101
+ name: "--target",
3102
+ aliases: Object.freeze(["-t"]),
3103
+ source: "global",
3104
+ valueType: "string",
3105
+ allowNo: false,
3106
+ required: false,
3107
+ multiple: false,
3108
+ enum: Object.freeze([]),
3109
+ default: Object.freeze({ kind: "derived", description: "configured CLI target" }),
3110
+ decision: surfaceDecision("fixed", "The provider is permanently bound to the Desktop target.", null, null, "desktop")
3111
+ }),
3112
+ Object.freeze({
3113
+ name: "--debug",
3114
+ aliases: Object.freeze([]),
3115
+ source: "global",
3116
+ valueType: "boolean",
3117
+ allowNo: false,
3118
+ required: false,
3119
+ multiple: false,
3120
+ enum: Object.freeze([]),
3121
+ default: Object.freeze({ kind: "literal", value: false, authority: "tagged-source" }),
3122
+ decision: surfaceDecision("unsupported", "Raw SDK debug output can contain provider internals and is never returned.")
3123
+ }),
3124
+ Object.freeze({
3125
+ name: "--events",
3126
+ aliases: Object.freeze([]),
3127
+ source: "global",
3128
+ valueType: "boolean",
3129
+ allowNo: false,
3130
+ required: false,
3131
+ multiple: false,
3132
+ enum: Object.freeze([]),
3133
+ default: Object.freeze({ kind: "literal", value: false, authority: "tagged-source" }),
3134
+ decision: surfaceDecision("replaced", "Wrench emits its own bounded operation lifecycle instead of raw CLI NDJSON.", null, "Wrench operation events")
3135
+ }),
3136
+ Object.freeze({
3137
+ name: "--full",
3138
+ aliases: Object.freeze([]),
3139
+ source: "global",
3140
+ valueType: "boolean",
3141
+ allowNo: false,
3142
+ required: false,
3143
+ multiple: false,
3144
+ enum: Object.freeze([]),
3145
+ default: Object.freeze({ kind: "literal", value: false, authority: "tagged-source" }),
3146
+ decision: surfaceDecision("fixed", "Wrench fixes --full true and independently enforces its output bound; the upstream core currently ignores the parsed value.", null, null, true)
3147
+ }),
3148
+ Object.freeze({
3149
+ name: "--json",
3150
+ aliases: Object.freeze([]),
3151
+ source: "global",
3152
+ valueType: "boolean",
3153
+ allowNo: false,
3154
+ required: false,
3155
+ multiple: false,
3156
+ enum: Object.freeze([]),
3157
+ default: Object.freeze({ kind: "literal", value: false, authority: "tagged-source" }),
3158
+ decision: surfaceDecision("fixed", "The provider always requests machine-readable output.", null, null, true)
3159
+ }),
3160
+ Object.freeze({
3161
+ name: "--quiet",
3162
+ aliases: Object.freeze(["-q"]),
3163
+ source: "global",
3164
+ valueType: "boolean",
3165
+ allowNo: false,
3166
+ required: false,
3167
+ multiple: false,
3168
+ enum: Object.freeze([]),
3169
+ default: Object.freeze({ kind: "literal", value: false, authority: "tagged-source" }),
3170
+ decision: surfaceDecision("fixed", "The provider always suppresses interactive presentation.", null, null, true)
3171
+ }),
3172
+ Object.freeze({
3173
+ name: "--read-only",
3174
+ aliases: Object.freeze([]),
3175
+ source: "global",
3176
+ valueType: "boolean",
3177
+ allowNo: false,
3178
+ required: false,
3179
+ multiple: false,
3180
+ enum: Object.freeze([]),
3181
+ default: Object.freeze({ kind: "literal", value: false, authority: "tagged-source" }),
3182
+ decision: surfaceDecision("absorbed", "Wrench fixes this flag for reads and uses kernel preview and confirmation for writes.")
3183
+ }),
3184
+ Object.freeze({
3185
+ name: "--timeout",
3186
+ aliases: Object.freeze([]),
3187
+ source: "global",
3188
+ valueType: "string",
3189
+ allowNo: false,
3190
+ required: false,
3191
+ multiple: false,
3192
+ enum: Object.freeze([]),
3193
+ default: Object.freeze({ kind: "none" }),
3194
+ decision: surfaceDecision("fixed", "The upstream core currently ignores --timeout; Wrench's outer process deadline is authoritative and callers cannot inject duration syntax.", null, null, "outer-process-deadline")
3195
+ }),
3196
+ Object.freeze({
3197
+ name: "--yes",
3198
+ aliases: Object.freeze(["-y"]),
3199
+ source: "global",
3200
+ valueType: "boolean",
3201
+ allowNo: false,
3202
+ required: false,
3203
+ multiple: false,
3204
+ enum: Object.freeze([]),
3205
+ default: Object.freeze({ kind: "literal", value: false, authority: "tagged-source" }),
3206
+ decision: surfaceDecision("absorbed", "The kernel owns explicit preview and confirmation before fixed noninteractive dispatch.")
3207
+ })
3208
+ ]);
3209
+ var INPUT_DEPENDENT_EFFECT_COMMANDS = new Set([
3210
+ "api request",
3211
+ "completion",
3212
+ "messages export",
3213
+ "media download",
3214
+ "plugins",
3215
+ "rpc",
3216
+ "update",
3217
+ "watch"
3218
+ ]);
3219
+ var REPORTED_READS_WITH_REVIEWED_WRITES = new Set([
3220
+ "auth email response",
3221
+ "api post",
3222
+ "export",
3223
+ "presence",
3224
+ "targets tunnel",
3225
+ "verify"
3226
+ ]);
3227
+ function reviewedEffect(command, upstreamReportedMutates) {
3228
+ if (INPUT_DEPENDENT_EFFECT_COMMANDS.has(command))
3229
+ return "input-dependent";
3230
+ return upstreamReportedMutates || REPORTED_READS_WITH_REVIEWED_WRITES.has(command) ? "write" : "read";
3231
+ }
3232
+ function surfaceCommandDecision(command) {
3233
+ if (command === "_complete") {
3234
+ return surfaceDecision("unsupported", "Private source completion internals can resolve fuzzy live identities and are outside provider authority.", null, "Wrench capability metadata and exact semantic IDs");
3235
+ }
3236
+ if (command === "accounts add" || command === "accounts remove") {
3237
+ return surfaceDecision("R4", "Account lifecycle is operator-only administration and has no routine provider operation.");
3238
+ }
3239
+ if (command === "messages delete") {
3240
+ return surfaceDecision("R4", "Deletion stays inert: upstream can silently fall back from delete-for-everyone to local deletion and only returns success/void with no provable effect.", null, "No dispatch without exact external confirmation and effect proof");
3241
+ }
3242
+ if (command === "accounts use") {
3243
+ return surfaceDecision("absorbed", "Mutable default-account selection is replaced by an exact account_id on every account-aware operation.", null, "Explicit account_id");
3244
+ }
3245
+ if (command === "export") {
3246
+ return surfaceDecision("internal", "Only the existing bounded private archive path may invoke top-level export with Wrench-owned output, limits, and no attachments.", null, "Internal bounded private export");
3247
+ }
3248
+ const legacy = BEEPER_CLI_COMMAND_COVERAGE[command];
3249
+ if (legacy === undefined)
3250
+ throw new Error(`Beeper surface command ${command} lacks a disposition`);
3251
+ if (legacy.state === "supported") {
3252
+ return surfaceDecision("supported", `A bounded semantic ${legacy.operation} operation covers this command without raw argv authority.`, legacy.operation);
3253
+ }
3254
+ if (legacy.state === "internal-preflight") {
3255
+ return surfaceDecision("internal", `This command is restricted to the ${legacy.purpose} runtime preflight.`);
3256
+ }
3257
+ const special = command === "messages export" ? "A bounded private messages artifact is not yet exposed; caller paths and buffered stdout remain forbidden." : command === "media download" ? "No media operation exists until an opaque prior-message handle can be consumed by a genuinely bounded worker." : command === "watch" ? "No event operation exists until finite supervision proves count, duration, byte, and termination bounds; webhooks remain forbidden." : command === "targets tunnel" ? "The floating Cloudflare JIT plugin and public tunnel are permanently outside provider authority." : `This ${legacy.reason} command group remains outside the semantic provider authority.`;
3258
+ return surfaceDecision("unsupported", special);
3259
+ }
3260
+ function surfaceItemDecision(command, item, commandDecision) {
3261
+ if (command === "export" && commandDecision.disposition === "internal") {
3262
+ if (item === "--no-attachments") {
3263
+ return surfaceDecision("fixed", "The internal private export always disables attachments.", null, "Wrench-owned bounded private export", true);
3264
+ }
3265
+ if (item === "--force") {
3266
+ return surfaceDecision("fixed", "The internal private export never overwrites an existing caller path.", null, "Fresh Wrench-owned export root", false);
3267
+ }
3268
+ if (item === "--out") {
3269
+ return surfaceDecision("fixed", "The output root is allocated and owned by Wrench; callers cannot inject a path.", null, "Wrench-owned private export root", "wrench-owned-private-export-root");
3270
+ }
3271
+ if (item === "--quiet") {
3272
+ return surfaceDecision("fixed", "The internal export suppresses interactive presentation.", null, "Bounded canonical manifest", true);
3273
+ }
3274
+ if (["--limit-chats", "--limit-messages", "--max-participants"].includes(item)) {
3275
+ return surfaceDecision("absorbed", `${item} is supplied only by the bounded private export planner.`, null, "Validated Wrench capture bound");
3276
+ }
3277
+ return surfaceDecision("internal", `${item} is unavailable to provider callers and omitted by the fixed private export plan.`, null, "Internal bounded private export");
3278
+ }
3279
+ if (commandDecision.disposition !== "supported") {
3280
+ return surfaceDecision(commandDecision.disposition, `${item} inherits the command disposition: ${commandDecision.rationale}`, commandDecision.operation, commandDecision.replacement);
3281
+ }
3282
+ const operation = commandDecision.operation;
3283
+ if (item === "--pick") {
3284
+ return surfaceDecision("replaced", "Fuzzy selection and result picking are forbidden.", operation, "Exact provider ID input");
3285
+ }
3286
+ if (item === "--ids") {
3287
+ return surfaceDecision("absorbed", "Normalized results always include stable provider IDs.", operation);
3288
+ }
3289
+ if (item === "--asc") {
3290
+ return surfaceDecision("absorbed", "The operation uses one canonical page order and never passes --asc before deriving continuation.", operation, "Canonical operation order");
3291
+ }
3292
+ if (item === "--wait" || item === "--wait-timeout") {
3293
+ return surfaceDecision("replaced", "Mutation dispatch never waits inside the send command.", operation, "Future read-only messaging.delivery.await over an accepted pending send");
3294
+ }
3295
+ if (item === "--transaction") {
3296
+ return surfaceDecision("absorbed", "Wrench owns the reaction transaction identity through the confirmed plan and dispatch fence.", operation);
3297
+ }
3298
+ if (command === "chats start" && item === "--title") {
3299
+ return surfaceDecision("replaced", "Conversation creation first returns an exact ID; title mutation is separate.", operation, "conversations.title.set");
3300
+ }
3301
+ if (command === "presence" && item === "--duration") {
3302
+ return surfaceDecision("absorbed", "Duration becomes two explicit bounded Wrench dispatches instead of a hidden child-process write.", operation);
3303
+ }
3304
+ if (item === "--file" || item === "--attachment") {
3305
+ return surfaceDecision("replaced", "Caller filesystem paths are forbidden.", operation, "Wrench plan-bound file capability");
3306
+ }
3307
+ if (item === "--account" && command === "accounts list") {
3308
+ return surfaceDecision("replaced", "The list returns the fixed account realm; exact lookup is separate.", operation, "accounts.read with account_id");
3309
+ }
3310
+ if (item === "--account") {
3311
+ return surfaceDecision("replaced", "Fuzzy and multi-account selectors are forbidden.", operation, "One exact account_id");
3312
+ }
3313
+ if (item === "--chat" || item === "--to") {
3314
+ return surfaceDecision("replaced", "Numeric, title, fuzzy, and multi-chat selectors are forbidden.", operation, "One exact full conversation_id");
3315
+ }
3316
+ if (["bridge", "account", "user", "id"].includes(item)) {
3317
+ return surfaceDecision("replaced", "Selector shorthand is replaced by an exact provider identity.", operation, "Exact semantic ID input");
3318
+ }
3319
+ if (command === "messages search" && item === "--exclude-low-priority") {
3320
+ return surfaceDecision("supported", "The semantic default is true, matching the generated Desktop API/OpenAPI server default used when the CLI omits the flag.", operation);
3321
+ }
3322
+ if (command === "bridges list" && item === "--provider") {
3323
+ return surfaceDecision("supported", "The three upstream values pass exactly; platform-sdk is a Wrench-local filter over an unfiltered bridge catalog and is never passed upstream.", operation);
3324
+ }
3325
+ return surfaceDecision("supported", `${item} is exposed through bounded typed input for ${operation}.`, operation);
3326
+ }
3327
+ function surfaceDefault(command, name, value) {
3328
+ const sourceAuthority = command === "targets tunnel" ? "jit-plugin-source" : "tagged-source";
3329
+ if (BEEPER_CLI_V062_EXPLICIT_FALSE_BOOLEAN_FLAGS.has(commandFlagCoordinate(command, name)))
3330
+ return Object.freeze({
3331
+ kind: "literal",
3332
+ value: false,
3333
+ authority: sourceAuthority
3334
+ });
3335
+ return value === null ? Object.freeze({ kind: "none" }) : Object.freeze({
3336
+ kind: "literal",
3337
+ value,
3338
+ authority: command === "messages search" && name === "--exclude-low-priority" ? "sdk-openapi" : sourceAuthority
3339
+ });
3340
+ }
3341
+ function commandReconciliation(command, decision) {
3342
+ if (decision.disposition !== "supported" || decision.operation === null) {
3343
+ return Object.freeze({
3344
+ availability: "none",
3345
+ namespace: null,
3346
+ predicate: null,
3347
+ rationale: "No provider mutation dispatch is authorized by this disposition."
3348
+ });
3349
+ }
3350
+ const policy = BEEPER_LOCAL_OPERATIONS[decision.operation];
3351
+ if (policy.effect === "read") {
3352
+ return Object.freeze({
3353
+ availability: "none",
3354
+ namespace: null,
3355
+ predicate: null,
3356
+ rationale: "Read operations do not require mutation reconciliation."
3357
+ });
3358
+ }
3359
+ if (["presence.set", "conversations.notify", "conversations.focus"].includes(decision.operation)) {
3360
+ return Object.freeze({
3361
+ availability: "none",
3362
+ namespace: null,
3363
+ predicate: null,
3364
+ rationale: "This visible effect has no exact provider readback and is never blindly retried after dispatch uncertainty."
3365
+ });
3366
+ }
3367
+ if (command === "chats avatar") {
3368
+ return Object.freeze({
3369
+ availability: "input-dependent",
3370
+ namespace: "semantic-operation",
3371
+ predicate: Object.freeze({
3372
+ op: "not",
3373
+ predicate: Object.freeze({ op: "present", field: "avatar" })
3374
+ }),
3375
+ rationale: "Only clear/no-file avatar state has an exact readback; uploaded file identity is irreconcilable."
3376
+ });
3377
+ }
3378
+ if (command === "chats draft") {
3379
+ return Object.freeze({
3380
+ availability: "input-dependent",
3381
+ namespace: "semantic-operation",
3382
+ predicate: Object.freeze({
3383
+ op: "not",
3384
+ predicate: Object.freeze({ op: "present", field: "attachment" })
3385
+ }),
3386
+ rationale: "Only drafts without an attachment have an exact readback; attachment identity is irreconcilable."
3387
+ });
3388
+ }
3389
+ if (command === "chats mark-read" || command === "chats mark-unread") {
3390
+ return Object.freeze({
3391
+ availability: "input-dependent",
3392
+ namespace: "semantic-operation",
3393
+ predicate: Object.freeze({
3394
+ op: "not",
3395
+ predicate: Object.freeze({ op: "present", field: "message_id" })
3396
+ }),
3397
+ rationale: "Only the conversation-level marker has an exact readback; a caller-selected message boundary is irreconcilable."
3398
+ });
3399
+ }
3400
+ return Object.freeze({
3401
+ availability: "always",
3402
+ namespace: null,
3403
+ predicate: null,
3404
+ rationale: "The operation contract defines an exact accepted target or desired-state readback and forbids blind retry."
3405
+ });
3406
+ }
3407
+ function commandOutput(command, output, decision) {
3408
+ if (command === "export") {
3409
+ return Object.freeze({
3410
+ shape: "Private canonical archive shards under a Wrench-owned root.",
3411
+ completeness: "internal",
3412
+ maxBytes: 4 * 1024 * 1024 * 1024,
3413
+ privateArtifact: true,
3414
+ truncation: "The internal caller fixes chat, message, participant, timeout, and no-attachment bounds."
3415
+ });
3416
+ }
3417
+ if (decision.disposition !== "supported") {
3418
+ return Object.freeze({
3419
+ shape: `Upstream ${output} output is not returned through a provider operation.`,
3420
+ completeness: "unavailable",
3421
+ maxBytes: null,
3422
+ privateArtifact: false,
3423
+ truncation: null
3424
+ });
3425
+ }
3426
+ const policy = BEEPER_LOCAL_OPERATIONS[decision.operation];
3427
+ const search = decision.operation?.endsWith("search") === true;
3428
+ const blendedContactQuery = command === "contacts list";
3429
+ return Object.freeze({
3430
+ shape: policy.effect === "read" ? "Bounded normalized provider projection with explicit completeness metadata." : "Bounded normalized mutation receipt and exact reconciliation evidence when available.",
3431
+ completeness: policy.effect === "write" ? "input-dependent" : search ? "candidate-window" : blendedContactQuery ? "input-dependent" : "bounded",
3432
+ maxBytes: 10 * 1024 * 1024,
3433
+ privateArtifact: false,
3434
+ truncation: policy.effect === "read" ? blendedContactQuery ? "Desktop loopback contact pages include continuation metadata. Official CLI v0.6.2 contracts remain a first-page window with no continuation." : "Provider limits and continuation availability are explicit in the normalized output." : "No upstream body, path, token, or unbounded diagnostic output is exposed."
3435
+ });
3436
+ }
3437
+ function commandInputRules(command) {
3438
+ if (command === "messages list" || command === "messages export") {
3439
+ const namespace = command === "messages list" ? "semantic-operation" : "upstream-command";
3440
+ return Object.freeze([
3441
+ Object.freeze({
3442
+ namespace,
3443
+ when: Object.freeze({ op: "present", field: "before_cursor" }),
3444
+ require: Object.freeze([]),
3445
+ requireAny: Object.freeze([]),
3446
+ exactlyOne: Object.freeze([]),
3447
+ forbid: Object.freeze(["after_cursor"]),
3448
+ rationale: "A page has only one continuation direction."
3449
+ }),
3450
+ Object.freeze({
3451
+ namespace,
3452
+ when: Object.freeze({ op: "present", field: "after_cursor" }),
3453
+ require: Object.freeze([]),
3454
+ requireAny: Object.freeze([]),
3455
+ exactlyOne: Object.freeze([]),
3456
+ forbid: Object.freeze(["before_cursor"]),
3457
+ rationale: "A page has only one continuation direction."
3458
+ })
3459
+ ]);
3460
+ }
3461
+ if (command === "chats description")
3462
+ return Object.freeze([
3463
+ Object.freeze({
3464
+ namespace: "semantic-operation",
3465
+ when: Object.freeze({ op: "eq", field: "clear", value: true }),
3466
+ require: Object.freeze([]),
3467
+ requireAny: Object.freeze([]),
3468
+ exactlyOne: Object.freeze([]),
3469
+ forbid: Object.freeze(["description"]),
3470
+ rationale: "Clear description cannot also provide replacement text."
3471
+ }),
3472
+ Object.freeze({
3473
+ namespace: "semantic-operation",
3474
+ when: Object.freeze({ op: "eq", field: "clear", value: false }),
3475
+ require: Object.freeze(["description"]),
3476
+ requireAny: Object.freeze([]),
3477
+ exactlyOne: Object.freeze([]),
3478
+ forbid: Object.freeze([]),
3479
+ rationale: "A non-clear description mutation requires replacement text."
3480
+ })
3481
+ ]);
3482
+ if (command === "chats avatar")
3483
+ return Object.freeze([
3484
+ Object.freeze({
3485
+ namespace: "semantic-operation",
3486
+ when: Object.freeze({ op: "eq", field: "clear", value: true }),
3487
+ require: Object.freeze([]),
3488
+ requireAny: Object.freeze([]),
3489
+ exactlyOne: Object.freeze([]),
3490
+ forbid: Object.freeze(["avatar"]),
3491
+ rationale: "Clear avatar cannot also provide an upload capability."
3492
+ }),
3493
+ Object.freeze({
3494
+ namespace: "semantic-operation",
3495
+ when: Object.freeze({ op: "eq", field: "clear", value: false }),
3496
+ require: Object.freeze(["avatar"]),
3497
+ requireAny: Object.freeze([]),
3498
+ exactlyOne: Object.freeze([]),
3499
+ forbid: Object.freeze([]),
3500
+ rationale: "A non-clear avatar mutation requires one plan-bound upload capability."
3501
+ })
3502
+ ]);
3503
+ if (command === "chats draft")
3504
+ return Object.freeze([
3505
+ Object.freeze({
3506
+ namespace: "semantic-operation",
3507
+ when: Object.freeze({ op: "eq", field: "clear", value: true }),
3508
+ require: Object.freeze([]),
3509
+ requireAny: Object.freeze([]),
3510
+ exactlyOne: Object.freeze([]),
3511
+ forbid: Object.freeze(["text", "attachment", "filename", "mime_type"]),
3512
+ rationale: "Clear draft cannot carry replacement content or attachment metadata."
3513
+ }),
3514
+ Object.freeze({
3515
+ namespace: "semantic-operation",
3516
+ when: Object.freeze({ op: "eq", field: "clear", value: false }),
3517
+ require: Object.freeze(["text"]),
3518
+ requireAny: Object.freeze([]),
3519
+ exactlyOne: Object.freeze([]),
3520
+ forbid: Object.freeze([]),
3521
+ rationale: "A non-clear draft requires text; one plan-bound attachment is optional."
3522
+ }),
3523
+ ...["filename", "mime_type"].map((field) => Object.freeze({
3524
+ namespace: "semantic-operation",
3525
+ when: Object.freeze({ op: "present", field }),
3526
+ require: Object.freeze(["attachment"]),
3527
+ requireAny: Object.freeze([]),
3528
+ exactlyOne: Object.freeze([]),
3529
+ forbid: Object.freeze([]),
3530
+ rationale: `${field} is meaningful only with one attachment.`
3531
+ }))
3532
+ ]);
3533
+ if (command === "messages search")
3534
+ return Object.freeze([
3535
+ Object.freeze({
3536
+ namespace: "semantic-operation",
3537
+ when: Object.freeze({ op: "true" }),
3538
+ require: Object.freeze([]),
3539
+ requireAny: Object.freeze(["query", "account_id", "conversation_id", "chat_type", "after", "before", "media", "sender"]),
3540
+ exactlyOne: Object.freeze([]),
3541
+ forbid: Object.freeze([]),
3542
+ rationale: "Search requires text or a substantive bounded filter; presentation booleans alone are insufficient."
3543
+ })
3544
+ ]);
3545
+ return Object.freeze([]);
3546
+ }
3547
+ function commandPathSemanticInputs(command) {
3548
+ const fixed = {
3549
+ "chats archive": Object.freeze({ enabled: true }),
3550
+ "chats unarchive": Object.freeze({ enabled: false }),
3551
+ "chats pin": Object.freeze({ enabled: true }),
3552
+ "chats unpin": Object.freeze({ enabled: false }),
3553
+ "chats mute": Object.freeze({ enabled: true }),
3554
+ "chats unmute": Object.freeze({ enabled: false }),
3555
+ "chats mark-read": Object.freeze({ unread: false }),
3556
+ "chats mark-unread": Object.freeze({ unread: true }),
3557
+ "chats remind": Object.freeze({ clear: false }),
3558
+ "chats unremind": Object.freeze({ clear: true }),
3559
+ "send text": Object.freeze({ kind: "text" }),
3560
+ "send file": Object.freeze({ kind: "file" }),
3561
+ "send react": Object.freeze({ enabled: true }),
3562
+ "send sticker": Object.freeze({ kind: "sticker" }),
3563
+ "send unreact": Object.freeze({ enabled: false }),
3564
+ "send voice": Object.freeze({ kind: "voice" })
3565
+ };
3566
+ return fixed[command] ?? Object.freeze({});
3567
+ }
3568
+ function commandDefinition(profile, exposure = "public-manual") {
3569
+ const [command, upstreamReportedMutates, output, argumentProfiles, flagProfiles] = profile;
3570
+ const decision = surfaceCommandDecision(command);
3571
+ const provenance = exposure === "source-only-private" ? "source-only-private" : command === "targets tunnel" ? "jit-plugin" : "built-in-canonical";
3572
+ const arguments_ = Object.freeze(argumentProfiles.map(([name, required, enumValues = []], position) => Object.freeze({
3573
+ name,
3574
+ position,
3575
+ required,
3576
+ multiple: false,
3577
+ valueType: "string",
3578
+ enum: Object.freeze([...enumValues]),
3579
+ default: Object.freeze({ kind: "none" }),
3580
+ decision: surfaceItemDecision(command, name, decision)
3581
+ })));
3582
+ const flags = Object.freeze(flagProfiles.map(([
3583
+ name,
3584
+ aliases,
3585
+ valueType,
3586
+ required,
3587
+ multiple,
3588
+ enumValues,
3589
+ defaultValue
3590
+ ]) => Object.freeze({
3591
+ name,
3592
+ aliases: Object.freeze([...aliases]),
3593
+ source: "command",
3594
+ valueType,
3595
+ allowNo: BEEPER_CLI_V062_ALLOW_NO_FLAGS.has(commandFlagCoordinate(command, name)),
3596
+ required,
3597
+ multiple,
3598
+ enum: Object.freeze([...enumValues]),
3599
+ default: surfaceDefault(command, name, defaultValue),
3600
+ decision: surfaceItemDecision(command, name, decision)
3601
+ })));
3602
+ return Object.freeze({
3603
+ path: Object.freeze(command.split(" ")),
3604
+ provenance,
3605
+ profileAuthority: command === "targets tunnel" ? "jit-plugin-source" : "tagged-source",
3606
+ package: command === "targets tunnel" ? "@beeper/cli-plugin-cloudflare" : "@beeper/cli",
3607
+ version: command === "targets tunnel" ? "^0.6.0" : "0.6.1",
3608
+ versionKind: command === "targets tunnel" ? "range" : "exact",
3609
+ registered: exposure === "public-manual" && command !== "targets tunnel",
3610
+ publicManual: exposure === "public-manual",
3611
+ generatedCanonical: exposure === "public-manual" && command !== "targets tunnel",
3612
+ upstreamReportedMutates,
3613
+ reviewedEffect: reviewedEffect(command, upstreamReportedMutates),
3614
+ arguments: arguments_,
3615
+ flags,
3616
+ decision,
3617
+ pathSemanticInputs: commandPathSemanticInputs(command),
3618
+ output: commandOutput(command, output, decision),
3619
+ conditionalInputs: commandInputRules(command),
3620
+ reconciliation: commandReconciliation(command, decision)
3621
+ });
3622
+ }
3623
+ var additionalDecision = (disposition, rationale, replacement = null) => surfaceDecision(disposition, rationale, null, replacement);
3624
+ function oclifPluginEntry(path, canonicalTarget = null) {
3625
+ return Object.freeze({
3626
+ path: Object.freeze(path.split(" ")),
3627
+ provenance: "dynamic-plugin",
3628
+ profileAuthority: "framework-runtime",
3629
+ canonicalTarget: canonicalTarget === null ? null : Object.freeze(canonicalTarget.split(" ")),
3630
+ package: "@oclif/plugin-plugins",
3631
+ version: null,
3632
+ versionKind: null,
3633
+ registered: true,
3634
+ publicManual: false,
3635
+ rationale: canonicalTarget === null ? "Callable oclif plugin-management command omitted from the generated command map." : "Callable oclif plugin-management alias omitted from the generated command map.",
3636
+ decision: additionalDecision("unsupported", "Plugin inspection and lifecycle authority are permanently outside the provider.")
3637
+ });
3638
+ }
3639
+ var BEEPER_CLI_V062_ADDITIONAL_ENTRIES = Object.freeze([
3640
+ ...[
3641
+ ["accounts", "accounts list", "accounts.list"],
3642
+ ["accounts chats", "chats list", "messaging.list"],
3643
+ ["bridges", "bridges list", "bridges.list"],
3644
+ ["chats", "chats list", "messaging.list"],
3645
+ ["contacts", "contacts list", "contacts.list"],
3646
+ ["targets", "targets list", null]
3647
+ ].map(([path, target, operation]) => Object.freeze({
3648
+ path: Object.freeze(path.split(" ")),
3649
+ provenance: "built-in-alias",
3650
+ profileAuthority: "tagged-source",
3651
+ canonicalTarget: Object.freeze(target.split(" ")),
3652
+ package: "@beeper/cli",
3653
+ version: "0.6.1",
3654
+ versionKind: "exact",
3655
+ registered: true,
3656
+ publicManual: false,
3657
+ rationale: "Generated registration alias; never accepted as raw caller syntax.",
3658
+ decision: operation === null ? additionalDecision("unsupported", "Target lifecycle aliases remain outside provider authority.") : surfaceDecision("absorbed", "The canonical semantic operation absorbs this generated alias.", operation)
3659
+ })),
3660
+ Object.freeze({
3661
+ path: Object.freeze(["autocomplete"]),
3662
+ provenance: "built-in-hidden",
3663
+ profileAuthority: "tagged-source",
3664
+ canonicalTarget: null,
3665
+ package: "@beeper/cli",
3666
+ version: "0.6.1",
3667
+ versionKind: "exact",
3668
+ registered: true,
3669
+ publicManual: false,
3670
+ rationale: "Hidden generated canonical command omitted from the public manual.",
3671
+ decision: additionalDecision("internal", "Wrench capability metadata replaces CLI autocomplete.")
3672
+ }),
3673
+ Object.freeze({
3674
+ path: Object.freeze(["help"]),
3675
+ provenance: "built-in-hidden",
3676
+ profileAuthority: "framework-runtime",
3677
+ canonicalTarget: null,
3678
+ package: "@oclif/core",
3679
+ version: null,
3680
+ versionKind: null,
3681
+ registered: true,
3682
+ publicManual: false,
3683
+ rationale: "Callable framework help behavior is outside the generated source command map.",
3684
+ decision: additionalDecision("internal", "Wrench capability metadata replaces CLI help.")
3685
+ }),
3686
+ oclifPluginEntry("plugins inspect"),
3687
+ oclifPluginEntry("plugins install"),
3688
+ oclifPluginEntry("plugins add", "plugins install"),
3689
+ oclifPluginEntry("plugins link"),
3690
+ oclifPluginEntry("plugins reset"),
3691
+ oclifPluginEntry("plugins uninstall"),
3692
+ oclifPluginEntry("plugins unlink", "plugins uninstall"),
3693
+ oclifPluginEntry("plugins remove", "plugins uninstall"),
3694
+ oclifPluginEntry("plugins update"),
3695
+ Object.freeze({
3696
+ path: Object.freeze(["<dynamic-plugin-command>"]),
3697
+ provenance: "dynamic-plugin",
3698
+ profileAuthority: "framework-runtime",
3699
+ canonicalTarget: null,
3700
+ package: null,
3701
+ version: null,
3702
+ versionKind: null,
3703
+ registered: false,
3704
+ publicManual: false,
3705
+ rationale: "Installed oclif plugins may add unpinned commands dynamically.",
3706
+ decision: additionalDecision("unsupported", "Dynamic plugin commands are permanently outside provider authority.")
3707
+ }),
3708
+ Object.freeze({
3709
+ path: Object.freeze(["messages", "react"]),
3710
+ provenance: "documented-only",
3711
+ profileAuthority: "documentation",
3712
+ canonicalTarget: null,
3713
+ package: null,
3714
+ version: null,
3715
+ versionKind: null,
3716
+ registered: false,
3717
+ publicManual: false,
3718
+ rationale: "A stale documentation alias is absent from the tagged source registration.",
3719
+ decision: additionalDecision("replaced", "Use reactions.set through the canonical send react mapping.", "reactions.set")
3720
+ }),
3721
+ Object.freeze({
3722
+ path: Object.freeze(["messages", "unreact"]),
3723
+ provenance: "documented-only",
3724
+ profileAuthority: "documentation",
3725
+ canonicalTarget: null,
3726
+ package: null,
3727
+ version: null,
3728
+ versionKind: null,
3729
+ registered: false,
3730
+ publicManual: false,
3731
+ rationale: "A stale documentation alias is absent from the tagged source registration.",
3732
+ decision: additionalDecision("replaced", "Use reactions.set through the canonical send unreact mapping.", "reactions.set")
3733
+ })
3734
+ ]);
3735
+ var BEEPER_CLI_V062_COMMANDS = Object.freeze([
3736
+ ...BEEPER_CLI_V062_COMMAND_PROFILES.map((profile) => commandDefinition(profile)),
3737
+ commandDefinition(BEEPER_CLI_V062_PRIVATE_COMMAND_PROFILE, "source-only-private")
3738
+ ]);
3739
+ if (BEEPER_CLI_V062_COMMANDS.length !== 102 || BEEPER_CLI_V062_COMMANDS.filter((command) => command.publicManual).length !== 101 || BEEPER_CLI_V062_COMMANDS.filter((command) => command.generatedCanonical).length !== 100 || BEEPER_CLI_V062_COMMANDS.filter((command) => command.registered).length + 7 !== 107)
3740
+ throw new Error("Beeper v0.6.2 surface cardinality drifted from reviewed provenance");
3741
+ var BEEPER_CLI_V062_SURFACE_CONTRACT = defineLocalCliSurfaceContractV1({
3742
+ schemaVersion: 1,
3743
+ format: "wrench.local-cli-surface",
3744
+ surface: "beeper",
3745
+ executable: {
3746
+ id: BEEPER_CLI_PIN.id,
3747
+ implementation: BEEPER_CLI_PIN.implementation,
3748
+ releaseVersion: BEEPER_CLI_PIN.version,
3749
+ releaseDate: "2026-05-18",
3750
+ releaseTag: "v0.6.2",
3751
+ releaseCommit: BEEPER_CLI_PIN.commit,
3752
+ releaseManifestSha256: BEEPER_CLI_PIN.releaseManifestSha256,
3753
+ runtimeReportedName: "@beeper/cli",
3754
+ runtimeReportedVersion: "0.6.2",
3755
+ artifacts: Object.freeze(BEEPER_CLI_PIN.artifacts.map((artifact) => Object.freeze({
3756
+ platform: artifact.platform,
3757
+ arch: artifact.arch,
3758
+ archiveSha256: artifact.archiveSha256,
3759
+ executableSha256: artifact.executableSha256
3760
+ })))
3761
+ },
3762
+ source: {
3763
+ package: "@beeper/cli",
3764
+ packagePath: "packages/cli/package.json",
3765
+ packageDeclaredVersion: "0.6.1",
3766
+ versionDiscrepancy: "Official v0.6.2 binaries.json and the exact executable report 0.6.2, while package.json at tag a416af06023449a87312dc11e54643fd9dc94b8c declares 0.6.1; executable runtime identity remains authoritative.",
3767
+ generatedManualSha256: "18a11300ae7fe321ace0c9c5bbdfd062f114c91add7d64e256b78c2e89e328a9",
3768
+ generatedManualIncludesFlagsAndDefaults: false,
3769
+ generatedManualEntries: 101,
3770
+ generatedCanonicalEntries: 101,
3771
+ registeredKeys: 107
3772
+ },
3773
+ sdk: BEEPER_DESKTOP_API_PIN,
3774
+ runtime: {
3775
+ providerPluginId: "beeper-linked-device",
3776
+ providerPluginVersion: "2.4.0",
3777
+ adapterId: "beeper-local",
3778
+ adapterVersion: "2.4.0",
3779
+ operationContractVersions: BEEPER_LOCAL_OPERATION_CONTRACT_VERSIONS,
3780
+ operationInputTypes: BEEPER_LOCAL_OPERATION_INPUT_TYPES,
3781
+ target: BEEPER_DESKTOP_TARGET,
3782
+ realm: "Fixed local Beeper Desktop realm with a verified loopback endpoint, exact account subject, isolated config/cache/plugins, and no caller endpoint, target, path, or environment.",
3783
+ compatibility: "The exact CLI executable identity is enforced and its reviewed API schema is @beeper/desktop-api 5.0.0 at b9c1714410139c2139b597338cd002d785653e85; callers cannot select a Desktop channel or protocol."
3784
+ },
3785
+ globalFlags: BEEPER_CLI_V062_GLOBAL_FLAGS,
3786
+ commands: BEEPER_CLI_V062_COMMANDS,
3787
+ additionalEntries: BEEPER_CLI_V062_ADDITIONAL_ENTRIES
3788
+ });
3789
+ var BEEPER_CLI_V062_UPSTREAM_SURFACE_SHA256 = "74297df1af30fe89cf1596a0670983e79cf85c0768c2f68e9bc3d386be640836";
3790
+ var BEEPER_CLI_V062_CLASSIFICATION_SHA256 = "bcd411af1544e5cd618cd3c04f2852a797bd804d92b7fe4cd226374b61c57d08";
3791
+ var BEEPER_CLI_V062_SEMANTIC_PROFILES_SHA256 = "fb7ea5f70f004dd8090c3e6e0996bfa00b0bab8ea5639203e2d1027602450ffe";
3792
+ var BEEPER_CLI_V062_WHOLE_SURFACE_SHA256 = "72201ac5eb3532f7c159583f19009f547d7d313e86388466b57c135bd2dc4944";
3793
+ var BEEPER_CLI_V062_PUBLIC_MANUAL_SEMANTIC_PROFILE_SHA256 = Object.freeze({
3794
+ setup: "cd432e2649e5724d70398e739a2d1c0c21557a23820aaa14562575a5fe689406",
3795
+ "install desktop": "478f4cc022b1d51d4016a319efea17e4523c55e3168560c99fdf7779347ae78a",
3796
+ "install server": "999b4aa7576c772ef4f2fa21076064885d67ab53354ab2446399562e1ad8af89",
3797
+ "targets list": "b1db92e025f67dda8d6bcfc642fa591ae7a2e4d3555c5aee7af5a0b94cfe94f2",
3798
+ "bridges list": "52c8c245a2088a781f0021232c0baaf6bf14fa9246dbfb192c6c57ef3f5d11af",
3799
+ "bridges show": "e23a6027d7536389501d008da503320d58b421c1f132c9a7d402b1d7b031658e",
3800
+ "targets add desktop": "fbfa2c790848792b519b11d45285c5ebf42abe3f46fc6b0a7bca231b9d7408e0",
3801
+ "targets add server": "488d26c83f2261dbe04195fb429d04019977c5cb21d092db8a4765afe68812bf",
3802
+ "targets add remote": "db56749d593d43b78922aab5ff1456f617d6dbdbf7f06d44761c2a5133c80da3",
3803
+ "targets use": "4617f7e87a68149c5a96624567ce9dc1501d4e31c86920eb64e3f9c536553eeb",
3804
+ "targets show": "a48dacbc13afc37f1a58c5b2178d22c5ae049bff1f2701e1e3e72a9e4088259b",
3805
+ "targets status": "a70e6eef1793a561914c49a8bcfa118be22b23244a24e622360ad205c9232cc2",
3806
+ "targets start": "4bb79ca30f3564cab02a1c5ec173ee016a04bafe263e38ddbf7aa778747d5f48",
3807
+ "targets stop": "65ebf81b3855a7fe5585f94b0cd6dc042ae6e5d92eb3e299c5076e9f84ee24f6",
3808
+ "targets restart": "dd1281aad6369e7d68185d6a949449d0b0ce8ff395f9d01570a8bf5ed78387e7",
3809
+ "targets logs": "808f0e13386372ef9580575b7a2c9110d540209407cb14dc778faba538a51b41",
3810
+ "targets enable": "20baea46e6d8b5f5f8ebc5dc0a8bfe9ff7836ba7b1991c8be2af8ee373cbbe1b",
3811
+ "targets disable": "0d5695503942f090b118cb445b64556713536d6deeb32ba582e8a1f6f48135fb",
3812
+ "targets remove": "0ba9940afc0ead36641b1539dea4f97dd920d8064067839ddb59b5bda874a2e0",
3813
+ "targets tunnel": "a96cdc41c42ea64777782ca96b81cbe630928df35067cdcdd903c506e7bdb5a8",
3814
+ "auth status": "e08a0176cdc9d9dd06c75a6082b64c8e9b5f68075b58e9c2e61fe2f99bbb6044",
3815
+ "auth logout": "25a8d13779a8fc86c13cf8dbd9c1cfc8d68694fed1a7ab9f872cb648dee366ad",
3816
+ "auth email start": "d6d355b494860b57a8ae00d3562c9bd1054c6c70b8f0bf478abff88497ef2334",
3817
+ "auth email response": "0842a657dbfbeeeb7744332a60ec04064e991dab501fd47f92bc5596cfd7fbfb",
3818
+ verify: "b16da79fe75c014faf681d36eff05c4e81e274c8ca29d576592d45f35078503a",
3819
+ "verify status": "abd89afdf112ac6aeaa97b9843bc2f81e1a52f6e92e4c42ad8e7a035ae73198b",
3820
+ "verify approve": "f724a957287b638b9f27a6b02897260c4ece685113448ebd69e6ff793038b2a0",
3821
+ "verify recovery-key": "db9d69676807ba959731125bc95ffb6bef735bddb8cd5b5401cb96d8678e4dfb",
3822
+ "verify reset-recovery-key": "e59d2b06f2feaa8008f0e285ac4ec7d7a75a18fd66ca39ddce6d9914c28b6c98",
3823
+ "verify cancel": "40197355731efde46280b13a2b227f13fb9ebc33cb80712087380d8d805944f0",
3824
+ "verify list": "85de0df592d523d3c127f8c33adb2855fc49f43d470d2675d7854401c975ec9e",
3825
+ "verify start": "3c0ef55faaf49552315322b4b521290185c36774a8d87a0e2f2614392407e2b7",
3826
+ "verify show": "08a4a85bdfc3a900c8d9f49564fdaa3d4d37046eace6ed665c8b767867b83afc",
3827
+ "verify sas": "d6fd6130fd9eee6d51c193989184d2115b171993a304cf4707c0aaecafd2c3e0",
3828
+ "verify sas-confirm": "0bc55ff8df6068cb6e3fae1ed136dba94442bae00fc4a95c56a9f206fa3a9d38",
3829
+ "verify qr-scan": "d618900cb8548d4abf09d29cd577c7aedbaa660dc6978e28fababe7ea520bf25",
3830
+ "verify qr-confirm": "4dc005579ee36737d6c03f0f9fdba18274fbf257bc0921bf2592421ec11b3464",
3831
+ "accounts list": "325bb478a9fc344a1982c130c6fddecd0c34371052409df6ba05ba59248e3d38",
3832
+ "accounts add": "fa8b9c9e695bf6bb3bf6b122773cc633e8fa6c817760314ecd44a848a384eb17",
3833
+ "accounts show": "234fef2ec2a24ca7254e3d2b77f0e7179f71bcc67b4e9fc387ae82122a5d6c7a",
3834
+ "accounts remove": "6188c67a6ded6d6b7d2662295ead8fab65c6509614c3d39ebc301f7e7cf5eaf0",
3835
+ "accounts use": "bd8dc05db1633966700bf488c56ca6710be4766ea7576c11dd0fe7431d576275",
3836
+ "chats list": "cc71df6c537ae4878cffc5c3de743481b2daabf47459ab1a52fabcae14d65a92",
3837
+ "chats search": "055097bbd9b156f02a5c5177d566a1ed611477032b0f279dbfaabc5830afc56b",
3838
+ "chats show": "b090de1ce0486fc8217264baf46d6b312af7d0b063a457037eb14201ef4d77e7",
3839
+ "chats start": "7691cf0d6ac68081ce574edbc9ab2c9e5bd2ad6f82902d04d82590bc54cfc91a",
3840
+ "chats archive": "fcfe1fb838c27a65a27b116394911bee2bc2f641e7ae2f7c5904388efcafede1",
3841
+ "chats unarchive": "d371d735e983d85ae235a955e06cb0542ccb6bcd7e00155919938b948985f30f",
3842
+ "chats pin": "5f037961e20915f06ede7fd02b809591ff81ca139d1c5213170f8a14fb032d12",
3843
+ "chats unpin": "02bda6e96362e9037931fb53733ce6901a61f6025aaf01de81fc10d103995e58",
3844
+ "chats mute": "e56e2b2e43a037765db6bb7ad031a6e927bee1d6e4dd23ec4068488dbb7a4ba5",
3845
+ "chats unmute": "f39c1f039777c9771bc97897b0542f95e626c0f34c3c9c854b4da4c740e455d4",
3846
+ "chats mark-read": "a3b738d7aba9737d892a62b37d922a7f2023c5bf0929f9283f2de4c3fb4cdfe4",
3847
+ "chats mark-unread": "28520f6500ae501537822360ad25b58ff1d48df6adaddd65d9e5b56d557f9e0f",
3848
+ "chats priority": "759b966b88e8d1b5236a77405568ff3b659cccbbacf1dbf9dfcdd64e46817c56",
3849
+ "chats notify-anyway": "b527d36467f10fbad9913742846605acbb6e1024e8a07c45ba19658a49bd6ab2",
3850
+ "chats rename": "5e45d6f1bb18fcc0e8f13097e6b2e286ae6bc2cf925f4dba90c2e60002968e48",
3851
+ "chats description": "158fd28b2573c3da43160e04b8749ace7ad552d80aef5a61c912ed33931a69c7",
3852
+ "chats avatar": "8e16f4edfd5b780ce0ee3968416864d43f19603f17999bb4e2dd99a6b873440f",
3853
+ "chats draft": "bb245a9e50012cca9dbcd65dc2197b1babc6461ce1f0ab61ed53b6322fea02c6",
3854
+ "chats disappear": "9d2b7b70d11cb1c749007d2f1c6a2b2298a525ba88fe1790e9dacc97490996b6",
3855
+ "chats remind": "b5133c8f6a103234344c2203637ceea98c65c3b97f805e97e169f475bd0e35fd",
3856
+ "chats unremind": "0dd3dbfe98dba426c286ca08a73753a4c0a5dfff1ed1ac397e964b336d46b4db",
3857
+ "chats focus": "a53f3dc9bbd93e05adfee9f9f6540e417f8fd5030b1c9d1789fc495e5f625931",
3858
+ "messages list": "e691ea9f57b65cdfb9e2576ded7a502e24e61d9522122d9440fea386c9c22e6b",
3859
+ "messages search": "a19a5290708c3c43aa1e1f84fb5d3ba2664575aa32afc2784042bab2314e72a9",
3860
+ "messages show": "b8436a8e46bf761062850f6cc8bf5777a3ae00166631cb77e1cd21ea122be67f",
3861
+ "messages context": "68f0a77a8b98435c8aee0dccd603f9ee8d21c83c97b5face47ec582cd525c711",
3862
+ "messages edit": "95380f389feaac7cb93f27be89eed617d997ce98f9a3bc1972306d2ccf353339",
3863
+ "messages delete": "305e8826df70ebde061dd7099af33b5eec203453560a50a5a1c008ba175a0ecc",
3864
+ "messages export": "7a0c90728af3b602726d59fd2f8ac9352db4fae8ccb440515daab5b37955d2ce",
3865
+ "send text": "05ef4e97a2611f3e350f54fe34ec31c7f34873de1da060450c7bc7ae9308f32f",
3866
+ "send file": "770a6ff88d6e28d1431d2435bac54c2a76a344611e7be5a442f5d1657a005ebf",
3867
+ "send react": "b46e199df693cb824bf109dbd1aa5e847445549096c75e6e04c81ea75f1895b6",
3868
+ "send sticker": "3da1e6a17df385f098a4a9b6d7e86ab7dd1c7c6d2c0ca5bee9f5de1f38b0b741",
3869
+ "send unreact": "f2fe46e5854571eecbde82fc59663f99b44b4484bffda7c92b12614de709b2d3",
3870
+ "send voice": "966b39e192073fc581b8efece9fa744f169b51361e9a8223a84d3c9251e08c24",
3871
+ presence: "2d6e067b5d572f7d2524c3e4fdf41300ee82b9af03116f17b098a6afcb9fc9b7",
3872
+ "contacts list": "77b752f6e0a37b68cf31cd85c554a5bdec51c20b0239a8a13ef111f7d30b9c6c",
3873
+ "contacts search": "8b33f02bb3011f2dd304be5f9f5ccec2303833ae739dc4e96dc3691d6354032b",
3874
+ "contacts show": "724c25f80b5f58bbfb4b858187d5f785e946853e6a2f355bd14f8b8bc2052c92",
3875
+ "media download": "47f7e05839640b88c42e719b44f3d8f9632ddb7f5abbb1ae2f4eee32341d4f88",
3876
+ export: "3a8e13c94c79c7352fc204e7f73c103a55e871befe6dcf943023c832b7119d52",
3877
+ watch: "7839bc4e2a9e905f883a372895fbe40aecfb055f3ed642c4e800dcf4fffb9c03",
3878
+ rpc: "2399aaaab78a0129bcac2fd0e39c26be1e2fb97ce3ed0c40b631474ca1bd4d9d",
3879
+ man: "5f9eb21048ecf86926e64751865c28aa76f3673fc29b41ef5f8273801377cb2a",
3880
+ doctor: "18b285f3054ac9f1ee445827540cc26d1a5e367b230d2015d502233d1c5946aa",
3881
+ status: "73db0a7f0fd5a33620589d8b6f6e2f9a86310371cbc265a28af6e0901373d8a7",
3882
+ docs: "1d44df3d2ad09e8986ec7937c312c3ca06e90ca02693846b64a001b65edaa3bf",
3883
+ version: "706d4759642840fa4cc99a80cb4e73f3020cdcf71aee8d0537341bd3f6746c79",
3884
+ completion: "707719d9c820895ad1cdb0590501bc4656e966c54edb22d9bcba02358395c2d0",
3885
+ plugins: "788ea2111f878f710c8e7c9ed5ac163a58d30831e5a9a67f2c1c1aa88f767f46",
3886
+ "plugins available": "b579adca88123da1be0da8c3df02269b629c7f287086ae072e858d79c1e49198",
3887
+ update: "c7f6cf4ef3a19e4161a428b993a1527836c864adb4e812f8392c7cfbada76228",
3888
+ "config get": "4568bc28c22e82ed02429a59b38a47d68635a3e599570ad9a4b16d5d1bc4f9bc",
3889
+ "config set": "3708ca19869aa056d30c43b2c7368d13168255f73474d7ecea6a38d5d6f748ae",
3890
+ "config path": "7c45a2996a9d8b8da6ccc7691ec98c378d7cc3494f2929a0930b98e5e037ebbe",
3891
+ "config reset": "4f8f09e26043c8d7770dda894ab17289abdb41ab4881b90d3a287ca548a15374",
3892
+ "api get": "677eaba3c3008fd86da6920d6086a166de702c6a650b7499c54b5264300a65e5",
3893
+ "api post": "79a8826a3386036d10d2be46ef7eb87a0be769214e032ca909b3758916aecc5a",
3894
+ "api request": "9158437c08a2504cd1e7df43aa21c253052ea5f2afbefa7b7e0a01c0ce55746e"
3895
+ });
3896
+ var BEEPER_CLI_V062_SOURCE_ONLY_COMPLETE_SEMANTIC_PROFILE_SHA256 = "917b94060ef7f99a07843c15d1eee58bdeb4f53797a14157ebf5e54fb72350b2";
3897
+ if (BEEPER_CLI_V062_SURFACE_CONTRACT.digests.upstreamSurfaceSha256 !== BEEPER_CLI_V062_UPSTREAM_SURFACE_SHA256 || BEEPER_CLI_V062_SURFACE_CONTRACT.digests.classificationSha256 !== BEEPER_CLI_V062_CLASSIFICATION_SHA256 || BEEPER_CLI_V062_SURFACE_CONTRACT.digests.semanticProfilesSha256 !== BEEPER_CLI_V062_SEMANTIC_PROFILES_SHA256 || BEEPER_CLI_V062_SURFACE_CONTRACT.digests.wholeSurfaceSha256 !== BEEPER_CLI_V062_WHOLE_SURFACE_SHA256)
3898
+ throw new Error(`Beeper v0.6.2 reviewed surface digest drifted: ${JSON.stringify(BEEPER_CLI_V062_SURFACE_CONTRACT.digests)}`);
3899
+ for (const command of BEEPER_CLI_V062_SURFACE_CONTRACT.commands) {
3900
+ const path = command.path.join(" ");
3901
+ const reviewed = command.publicManual ? BEEPER_CLI_V062_PUBLIC_MANUAL_SEMANTIC_PROFILE_SHA256[path] : path === "_complete" ? BEEPER_CLI_V062_SOURCE_ONLY_COMPLETE_SEMANTIC_PROFILE_SHA256 : undefined;
3902
+ if (reviewed !== command.semanticProfileSha256) {
3903
+ throw new Error(`Beeper v0.6.2 semantic profile digest drifted for ${path}: ${command.semanticProfileSha256}`);
3904
+ }
3905
+ }
3906
+
3907
+ // src/beeper-contact-interactions.ts
3908
+ var BEEPER_CONTACT_INTERACTION_SCHEMA_VERSION = 1;
3909
+ var BEEPER_CONTACT_INTERACTION_FORMAT = "wrench.contact-interaction-summary";
3910
+ var BEEPER_CONTACT_INTERACTION_RECEIPT_FORMAT = "wrench.beeper-contact-interaction-export-receipt";
3911
+ var BEEPER_CONTACT_INTERACTION_TRANSFORM = Object.freeze({
3912
+ id: "beeper-direct-contact-interactions",
3913
+ version: 1,
3914
+ sourceVersion: LOCAL_MESSAGE_BUNDLE_V1_SOURCE_TRANSFORM_VERSION
3915
+ });
3916
+ var BEEPER_CONTACT_INTERACTION_IMPLEMENTATION = Object.freeze({
3917
+ producer: Object.freeze({
3918
+ package: "@hraness/ghostget",
3919
+ version: GHOSTGET_VERSION
3920
+ }),
3921
+ officialCli: Object.freeze({
3922
+ implementation: BEEPER_CLI_PIN.implementation,
3923
+ version: BEEPER_CLI_PIN.version,
3924
+ commit: BEEPER_CLI_PIN.commit,
3925
+ platform: "darwin-arm64",
3926
+ binarySha256: BEEPER_CLI_PIN.darwinArm64BinarySha256
3927
+ })
3928
+ });
3929
+ var MAX_RECORDS = LOCAL_MESSAGE_BUNDLE_V1_LIMITS.records;
3930
+ var MAX_COORDINATE_BYTES = 4 * 1024;
3931
+ var MAX_NETWORK_BYTES = 64;
3932
+ var CONTACT_INTERACTION_WARNING_CODES = Object.freeze([
3933
+ "group-messages-excluded",
3934
+ "incomplete-direct-rosters-excluded",
3935
+ "message-content-excluded",
3936
+ "replacement-message-versions-excluded"
3937
+ ]);
3938
+ var MAX_WARNINGS = LOCAL_MESSAGE_BUNDLE_V1_LIMITS.warnings + CONTACT_INTERACTION_WARNING_CODES.length;
3939
+ var MAX_OUTPUT_BYTES = 128 * 1024 * 1024;
3940
+ var BEEPER_CONTACT_INTERACTION_WIRE_MAX_BYTES = MAX_OUTPUT_BYTES * 3 + 1024 * 1024;
3941
+ function fail(message) {
3942
+ throw new Error(`Beeper contact interaction summary: ${message}`);
3943
+ }
3944
+ function record2(value, label) {
3945
+ if (typeof value !== "object" || value === null || Array.isArray(value) || nodeTypes2.isProxy(value) || Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null)
3946
+ return fail(`${label} must be a plain object`);
3947
+ const descriptors = Object.getOwnPropertyDescriptors(value);
3948
+ const keys = Reflect.ownKeys(descriptors);
3949
+ if (keys.some((key) => typeof key !== "string")) {
3950
+ return fail(`${label} must not contain symbol fields`);
3951
+ }
3952
+ for (const key of keys) {
3953
+ const descriptor = descriptors[key];
3954
+ if (descriptor === undefined || !descriptor.enumerable || !("value" in descriptor)) {
3955
+ return fail(`${label}.${key} must be an enumerable data property`);
3956
+ }
3957
+ }
3958
+ return value;
3959
+ }
3960
+ function boundedArray(value, label, maximum) {
3961
+ if (!Array.isArray(value) || nodeTypes2.isProxy(value) || value.length > maximum)
3962
+ return fail(`${label} must be a bounded plain array`);
3963
+ const keys = Reflect.ownKeys(value);
3964
+ if (keys.some((key) => typeof key !== "string") || keys.length !== value.length + 1 || keys[keys.length - 1] !== "length")
3965
+ return fail(`${label} must not contain holes or custom fields`);
3966
+ const descriptors = Object.getOwnPropertyDescriptors(value);
3967
+ for (let index = 0;index < value.length; index += 1) {
3968
+ const descriptor = descriptors[String(index)];
3969
+ if (descriptor === undefined || !descriptor.enumerable || !("value" in descriptor)) {
3970
+ return fail(`${label}[${String(index)}] must be an enumerable data property`);
3971
+ }
3972
+ }
3973
+ return value;
3974
+ }
3975
+ function exactKeys2(value, keys, label) {
3976
+ const actual = Object.keys(value).sort();
3977
+ const expected = [...keys].sort();
3978
+ if (actual.length !== expected.length || actual.some((key, index) => key !== expected[index]))
3979
+ fail(`${label} contains unsupported or missing fields`);
3980
+ }
3981
+ function coordinate(value, label) {
3982
+ if (typeof value !== "string" || value.length < 1 || Buffer.byteLength(value, "utf8") > MAX_COORDINATE_BYTES || /[\u0000-\u001f\u007f]/u.test(value))
3983
+ return fail(`${label} must be bounded provider text`);
3984
+ return value;
3985
+ }
3986
+ function compareCanonicalText(left, right) {
3987
+ return left < right ? -1 : left > right ? 1 : 0;
3988
+ }
3989
+ function token(value, label, maximum = 128) {
3990
+ const parsed = coordinate(value, label);
3991
+ if (Buffer.byteLength(parsed, "utf8") > maximum || !/^[A-Za-z0-9](?:[A-Za-z0-9._+-]*[A-Za-z0-9])?$/u.test(parsed))
3992
+ return fail(`${label} must be a token`);
3993
+ return parsed;
3994
+ }
3995
+ function digest(value, label) {
3996
+ const parsed = token(value, label, 64);
3997
+ if (!/^[a-f0-9]{64}$/u.test(parsed))
3998
+ return fail(`${label} must be a SHA-256 digest`);
3999
+ return parsed;
4000
+ }
4001
+ function integer2(value, label) {
4002
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0)
4003
+ return fail(`${label} must be a non-negative integer`);
4004
+ return value;
4005
+ }
4006
+ function timestamp(value, label) {
4007
+ const parsed = coordinate(value, label);
4008
+ const date = new Date(parsed);
4009
+ if (!Number.isFinite(date.getTime()) || date.toISOString() !== parsed) {
4010
+ return fail(`${label} must be a canonical UTC timestamp`);
4011
+ }
4012
+ return parsed;
4013
+ }
4014
+ function nullableTimestamp(value, label) {
4015
+ return value === null ? null : timestamp(value, label);
4016
+ }
4017
+ function providerId(kind, ...parts) {
4018
+ return `beeper-${kind}:${sha256(canonicalJson(parts))}`;
4019
+ }
4020
+ function summaryProjection(value) {
4021
+ return value;
4022
+ }
4023
+ function parseStringArray(value, label, maximum) {
4024
+ const parsed = boundedArray(value, label, maximum).map((item, index) => token(item, `${label}[${String(index)}]`));
4025
+ if (new Set(parsed).size !== parsed.length)
4026
+ return fail(`${label} contains duplicates`);
4027
+ return Object.freeze(parsed);
4028
+ }
4029
+ function parseBeeperContactInteractionSummary(value) {
4030
+ const source = record2(value, "summary");
4031
+ exactKeys2(source, [
4032
+ "schemaVersion",
4033
+ "format",
4034
+ "transform",
4035
+ "source",
4036
+ "provider",
4037
+ "observedAt",
4038
+ "scope",
4039
+ "completeness",
4040
+ "warnings",
4041
+ "privacy",
4042
+ "counts",
4043
+ "accounts",
4044
+ "interactions",
4045
+ "integrity"
4046
+ ], "summary");
4047
+ if (source.schemaVersion !== BEEPER_CONTACT_INTERACTION_SCHEMA_VERSION || source.format !== BEEPER_CONTACT_INTERACTION_FORMAT)
4048
+ return fail("schema is unsupported");
4049
+ const transform = record2(source.transform, "summary.transform");
4050
+ exactKeys2(transform, ["id", "version", "sourceVersion"], "summary.transform");
4051
+ if (transform.id !== BEEPER_CONTACT_INTERACTION_TRANSFORM.id || transform.version !== BEEPER_CONTACT_INTERACTION_TRANSFORM.version || transform.sourceVersion !== BEEPER_CONTACT_INTERACTION_TRANSFORM.sourceVersion)
4052
+ return fail("transform is unsupported");
4053
+ const sourceValue = record2(source.source, "summary.source");
4054
+ exactKeys2(sourceValue, ["id", "version"], "summary.source");
4055
+ if (sourceValue.id !== "beeper-local" || sourceValue.version !== BEEPER_CONTACT_INTERACTION_TRANSFORM.sourceVersion)
4056
+ return fail("source is unsupported");
4057
+ const provider = record2(source.provider, "summary.provider");
4058
+ exactKeys2(provider, ["id", "version"], "summary.provider");
4059
+ if (provider.id !== "beeper")
4060
+ return fail("provider is unsupported");
4061
+ const providerVersion = token(provider.version, "summary.provider.version");
4062
+ const observedAt = nullableTimestamp(source.observedAt, "summary.observedAt");
4063
+ const scope = record2(source.scope, "summary.scope");
4064
+ exactKeys2(scope, ["conversations", "messages"], "summary.scope");
4065
+ if (scope.conversations !== "complete-direct-only" || scope.messages !== "current-direction-known-only")
4066
+ return fail("scope is unsupported");
4067
+ const completeness = record2(source.completeness, "summary.completeness");
4068
+ exactKeys2(completeness, [
4069
+ "kind",
4070
+ "sourceKind",
4071
+ "reason",
4072
+ "observedFrom",
4073
+ "observedThrough"
4074
+ ], "summary.completeness");
4075
+ if (completeness.kind !== "lower-bound")
4076
+ return fail("completeness kind is unsupported");
4077
+ if (completeness.sourceKind !== "bounded-local" && completeness.sourceKind !== "truncated" && completeness.sourceKind !== "unknown")
4078
+ return fail("source completeness kind is unsupported");
4079
+ const reason = completeness.reason === null ? null : token(completeness.reason, "summary.completeness.reason");
4080
+ const observedFrom = nullableTimestamp(completeness.observedFrom, "summary.completeness.observedFrom");
4081
+ const observedThrough = nullableTimestamp(completeness.observedThrough, "summary.completeness.observedThrough");
4082
+ if (observedFrom !== null && observedThrough !== null && observedFrom > observedThrough) {
4083
+ return fail("completeness timestamps are reversed");
4084
+ }
4085
+ const warnings = parseStringArray(source.warnings, "summary.warnings", MAX_WARNINGS);
4086
+ const privacy = record2(source.privacy, "summary.privacy");
4087
+ exactKeys2(privacy, [
4088
+ "messageBodies",
4089
+ "attachments",
4090
+ "reactions",
4091
+ "media",
4092
+ "groupMessages",
4093
+ "localPaths",
4094
+ "credentials"
4095
+ ], "summary.privacy");
4096
+ if (privacy.messageBodies !== "excluded" || privacy.attachments !== "excluded" || privacy.reactions !== "excluded" || privacy.media !== "excluded" || privacy.groupMessages !== "excluded" || privacy.localPaths !== "excluded" || privacy.credentials !== "excluded")
4097
+ return fail("privacy boundary is unsupported");
4098
+ const counts = record2(source.counts, "summary.counts");
4099
+ exactKeys2(counts, [
4100
+ "accounts",
4101
+ "directRelationships",
4102
+ "directConversations",
4103
+ "interactions",
4104
+ "sent",
4105
+ "received"
4106
+ ], "summary.counts");
4107
+ const parsedCounts = Object.freeze({
4108
+ accounts: integer2(counts.accounts, "summary.counts.accounts"),
4109
+ directRelationships: integer2(counts.directRelationships, "summary.counts.directRelationships"),
4110
+ directConversations: integer2(counts.directConversations, "summary.counts.directConversations"),
4111
+ interactions: integer2(counts.interactions, "summary.counts.interactions"),
4112
+ sent: integer2(counts.sent, "summary.counts.sent"),
4113
+ received: integer2(counts.received, "summary.counts.received")
4114
+ });
4115
+ const accountValues = boundedArray(source.accounts, "summary.accounts", MAX_RECORDS);
4116
+ const accounts = Object.freeze(accountValues.map((item, index) => {
4117
+ const account = record2(item, `summary.accounts[${String(index)}]`);
4118
+ exactKeys2(account, [
4119
+ "accountId",
4120
+ "accountProviderId",
4121
+ "network",
4122
+ "selfParticipantId",
4123
+ "selfParticipantProviderId",
4124
+ "observedAt"
4125
+ ], `summary.accounts[${String(index)}]`);
4126
+ const accountId = coordinate(account.accountId, `summary.accounts[${String(index)}].accountId`);
4127
+ const expectedProviderId = providerId("account", accountId);
4128
+ const accountProviderId = coordinate(account.accountProviderId, `summary.accounts[${String(index)}].accountProviderId`);
4129
+ if (accountProviderId !== expectedProviderId)
4130
+ return fail("an account provider coordinate is invalid");
4131
+ const selfParticipantId = coordinate(account.selfParticipantId, `summary.accounts[${String(index)}].selfParticipantId`);
4132
+ const selfParticipantProviderId = coordinate(account.selfParticipantProviderId, `summary.accounts[${String(index)}].selfParticipantProviderId`);
4133
+ if (selfParticipantProviderId !== providerId("participant", accountId, selfParticipantId))
4134
+ return fail("an account self provider coordinate is invalid");
4135
+ return Object.freeze({
4136
+ accountId,
4137
+ accountProviderId,
4138
+ network: token(account.network, `summary.accounts[${String(index)}].network`, MAX_NETWORK_BYTES),
4139
+ selfParticipantId,
4140
+ selfParticipantProviderId,
4141
+ observedAt: timestamp(account.observedAt, `summary.accounts[${String(index)}].observedAt`)
4142
+ });
4143
+ }));
4144
+ const accountKeys = accounts.map((account) => account.accountId);
4145
+ if (new Set(accountKeys).size !== accountKeys.length || accountKeys.some((key, index) => index > 0 && compareCanonicalText(key, accountKeys[index - 1]) <= 0))
4146
+ return fail("accounts are not unique and canonically ordered");
4147
+ const interactionValues = boundedArray(source.interactions, "summary.interactions", MAX_RECORDS);
4148
+ const accountsById = new Map(accounts.map((account) => [account.accountId, account]));
4149
+ const interactions = Object.freeze(interactionValues.map((item, index) => {
4150
+ const interaction = record2(item, `summary.interactions[${String(index)}]`);
4151
+ exactKeys2(interaction, [
4152
+ "accountId",
4153
+ "accountProviderId",
4154
+ "contactId",
4155
+ "contactProviderId",
4156
+ "network",
4157
+ "sentCount",
4158
+ "receivedCount",
4159
+ "interactionCount",
4160
+ "conversationCount",
4161
+ "firstInteractionAt",
4162
+ "lastInteractionAt",
4163
+ "reciprocal",
4164
+ "completeness",
4165
+ "provenance"
4166
+ ], `summary.interactions[${String(index)}]`);
4167
+ const accountId = coordinate(interaction.accountId, `summary.interactions[${String(index)}].accountId`);
4168
+ const account = accountsById.get(accountId);
4169
+ if (account === undefined)
4170
+ return fail("an interaction references an unknown account");
4171
+ const accountProviderId = coordinate(interaction.accountProviderId, `summary.interactions[${String(index)}].accountProviderId`);
4172
+ if (accountProviderId !== account.accountProviderId) {
4173
+ return fail("an interaction account provider coordinate is invalid");
4174
+ }
4175
+ const contactId = coordinate(interaction.contactId, `summary.interactions[${String(index)}].contactId`);
4176
+ if (contactId === account.selfParticipantId) {
4177
+ return fail("an interaction contact cannot be the account self participant");
4178
+ }
4179
+ const contactProviderId = coordinate(interaction.contactProviderId, `summary.interactions[${String(index)}].contactProviderId`);
4180
+ if (contactProviderId !== providerId("participant", accountId, contactId)) {
4181
+ return fail("an interaction contact provider coordinate is invalid");
4182
+ }
4183
+ const network = token(interaction.network, `summary.interactions[${String(index)}].network`, MAX_NETWORK_BYTES);
4184
+ if (network !== account.network)
4185
+ return fail("an interaction changed account networks");
4186
+ const sentCount = integer2(interaction.sentCount, `summary.interactions[${String(index)}].sentCount`);
4187
+ const receivedCount = integer2(interaction.receivedCount, `summary.interactions[${String(index)}].receivedCount`);
4188
+ const interactionCount = integer2(interaction.interactionCount, `summary.interactions[${String(index)}].interactionCount`);
4189
+ const conversationCount = integer2(interaction.conversationCount, `summary.interactions[${String(index)}].conversationCount`);
4190
+ if (interactionCount !== sentCount + receivedCount || interactionCount < 1 || conversationCount < 1 || conversationCount > interactionCount || interaction.reciprocal !== (sentCount > 0 && receivedCount > 0) || interaction.completeness !== "lower-bound")
4191
+ return fail("an interaction has inconsistent counts or completeness");
4192
+ const firstInteractionAt = timestamp(interaction.firstInteractionAt, `summary.interactions[${String(index)}].firstInteractionAt`);
4193
+ const lastInteractionAt = timestamp(interaction.lastInteractionAt, `summary.interactions[${String(index)}].lastInteractionAt`);
4194
+ if (firstInteractionAt > lastInteractionAt)
4195
+ return fail("interaction timestamps are reversed");
4196
+ const provenance = record2(interaction.provenance, `summary.interactions[${String(index)}].provenance`);
4197
+ exactKeys2(provenance, [
4198
+ "sourceId",
4199
+ "sourceVersion",
4200
+ "providerId",
4201
+ "providerVersion",
4202
+ "observedAt"
4203
+ ], `summary.interactions[${String(index)}].provenance`);
4204
+ if (provenance.sourceId !== "beeper-local" || provenance.sourceVersion !== BEEPER_CONTACT_INTERACTION_TRANSFORM.sourceVersion || provenance.providerId !== "beeper" || provenance.providerVersion !== providerVersion)
4205
+ return fail("interaction provenance is unsupported");
4206
+ return Object.freeze({
4207
+ accountId,
4208
+ accountProviderId,
4209
+ contactId,
4210
+ contactProviderId,
4211
+ network,
4212
+ sentCount,
4213
+ receivedCount,
4214
+ interactionCount,
4215
+ conversationCount,
4216
+ firstInteractionAt,
4217
+ lastInteractionAt,
4218
+ reciprocal: interaction.reciprocal,
4219
+ completeness: "lower-bound",
4220
+ provenance: Object.freeze({
4221
+ sourceId: "beeper-local",
4222
+ sourceVersion: BEEPER_CONTACT_INTERACTION_TRANSFORM.sourceVersion,
4223
+ providerId: "beeper",
4224
+ providerVersion,
4225
+ observedAt: timestamp(provenance.observedAt, `summary.interactions[${String(index)}].provenance.observedAt`)
4226
+ })
4227
+ });
4228
+ }));
4229
+ const interactionKeys = interactions.map((item) => `${item.accountId}\x00${item.contactId}`);
4230
+ if (new Set(interactionKeys).size !== interactionKeys.length || interactionKeys.some((key, index) => index > 0 && compareCanonicalText(key, interactionKeys[index - 1]) <= 0))
4231
+ return fail("interactions are not unique and canonically ordered");
4232
+ if ((accounts.length > 0 || interactions.length > 0) && (observedAt === null || accounts.some((account) => account.observedAt > observedAt) || interactions.some((interaction) => interaction.provenance.observedAt > observedAt)))
4233
+ return fail("summary observation does not cover retained relationship facts");
4234
+ const expectedSent = interactions.reduce((sum, item) => sum + item.sentCount, 0);
4235
+ const expectedReceived = interactions.reduce((sum, item) => sum + item.receivedCount, 0);
4236
+ if (parsedCounts.accounts !== accounts.length || parsedCounts.directRelationships !== interactions.length || parsedCounts.interactions !== expectedSent + expectedReceived || parsedCounts.sent !== expectedSent || parsedCounts.received !== expectedReceived || parsedCounts.directConversations !== interactions.reduce((sum, item) => sum + item.conversationCount, 0))
4237
+ return fail("summary counts are inconsistent");
4238
+ const integrity = record2(source.integrity, "summary.integrity");
4239
+ exactKeys2(integrity, ["algorithm", "summarySha256"], "summary.integrity");
4240
+ if (integrity.algorithm !== "sha256")
4241
+ return fail("integrity algorithm is unsupported");
4242
+ const summarySha256 = digest(integrity.summarySha256, "summary.integrity.summarySha256");
4243
+ const projection = Object.freeze({
4244
+ schemaVersion: BEEPER_CONTACT_INTERACTION_SCHEMA_VERSION,
4245
+ format: BEEPER_CONTACT_INTERACTION_FORMAT,
4246
+ transform: BEEPER_CONTACT_INTERACTION_TRANSFORM,
4247
+ source: Object.freeze({
4248
+ id: "beeper-local",
4249
+ version: BEEPER_CONTACT_INTERACTION_TRANSFORM.sourceVersion
4250
+ }),
4251
+ provider: Object.freeze({ id: "beeper", version: providerVersion }),
4252
+ observedAt,
4253
+ scope: Object.freeze({
4254
+ conversations: "complete-direct-only",
4255
+ messages: "current-direction-known-only"
4256
+ }),
4257
+ completeness: Object.freeze({
4258
+ kind: "lower-bound",
4259
+ sourceKind: completeness.sourceKind,
4260
+ reason,
4261
+ observedFrom,
4262
+ observedThrough
4263
+ }),
4264
+ warnings,
4265
+ privacy: Object.freeze({
4266
+ messageBodies: "excluded",
4267
+ attachments: "excluded",
4268
+ reactions: "excluded",
4269
+ media: "excluded",
4270
+ groupMessages: "excluded",
4271
+ localPaths: "excluded",
4272
+ credentials: "excluded"
4273
+ }),
4274
+ counts: parsedCounts,
4275
+ accounts,
4276
+ interactions
4277
+ });
4278
+ if (sha256(canonicalJson(summaryProjection(projection))) !== summarySha256) {
4279
+ return fail("integrity digest does not bind the summary projection");
4280
+ }
4281
+ return Object.freeze({
4282
+ ...projection,
4283
+ integrity: Object.freeze({ algorithm: "sha256", summarySha256 })
4284
+ });
4285
+ }
4286
+ function receiptProjection(receipt) {
4287
+ return receipt;
4288
+ }
4289
+ function nullableBound(value, label, maximum) {
4290
+ if (value === null)
4291
+ return null;
4292
+ const parsed = integer2(value, label);
4293
+ if (parsed < 1 || parsed > maximum) {
4294
+ return fail(`${label} is outside its supported bound`);
4295
+ }
4296
+ return parsed;
4297
+ }
4298
+ function parseBeeperContactInteractionExportResult(value) {
4299
+ const envelope = record2(value, "export result");
4300
+ exactKeys2(envelope, ["receipt", "output"], "export result");
4301
+ const output = parseBeeperContactInteractionSummary(envelope.output);
4302
+ const source = record2(envelope.receipt, "export receipt");
4303
+ exactKeys2(source, [
4304
+ "schemaVersion",
4305
+ "format",
4306
+ "runId",
4307
+ "operation",
4308
+ "status",
4309
+ "transport",
4310
+ "implementation",
4311
+ "startedAt",
4312
+ "finishedAt",
4313
+ "auth",
4314
+ "bounds",
4315
+ "source",
4316
+ "provider",
4317
+ "transform",
4318
+ "completeness",
4319
+ "counts",
4320
+ "output",
4321
+ "privacy",
4322
+ "integrity"
4323
+ ], "export receipt");
4324
+ if (source.schemaVersion !== 1 || source.format !== BEEPER_CONTACT_INTERACTION_RECEIPT_FORMAT || source.operation !== "beeper.export-contact-interactions" || source.status !== "succeeded" || source.transport !== "linked-device")
4325
+ return fail("export receipt identity is unsupported");
4326
+ const implementation = record2(source.implementation, "export receipt.implementation");
4327
+ exactKeys2(implementation, ["producer", "officialCli"], "export receipt.implementation");
4328
+ const producer = record2(implementation.producer, "export receipt.implementation.producer");
4329
+ exactKeys2(producer, ["package", "version"], "export receipt.implementation.producer");
4330
+ const officialCli = record2(implementation.officialCli, "export receipt.implementation.officialCli");
4331
+ exactKeys2(officialCli, ["implementation", "version", "commit", "platform", "binarySha256"], "export receipt.implementation.officialCli");
4332
+ if (producer.package !== BEEPER_CONTACT_INTERACTION_IMPLEMENTATION.producer.package || producer.version !== BEEPER_CONTACT_INTERACTION_IMPLEMENTATION.producer.version || officialCli.implementation !== BEEPER_CONTACT_INTERACTION_IMPLEMENTATION.officialCli.implementation || officialCli.version !== BEEPER_CONTACT_INTERACTION_IMPLEMENTATION.officialCli.version || officialCli.commit !== BEEPER_CONTACT_INTERACTION_IMPLEMENTATION.officialCli.commit || officialCli.platform !== BEEPER_CONTACT_INTERACTION_IMPLEMENTATION.officialCli.platform || officialCli.binarySha256 !== BEEPER_CONTACT_INTERACTION_IMPLEMENTATION.officialCli.binarySha256)
4333
+ return fail("export receipt implementation identity is unsupported");
4334
+ const runId = coordinate(source.runId, "export receipt.runId");
4335
+ if (!/^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/u.test(runId)) {
4336
+ return fail("export receipt.runId must be a lowercase UUID v4");
4337
+ }
4338
+ const startedAt = timestamp(source.startedAt, "export receipt.startedAt");
4339
+ const finishedAt = timestamp(source.finishedAt, "export receipt.finishedAt");
4340
+ if (startedAt > finishedAt)
4341
+ return fail("export receipt timestamps are reversed");
4342
+ const auth = record2(source.auth, "export receipt.auth");
4343
+ exactKeys2(auth, ["id", "kind", "provider", "identitySha256"], "export receipt.auth");
4344
+ const authId = coordinate(auth.id, "export receipt.auth.id");
4345
+ if (!/^[a-z][a-z0-9-]{0,127}$/u.test(authId) || auth.kind !== "linked-device-store" || auth.provider !== "beeper")
4346
+ return fail("export receipt auth identity is unsupported");
4347
+ const identitySha256 = digest(auth.identitySha256, "export receipt.auth.identitySha256");
4348
+ const bounds = record2(source.bounds, "export receipt.bounds");
4349
+ exactKeys2(bounds, ["limitChats", "limitMessages", "maxParticipants"], "export receipt.bounds");
4350
+ const parsedBounds = Object.freeze({
4351
+ limitChats: nullableBound(bounds.limitChats, "export receipt.bounds.limitChats", 1e5),
4352
+ limitMessages: nullableBound(bounds.limitMessages, "export receipt.bounds.limitMessages", 1e6),
4353
+ maxParticipants: nullableBound(bounds.maxParticipants, "export receipt.bounds.maxParticipants", 2000)
4354
+ });
4355
+ for (const [field, expected] of [
4356
+ ["source", output.source],
4357
+ ["provider", output.provider],
4358
+ ["transform", output.transform],
4359
+ ["completeness", output.completeness],
4360
+ ["counts", output.counts]
4361
+ ]) {
4362
+ const parsed = record2(source[field], `export receipt.${field}`);
4363
+ if (canonicalJson(parsed) !== canonicalJson(expected)) {
4364
+ return fail(`export receipt.${field} does not bind the output`);
4365
+ }
4366
+ }
4367
+ const outputBinding = record2(source.output, "export receipt.output");
4368
+ exactKeys2(outputBinding, ["schemaVersion", "format", "summarySha256"], "export receipt.output");
4369
+ const summarySha256 = digest(outputBinding.summarySha256, "export receipt.output.summarySha256");
4370
+ if (outputBinding.schemaVersion !== output.schemaVersion || outputBinding.format !== output.format || summarySha256 !== output.integrity.summarySha256)
4371
+ return fail("export receipt output identity does not bind the summary");
4372
+ const privacy = record2(source.privacy, "export receipt.privacy");
4373
+ exactKeys2(privacy, [
4374
+ "messageBodies",
4375
+ "attachments",
4376
+ "reactions",
4377
+ "media",
4378
+ "localPaths",
4379
+ "credentials"
4380
+ ], "export receipt.privacy");
4381
+ if (Object.values(privacy).some((item) => item !== "excluded")) {
4382
+ return fail("export receipt privacy boundary is unsupported");
4383
+ }
4384
+ const projection = Object.freeze({
4385
+ schemaVersion: 1,
4386
+ format: BEEPER_CONTACT_INTERACTION_RECEIPT_FORMAT,
4387
+ runId,
4388
+ operation: "beeper.export-contact-interactions",
4389
+ status: "succeeded",
4390
+ transport: "linked-device",
4391
+ implementation: BEEPER_CONTACT_INTERACTION_IMPLEMENTATION,
4392
+ startedAt,
4393
+ finishedAt,
4394
+ auth: Object.freeze({
4395
+ id: authId,
4396
+ kind: "linked-device-store",
4397
+ provider: "beeper",
4398
+ identitySha256
4399
+ }),
4400
+ bounds: parsedBounds,
4401
+ source: output.source,
4402
+ provider: output.provider,
4403
+ transform: output.transform,
4404
+ completeness: output.completeness,
4405
+ counts: output.counts,
4406
+ output: Object.freeze({
4407
+ schemaVersion: output.schemaVersion,
4408
+ format: output.format,
4409
+ summarySha256
4410
+ }),
4411
+ privacy: Object.freeze({
4412
+ messageBodies: "excluded",
4413
+ attachments: "excluded",
4414
+ reactions: "excluded",
4415
+ media: "excluded",
4416
+ localPaths: "excluded",
4417
+ credentials: "excluded"
4418
+ })
4419
+ });
4420
+ const integrity = record2(source.integrity, "export receipt.integrity");
4421
+ exactKeys2(integrity, ["algorithm", "receiptSha256"], "export receipt.integrity");
4422
+ if (integrity.algorithm !== "sha256") {
4423
+ return fail("export receipt integrity algorithm is unsupported");
4424
+ }
4425
+ const receiptSha256 = digest(integrity.receiptSha256, "export receipt.integrity.receiptSha256");
4426
+ if (sha256(canonicalJson(receiptProjection(projection))) !== receiptSha256) {
4427
+ return fail("export receipt integrity does not bind its projection");
4428
+ }
4429
+ return Object.freeze({
4430
+ receipt: Object.freeze({
4431
+ ...projection,
4432
+ integrity: Object.freeze({ algorithm: "sha256", receiptSha256 })
4433
+ }),
4434
+ output
4435
+ });
4436
+ }
4437
+
4438
+ // src/beeper-client.ts
4439
+ var MAX_STDERR_BYTES = 8 * 1024;
4440
+ var PROCESS_TIMEOUT_MS = 6 * 60 * 60 * 1000 + 60000;
4441
+ function fail2(message) {
4442
+ throw new Error(`Ghostget Beeper client: ${message}`);
4443
+ }
4444
+ function cliSourcePath() {
4445
+ const besideSource = fileURLToPath(new URL("./cli.ts", import.meta.url));
4446
+ if (existsSync(besideSource))
4447
+ return besideSource;
4448
+ const packagedSource = fileURLToPath(new URL("../src/cli.ts", import.meta.url));
4449
+ if (existsSync(packagedSource))
4450
+ return packagedSource;
4451
+ return fail2("the installed Ghostget CLI source is unavailable");
4452
+ }
4453
+ function requireBunRuntime() {
4454
+ if (typeof process.versions.bun !== "string") {
4455
+ fail2("@hraness/ghostget/beeper requires Bun to run the installed Ghostget CLI");
4456
+ }
4457
+ }
4458
+ function plainDataObject(value, label) {
4459
+ if (typeof value !== "object" || value === null || Array.isArray(value) || nodeTypes3.isProxy(value) || Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null)
4460
+ return fail2(`${label} must use a plain, non-proxy object`);
4461
+ const descriptors = Object.getOwnPropertyDescriptors(value);
4462
+ const keys = Reflect.ownKeys(descriptors);
4463
+ if (keys.some((key) => typeof key !== "string")) {
4464
+ return fail2(`${label} has unsupported symbol fields`);
4465
+ }
4466
+ for (const key of keys) {
4467
+ const descriptor = descriptors[key];
4468
+ if (descriptor === undefined || !descriptor.enumerable || !("value" in descriptor)) {
4469
+ return fail2(`${label} must contain only enumerable data properties`);
4470
+ }
4471
+ }
4472
+ return descriptors;
4473
+ }
4474
+ function positiveInteger(value, label, maximum) {
4475
+ if (value === undefined)
4476
+ return;
4477
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1 || value > maximum)
4478
+ return fail2(`${label} must be an integer from 1 through ${String(maximum)}`);
4479
+ return value;
4480
+ }
4481
+ function prepareRequest(value) {
4482
+ const descriptors = plainDataObject(value, "request");
4483
+ const keys = Object.keys(descriptors);
4484
+ const allowed = new Set([
4485
+ "authId",
4486
+ "limitChats",
4487
+ "limitMessages",
4488
+ "maxParticipants"
4489
+ ]);
4490
+ if (!keys.includes("authId") || keys.some((key) => !allowed.has(key))) {
4491
+ return fail2("request contains unsupported or missing fields");
4492
+ }
4493
+ const authId = descriptors.authId?.value;
4494
+ if (typeof authId !== "string" || !/^[a-z][a-z0-9-]{0,127}$/u.test(authId))
4495
+ return fail2("authId must be lowercase kebab text");
4496
+ const limitChats = positiveInteger(descriptors.limitChats?.value, "limitChats", 1e5);
4497
+ const limitMessages = positiveInteger(descriptors.limitMessages?.value, "limitMessages", 1e6);
4498
+ const maxParticipants = positiveInteger(descriptors.maxParticipants?.value, "maxParticipants", 2000);
4499
+ return Object.freeze({
4500
+ authId,
4501
+ ...limitChats === undefined ? {} : { limitChats },
4502
+ ...limitMessages === undefined ? {} : { limitMessages },
4503
+ ...maxParticipants === undefined ? {} : { maxParticipants }
4504
+ });
4505
+ }
4506
+ function environmentName(value) {
4507
+ if (value.length < 1 || value.includes("=") || value.includes("\x00")) {
4508
+ return fail2("environment name is malformed");
4509
+ }
4510
+ return value;
4511
+ }
4512
+ function prepareEnvironment(value) {
4513
+ const environment = Object.create(null);
4514
+ for (const [key, item] of Object.entries(process.env)) {
4515
+ if (typeof item === "string")
4516
+ environment[key] = item;
4517
+ }
4518
+ if (value === undefined)
4519
+ return Object.freeze(environment);
4520
+ const descriptors = plainDataObject(value, "environment");
4521
+ for (const key of Object.keys(descriptors).sort()) {
4522
+ const name = environmentName(key);
4523
+ const item = descriptors[key].value;
4524
+ if (item === undefined)
4525
+ delete environment[name];
4526
+ else if (typeof item !== "string" || item.includes("\x00")) {
4527
+ return fail2("environment value is malformed");
4528
+ } else
4529
+ environment[name] = item;
4530
+ }
4531
+ return Object.freeze(environment);
4532
+ }
4533
+ function prepareOptions(value) {
4534
+ const descriptors = plainDataObject(value, "options");
4535
+ const keys = Object.keys(descriptors);
4536
+ if (keys.some((key) => key !== "environment")) {
4537
+ return fail2("options contain an unsupported field");
4538
+ }
4539
+ return prepareEnvironment(descriptors.environment?.value);
4540
+ }
4541
+ function boundedError(value) {
4542
+ const text = typeof value === "string" ? value.trim() : "";
4543
+ const bytes = Buffer.from(text, "utf8");
4544
+ if (bytes.byteLength <= MAX_STDERR_BYTES)
4545
+ return text;
4546
+ return `${bytes.subarray(0, MAX_STDERR_BYTES).toString("utf8").trim()}\u2026`;
4547
+ }
4548
+ function exportBeeperContactInteractionsSync(requestValue, optionsValue = {}) {
4549
+ requireBunRuntime();
4550
+ const request = prepareRequest(requestValue);
4551
+ const environment = prepareOptions(optionsValue);
4552
+ const result = spawnSync(process.execPath, [
4553
+ cliSourcePath(),
4554
+ "beeper",
4555
+ "export-contact-interactions",
4556
+ "--auth",
4557
+ request.authId,
4558
+ ...request.limitChats === undefined ? [] : ["--limit-chats", String(request.limitChats)],
4559
+ ...request.limitMessages === undefined ? [] : ["--limit-messages", String(request.limitMessages)],
4560
+ ...request.maxParticipants === undefined ? [] : ["--max-participants", String(request.maxParticipants)],
4561
+ "--json"
4562
+ ], {
4563
+ cwd: process.cwd(),
4564
+ env: environment,
4565
+ encoding: "utf8",
4566
+ maxBuffer: BEEPER_CONTACT_INTERACTION_WIRE_MAX_BYTES,
4567
+ timeout: PROCESS_TIMEOUT_MS,
4568
+ stdio: ["ignore", "pipe", "inherit"]
4569
+ });
4570
+ if (result.error !== undefined)
4571
+ return fail2("summary process could not complete");
4572
+ if (result.status !== 0 || typeof result.stdout !== "string") {
4573
+ const stderr = boundedError(result.stderr);
4574
+ return fail2(stderr.length === 0 ? "summary process failed" : stderr);
4575
+ }
4576
+ if (Buffer.byteLength(result.stdout, "utf8") > BEEPER_CONTACT_INTERACTION_WIRE_MAX_BYTES) {
4577
+ return fail2("summary response exceeded its byte bound");
4578
+ }
4579
+ let parsed;
4580
+ try {
4581
+ parsed = JSON.parse(result.stdout);
4582
+ } catch {
4583
+ return fail2("summary response was not JSON");
4584
+ }
4585
+ const resultValue = parseBeeperContactInteractionExportResult(parsed);
4586
+ if (resultValue.receipt.auth.id !== request.authId) {
4587
+ return fail2("summary receipt auth does not match its request");
4588
+ }
4589
+ const expectedBounds = Object.freeze({
4590
+ limitChats: request.limitChats ?? null,
4591
+ limitMessages: request.limitMessages ?? null,
4592
+ maxParticipants: request.maxParticipants ?? null
4593
+ });
4594
+ if (resultValue.receipt.bounds.limitChats !== expectedBounds.limitChats || resultValue.receipt.bounds.limitMessages !== expectedBounds.limitMessages || resultValue.receipt.bounds.maxParticipants !== expectedBounds.maxParticipants)
4595
+ return fail2("summary receipt bounds do not match its request");
4596
+ return resultValue;
4597
+ }
4598
+ export {
4599
+ parseBeeperContactInteractionSummary,
4600
+ parseBeeperContactInteractionExportResult,
4601
+ exportBeeperContactInteractionsSync
4602
+ };