@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,135 @@
1
+ import { randomUUID } from "node:crypto";
2
+
3
+ import type { GhostgetAuth } from "./auth";
4
+ import { canonicalJson, sha256 } from "./canonical-json";
5
+ import { localCliToolArtifactForCurrentRuntime } from "./local-cli-tool-identity";
6
+ import type { LocalCliPluginBindingV1 } from "./provider-plugin";
7
+ import type { ProviderPluginRegistry } from "./provider-plugin-registry";
8
+ import {
9
+ withWebSessionCleanupAdmission,
10
+ type WebSessionCleanupAdmissionIdentity,
11
+ } from "./web-session-cleanup-admission";
12
+ import type { ProviderPluginCleanupBarrierRegistrar } from "./provider-plugin-cleanup-execution";
13
+
14
+ type Environment = Readonly<Record<string, string | undefined>>;
15
+
16
+ export type LocalCliCleanupAdmissionPurposeV1 =
17
+ | { readonly kind: "inspect" }
18
+ | { readonly kind: "subject-probe" }
19
+ | {
20
+ readonly kind: "messaging";
21
+ readonly action: string;
22
+ readonly contractVersion: number;
23
+ readonly messagingRunId: string;
24
+ readonly partIndex: number;
25
+ }
26
+ | {
27
+ readonly kind: "reconcile";
28
+ readonly action: string;
29
+ readonly contractVersion: number;
30
+ readonly recoveryRunId: string;
31
+ };
32
+
33
+ function ownerForBinding(
34
+ registry: ProviderPluginRegistry,
35
+ binding: LocalCliPluginBindingV1,
36
+ ) {
37
+ const owners = registry.list().filter((plugin) =>
38
+ plugin.bindings.some((candidate) => candidate === binding));
39
+ if (owners.length !== 1 || owners[0] === undefined) {
40
+ throw new Error("local CLI cleanup admission binding ownership is ambiguous");
41
+ }
42
+ return owners[0];
43
+ }
44
+
45
+ function cleanupAdmissionIdentity(
46
+ registry: ProviderPluginRegistry,
47
+ binding: LocalCliPluginBindingV1,
48
+ auth: GhostgetAuth | null,
49
+ purpose: LocalCliCleanupAdmissionPurposeV1,
50
+ ): WebSessionCleanupAdmissionIdentity {
51
+ const plugin = ownerForBinding(registry, binding);
52
+ if (purpose.kind === "reconcile" || purpose.kind === "messaging") {
53
+ const operation = binding.operations.find((candidate) =>
54
+ candidate.name === purpose.action
55
+ && candidate.contractVersions.includes(purpose.contractVersion));
56
+ if (
57
+ operation === undefined
58
+ || purpose.kind === "reconcile" && operation.reconciliation === undefined
59
+ || purpose.kind === "messaging" && operation.risk !== "R3"
60
+ ) {
61
+ throw new Error(
62
+ purpose.kind === "reconcile"
63
+ ? "local CLI cleanup admission reconciliation route is not installed"
64
+ : "local CLI cleanup admission messaging route is not an installed R3 operation",
65
+ );
66
+ }
67
+ }
68
+ const implementationHash = registry.implementationHash(binding).toString("hex");
69
+ let artifact: ReturnType<typeof localCliToolArtifactForCurrentRuntime> | null;
70
+ try {
71
+ artifact = localCliToolArtifactForCurrentRuntime(binding.tool);
72
+ } catch (error) {
73
+ if (purpose.kind !== "inspect") throw error;
74
+ artifact = null;
75
+ }
76
+ const executionIdentityHash = sha256(canonicalJson({
77
+ schemaVersion: 1,
78
+ transport: "local-cli",
79
+ plugin: {
80
+ id: plugin.id,
81
+ version: plugin.version,
82
+ implementationHash,
83
+ },
84
+ surfaceId: binding.surfaceId,
85
+ tool: binding.tool,
86
+ runtime: { platform: process.platform, arch: process.arch },
87
+ artifact,
88
+ purpose,
89
+ }));
90
+ return Object.freeze({
91
+ runId: randomUUID(),
92
+ pluginId: plugin.id,
93
+ pluginVersion: plugin.version,
94
+ pluginImplementationHash: implementationHash,
95
+ adapterId: "local-cli-kernel",
96
+ adapterHash: executionIdentityHash,
97
+ surfaceId: binding.surfaceId,
98
+ authId: auth?.id ?? "local-cli-inspect",
99
+ authHash: auth === null
100
+ ? sha256(canonicalJson({ schemaVersion: 1, purpose: "local-cli-inspect" }))
101
+ : sha256(canonicalJson(auth)),
102
+ transport: "local-cli",
103
+ executionIdentityHash,
104
+ });
105
+ }
106
+
107
+ /**
108
+ * Admit non-invocation local-CLI work (inspection, auth probes, and recovery
109
+ * readback) to the same durable resource-containment kernel as normal runs.
110
+ */
111
+ export function withLocalCliProviderCleanupAdmission<T>(
112
+ input: {
113
+ readonly registry: ProviderPluginRegistry;
114
+ readonly binding: LocalCliPluginBindingV1;
115
+ readonly auth: GhostgetAuth | null;
116
+ readonly purpose: LocalCliCleanupAdmissionPurposeV1;
117
+ readonly environment?: Environment;
118
+ readonly now?: Date;
119
+ },
120
+ operation: (
121
+ registerCleanupBarrier: ProviderPluginCleanupBarrierRegistrar,
122
+ ) => Promise<T>,
123
+ ): Promise<T> {
124
+ return withWebSessionCleanupAdmission(
125
+ cleanupAdmissionIdentity(
126
+ input.registry,
127
+ input.binding,
128
+ input.auth,
129
+ input.purpose,
130
+ ),
131
+ input.environment ?? process.env,
132
+ operation,
133
+ input.now,
134
+ );
135
+ }
@@ -0,0 +1,271 @@
1
+ import { createHash } from "node:crypto";
2
+ import { types as nodeTypes } from "node:util";
3
+
4
+ import type {
5
+ BrowserDispatchPlan,
6
+ IdempotencyKind,
7
+ InputSchema,
8
+ LocalCliRecipe,
9
+ OperationInput,
10
+ OperationRisk,
11
+ } from "./model";
12
+ import type { LocalCliPluginOperationV1 } from "./provider-plugin";
13
+ import {
14
+ isProviderPluginOperationName,
15
+ isProviderPluginSurfaceId,
16
+ type ProviderPluginOperationName,
17
+ } from "./provider-plugin-identifiers";
18
+ import type { ProviderPluginRegistry } from "./provider-plugin-registry";
19
+ import {
20
+ parseLocalCliToolIdentityV1,
21
+ type LocalCliToolIdentityV1,
22
+ } from "./local-cli-tool-identity";
23
+
24
+ export type LocalCliContract = {
25
+ readonly surface: string;
26
+ readonly operation: ProviderPluginOperationName;
27
+ readonly contractVersion: number;
28
+ readonly risk: OperationRisk;
29
+ readonly input: InputSchema;
30
+ readonly sideEffect: string;
31
+ readonly idempotency: IdempotencyKind;
32
+ readonly dedupeWindowMs: number;
33
+ readonly state: "observed" | "capture-required";
34
+ readonly dispatch: "none" | "single" | "thread-items" | "bounded-items";
35
+ readonly implementation: string;
36
+ readonly tool: LocalCliToolIdentityV1;
37
+ };
38
+
39
+ export type LocalCliContractIdentityV1 = {
40
+ readonly surface: string;
41
+ readonly action: string;
42
+ readonly version: number;
43
+ readonly hash: string;
44
+ readonly tool: LocalCliToolIdentityV1;
45
+ };
46
+
47
+ function hasWellFormedUnicode(value: string): boolean {
48
+ for (let index = 0; index < value.length; index += 1) {
49
+ const code = value.charCodeAt(index);
50
+ if (code >= 0xd800 && code <= 0xdbff) {
51
+ if (index + 1 >= value.length) return false;
52
+ const next = value.charCodeAt(index + 1);
53
+ if (next < 0xdc00 || next > 0xdfff) return false;
54
+ index += 1;
55
+ } else if (code >= 0xdc00 && code <= 0xdfff) return false;
56
+ }
57
+ return true;
58
+ }
59
+
60
+ function strictIdentityRecord(
61
+ value: unknown,
62
+ ): Readonly<Record<string, unknown>> {
63
+ if (
64
+ typeof value !== "object"
65
+ || value === null
66
+ || Array.isArray(value)
67
+ || nodeTypes.isProxy(value)
68
+ ) {
69
+ throw new Error("local CLI contract identity must be an object");
70
+ }
71
+ const prototype: unknown = Object.getPrototypeOf(value) as unknown;
72
+ if (prototype !== Object.prototype && prototype !== null) {
73
+ throw new Error("local CLI contract identity has an unsupported prototype");
74
+ }
75
+ const descriptors = Object.getOwnPropertyDescriptors(value);
76
+ if (Reflect.ownKeys(descriptors).some((key) => typeof key !== "string")) {
77
+ throw new Error("local CLI contract identity has unsupported symbol fields");
78
+ }
79
+ const result: Record<string, unknown> = {};
80
+ for (const [key, descriptor] of Object.entries(descriptors)) {
81
+ if (
82
+ !descriptor.enumerable
83
+ || !("value" in descriptor)
84
+ || !hasWellFormedUnicode(key)
85
+ || /[\u0000-\u001f\u007f-\u009f]/u.test(key)
86
+ ) {
87
+ throw new Error("local CLI contract identity has unsupported accessor fields");
88
+ }
89
+ result[key] = descriptor.value;
90
+ }
91
+ return result;
92
+ }
93
+
94
+ export function parseLocalCliContractIdentityV1(
95
+ value: unknown,
96
+ ): LocalCliContractIdentityV1 {
97
+ const record = strictIdentityRecord(value);
98
+ const keys = Object.keys(record).sort();
99
+ if (keys.join("\0") !== ["action", "hash", "surface", "tool", "version"].sort().join("\0")) {
100
+ throw new Error("local CLI contract identity has unsupported fields");
101
+ }
102
+ if (
103
+ !isProviderPluginSurfaceId(record.surface)
104
+ || !isProviderPluginOperationName(record.action)
105
+ || typeof record.version !== "number"
106
+ || !Number.isSafeInteger(record.version)
107
+ || record.version < 1
108
+ || record.version > 1_000_000
109
+ || typeof record.hash !== "string"
110
+ || !/^[a-f0-9]{64}$/u.test(record.hash)
111
+ ) {
112
+ throw new Error("local CLI contract identity is malformed");
113
+ }
114
+ return Object.freeze({
115
+ surface: record.surface,
116
+ action: record.action,
117
+ version: record.version,
118
+ hash: record.hash,
119
+ tool: parseLocalCliToolIdentityV1(record.tool),
120
+ });
121
+ }
122
+
123
+ function stableJson(value: unknown): string {
124
+ if (value === null || typeof value === "boolean" || typeof value === "string") {
125
+ return JSON.stringify(value);
126
+ }
127
+ if (typeof value === "number") {
128
+ if (!Number.isFinite(value)) throw new Error("local CLI contract contains a non-finite number");
129
+ return JSON.stringify(value);
130
+ }
131
+ if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
132
+ if (typeof value === "object") {
133
+ const record = value as Record<string, unknown>;
134
+ return `{${Object.keys(record).sort().map((key) =>
135
+ `${JSON.stringify(key)}:${stableJson(record[key])}`).join(",")}}`;
136
+ }
137
+ throw new Error("local CLI contract contains an unsupported value");
138
+ }
139
+
140
+ function requireLocalCliOperation(
141
+ recipe: Pick<LocalCliRecipe, "surface" | "action" | "contractVersion">,
142
+ registry: ProviderPluginRegistry,
143
+ ) {
144
+ const resolution = registry.resolveOperationDefinition(
145
+ "local-cli",
146
+ recipe.surface,
147
+ recipe.action,
148
+ recipe.contractVersion,
149
+ );
150
+ if (resolution === undefined || resolution.binding.transport !== "local-cli") {
151
+ throw new Error(
152
+ `local CLI contract ${recipe.surface}/${recipe.action}@${recipe.contractVersion} is not installed`,
153
+ );
154
+ }
155
+ return {
156
+ ...resolution,
157
+ binding: resolution.binding,
158
+ operation: resolution.operation as LocalCliPluginOperationV1,
159
+ };
160
+ }
161
+
162
+ const caches = new WeakMap<ProviderPluginRegistry, Map<string, LocalCliContract>>();
163
+
164
+ function cache(registry: ProviderPluginRegistry): Map<string, LocalCliContract> {
165
+ const current = caches.get(registry);
166
+ if (current !== undefined) return current;
167
+ const created = new Map<string, LocalCliContract>();
168
+ caches.set(registry, created);
169
+ return created;
170
+ }
171
+
172
+ function key(recipe: Pick<LocalCliRecipe, "surface" | "action" | "contractVersion">): string {
173
+ return `${recipe.surface}/${recipe.action}@${recipe.contractVersion}`;
174
+ }
175
+
176
+ export function getLocalCliContract(
177
+ recipe: LocalCliRecipe,
178
+ registry: ProviderPluginRegistry,
179
+ ): LocalCliContract {
180
+ const resolution = requireLocalCliOperation(recipe, registry);
181
+ const contractKey = key(recipe);
182
+ const current = cache(registry).get(contractKey);
183
+ if (current !== undefined) return current;
184
+ const contract: LocalCliContract = Object.freeze({
185
+ surface: recipe.surface,
186
+ operation: resolution.operation.name as ProviderPluginOperationName,
187
+ contractVersion: resolution.contractVersion,
188
+ risk: resolution.operation.risk,
189
+ input: resolution.operation.input,
190
+ sideEffect: resolution.operation.sideEffect,
191
+ idempotency: resolution.operation.idempotency,
192
+ dedupeWindowMs: resolution.operation.dedupeWindowMs,
193
+ state: resolution.operation.state,
194
+ dispatch: resolution.operation.dispatch,
195
+ implementation: resolution.operation.implementation,
196
+ tool: resolution.binding.tool,
197
+ });
198
+ cache(registry).set(contractKey, contract);
199
+ return contract;
200
+ }
201
+
202
+ export function localCliContractHash(
203
+ contract: LocalCliContract,
204
+ registry: ProviderPluginRegistry,
205
+ ): string {
206
+ const { binding } = requireLocalCliOperation({
207
+ surface: contract.surface,
208
+ action: contract.operation,
209
+ contractVersion: contract.contractVersion,
210
+ }, registry);
211
+ return createHash("sha256")
212
+ .update(stableJson(contract))
213
+ .update("\0")
214
+ .update(registry.contractImplementationHash(binding))
215
+ .digest("hex");
216
+ }
217
+
218
+ export function localCliContractIdentity(
219
+ recipe: LocalCliRecipe,
220
+ registry: ProviderPluginRegistry,
221
+ ): LocalCliContractIdentityV1 {
222
+ const contract = getLocalCliContract(recipe, registry);
223
+ return Object.freeze({
224
+ surface: contract.surface,
225
+ action: contract.operation,
226
+ version: contract.contractVersion,
227
+ hash: localCliContractHash(contract, registry),
228
+ tool: contract.tool,
229
+ });
230
+ }
231
+
232
+ export function isCompatibleLocalCliContractHash(
233
+ contract: LocalCliContract,
234
+ candidate: string,
235
+ registry: ProviderPluginRegistry,
236
+ ): boolean {
237
+ if (candidate === localCliContractHash(contract, registry)) return true;
238
+ const { binding } = requireLocalCliOperation({
239
+ surface: contract.surface,
240
+ action: contract.operation,
241
+ contractVersion: contract.contractVersion,
242
+ }, registry);
243
+ return registry.legacyContractImplementationHashes(
244
+ binding,
245
+ contract.operation,
246
+ contract.contractVersion,
247
+ ).some((implementationHash) =>
248
+ createHash("sha256")
249
+ .update(stableJson(contract))
250
+ .update("\0")
251
+ .update(implementationHash)
252
+ .digest("hex") === candidate);
253
+ }
254
+
255
+ export function planLocalCliDispatches(
256
+ recipe: LocalCliRecipe,
257
+ input: OperationInput,
258
+ registry: ProviderPluginRegistry,
259
+ ): readonly BrowserDispatchPlan[] {
260
+ getLocalCliContract(recipe, registry);
261
+ return requireLocalCliOperation(recipe, registry).operation.planDispatches(input);
262
+ }
263
+
264
+ export function localCliConditionalInputIssues(
265
+ recipe: LocalCliRecipe,
266
+ input: OperationInput,
267
+ registry: ProviderPluginRegistry,
268
+ ): readonly string[] {
269
+ getLocalCliContract(recipe, registry);
270
+ return requireLocalCliOperation(recipe, registry).operation.validateInput(input);
271
+ }
@@ -0,0 +1,98 @@
1
+ import type { GhostgetAuth } from "./auth";
2
+ import type {
3
+ FileInputValue,
4
+ LocalCliRecipe,
5
+ OperationInput,
6
+ GhostgetManifest,
7
+ } from "./model";
8
+ import type {
9
+ OperationDeadline,
10
+ OperationDeadlineClock,
11
+ } from "./operation-deadline";
12
+ import type { ProviderPluginCleanupBarrierRegistrar } from "./provider-plugin-cleanup-execution";
13
+ import type {
14
+ ProviderAcceptedMutationTarget,
15
+ ProviderBoundMutationTarget,
16
+ } from "./recovery";
17
+ import { runWebSessionOperationWithDeadline } from "./web-session-execution";
18
+
19
+ export type LocalCliFileResolver = (
20
+ files: readonly FileInputValue[],
21
+ ) => Promise<readonly string[]>;
22
+
23
+ export type LocalCliExecution = {
24
+ readonly status: "succeeded" | "failed" | "partial" | "indeterminate";
25
+ readonly output: unknown;
26
+ readonly finalUrl: string | null;
27
+ readonly noOp?: true;
28
+ readonly dispatchStarted: boolean;
29
+ readonly dispatch: {
30
+ readonly planned: number;
31
+ readonly started: number;
32
+ readonly verified: number;
33
+ };
34
+ readonly error?: string;
35
+ };
36
+
37
+ export type LocalCliDispatchEvent = {
38
+ readonly id: string;
39
+ readonly index: number;
40
+ readonly progress: LocalCliExecution["dispatch"];
41
+ };
42
+
43
+ export type LocalCliProviderAcceptedMutationTargetEvent = {
44
+ readonly id: string;
45
+ readonly index: number;
46
+ readonly target: ProviderAcceptedMutationTarget;
47
+ };
48
+
49
+ export type LocalCliProviderBoundMutationTargetEvent = {
50
+ readonly id: string;
51
+ readonly index: number;
52
+ readonly target: ProviderBoundMutationTarget;
53
+ };
54
+
55
+ export type LocalCliOperationDeadline = Pick<
56
+ OperationDeadline,
57
+ "signal" | "remainingTimeMs" | "run" | "throwIfUnavailable"
58
+ >;
59
+
60
+ export type LocalCliExecutionOptions = {
61
+ readonly fileResolver?: LocalCliFileResolver;
62
+ readonly environment?: Readonly<Record<string, string | undefined>>;
63
+ readonly signal?: AbortSignal;
64
+ readonly operationDeadline?: LocalCliOperationDeadline;
65
+ readonly deadlineClock?: OperationDeadlineClock;
66
+ readonly registerCleanupBarrier?: ProviderPluginCleanupBarrierRegistrar;
67
+ readonly beforeDispatch?: (event: LocalCliDispatchEvent) => Promise<void>;
68
+ readonly afterProviderAcceptedMutationTarget?: (
69
+ event: LocalCliProviderAcceptedMutationTargetEvent,
70
+ ) => Promise<void>;
71
+ readonly afterProviderBoundMutationTarget?: (
72
+ event: LocalCliProviderBoundMutationTargetEvent,
73
+ ) => Promise<void>;
74
+ readonly afterDispatchVerified?: (
75
+ event: LocalCliDispatchEvent,
76
+ ) => Promise<void>;
77
+ };
78
+
79
+ export type LocalCliOperationExecutor = (
80
+ manifest: GhostgetManifest,
81
+ recipe: LocalCliRecipe,
82
+ input: OperationInput,
83
+ auth: GhostgetAuth,
84
+ options: LocalCliExecutionOptions,
85
+ ) => Promise<LocalCliExecution>;
86
+
87
+ /** Local transport facade over the shared bounded deadline/cleanup join. */
88
+ export function runLocalCliOperationWithDeadline<T>(
89
+ recipe: Pick<LocalCliRecipe, "timeoutMs">,
90
+ options: LocalCliExecutionOptions,
91
+ execute: (boundedOptions: LocalCliExecutionOptions) => Promise<T>,
92
+ ): Promise<T> {
93
+ return runWebSessionOperationWithDeadline(
94
+ recipe,
95
+ options,
96
+ (boundedOptions) => execute(boundedOptions),
97
+ );
98
+ }