@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,695 @@
1
+ import { createHash } from "node:crypto";
2
+ import {
3
+ chmodSync,
4
+ closeSync,
5
+ constants,
6
+ fstatSync,
7
+ lstatSync,
8
+ mkdtempSync,
9
+ openSync,
10
+ readFileSync,
11
+ readdirSync,
12
+ rmSync,
13
+ writeFileSync,
14
+ type BigIntStats,
15
+ } from "node:fs";
16
+ import { tmpdir } from "node:os";
17
+ import { basename, join } from "node:path";
18
+
19
+ import { main as defaultGhostgetMain, type GhostgetDependencies } from "../ghostget";
20
+ import {
21
+ isLocalCliOperation,
22
+ isProviderOperation,
23
+ isWebSessionOperation,
24
+ manifestHash,
25
+ parseDiagnosticManifest,
26
+ parseRuntimeManifest,
27
+ type GhostgetManifest,
28
+ } from "../model";
29
+ import type { ProviderPluginRegistry } from "../provider-plugin-registry";
30
+ import {
31
+ portableProviderPluginStoreRoot,
32
+ } from "../provider-plugin-lifecycle";
33
+ import {
34
+ createPortableProviderPluginCatalog,
35
+ type PortableProviderPluginCatalog,
36
+ } from "../provider-plugin-portable-catalog";
37
+ import {
38
+ withPortableProviderPluginCatalogLock,
39
+ } from "../provider-plugin-store";
40
+ import { providerPluginRegistry } from "../provider-plugins";
41
+ import {
42
+ adapterManifestPath,
43
+ installBundledAdapterGeneration,
44
+ listInstalledDiagnosticManifestSnapshots,
45
+ type BundledAdapterGenerationSelection,
46
+ } from "../storage";
47
+
48
+ type SyncOutput = {
49
+ readonly stdout: (value: string) => void;
50
+ readonly stderr: (value: string) => void;
51
+ };
52
+
53
+ type GhostgetMain = (
54
+ rawArguments: readonly string[],
55
+ environment: Readonly<Record<string, string | undefined>>,
56
+ output: {
57
+ readonly stdout: (value: string) => void;
58
+ readonly stderr: (value: string) => void;
59
+ },
60
+ dependencyOverrides?: Partial<GhostgetDependencies>,
61
+ ) => Promise<number>;
62
+
63
+ type GenerationInstaller = (
64
+ selections: readonly BundledAdapterGenerationSelection[],
65
+ environment: Readonly<Record<string, string | undefined>>,
66
+ ) => {
67
+ readonly commitId: string;
68
+ readonly installed: number;
69
+ readonly preservedLegacy: number;
70
+ };
71
+
72
+ type SourceSnapshot = {
73
+ readonly path: string;
74
+ readonly sourceContentSha256: string;
75
+ readonly bytes: Uint8Array;
76
+ readonly value: unknown;
77
+ };
78
+
79
+ export type DiscoveredBundledAdapter = {
80
+ readonly id: string;
81
+ readonly current: SourceSnapshot & { readonly manifest: GhostgetManifest };
82
+ readonly upgradeFrom: readonly (
83
+ SourceSnapshot & { readonly manifest: GhostgetManifest }
84
+ )[];
85
+ readonly routeKey: string;
86
+ };
87
+
88
+ const defaultOutput: SyncOutput = {
89
+ stdout: (value) => process.stdout.write(value),
90
+ stderr: (value) => process.stderr.write(value),
91
+ };
92
+
93
+ const defaultAssetsDirectory = join(
94
+ import.meta.dir,
95
+ "..",
96
+ "assets",
97
+ "adapters",
98
+ );
99
+ const maximumSourceBytes = 1024 * 1024;
100
+ const currentManifestNames = new Set([
101
+ "wrench-adapter.json",
102
+ "wrench-web-adapter.json",
103
+ ]);
104
+ const archivedManifestNamePattern =
105
+ /^(wrench(?:-web)?-adapter)\.v[0-9]+\.[0-9]+\.[0-9]+\.json$/u;
106
+
107
+ function sha256(value: Uint8Array | string): string {
108
+ return createHash("sha256").update(value).digest("hex");
109
+ }
110
+
111
+ function portableCatalogFingerprint(
112
+ catalog: PortableProviderPluginCatalog,
113
+ ): string {
114
+ const identities = catalog.installed.map((entry) => ({
115
+ pluginId: entry.active.pluginId,
116
+ pluginVersion: entry.active.pluginVersion,
117
+ bundleSha256: entry.active.bundleSha256,
118
+ manifestSha256: entry.package.manifestSha256,
119
+ status: entry.active.status,
120
+ activatedAt: entry.active.activatedAt,
121
+ ...(entry.active.status === "disabled"
122
+ ? { disabledAt: entry.active.disabledAt }
123
+ : {}),
124
+ trustedAt: entry.trust.trustedAt,
125
+ })).sort((left, right) =>
126
+ left.pluginId.localeCompare(right.pluginId)
127
+ || left.bundleSha256.localeCompare(right.bundleSha256));
128
+ return sha256(JSON.stringify(identities));
129
+ }
130
+
131
+ function sameFileIdentity(left: BigIntStats, right: BigIntStats): boolean {
132
+ return left.dev === right.dev
133
+ && left.ino === right.ino
134
+ && left.size === right.size
135
+ && left.mode === right.mode
136
+ && left.mtimeNs === right.mtimeNs
137
+ && left.ctimeNs === right.ctimeNs;
138
+ }
139
+
140
+ function readSourceSnapshot(path: string): SourceSnapshot {
141
+ const lexical = lstatSync(path, { bigint: true });
142
+ if (lexical.isSymbolicLink() || !lexical.isFile()) {
143
+ throw new Error(`bundled adapter source is not a real regular file: ${path}`);
144
+ }
145
+ if (lexical.size > BigInt(maximumSourceBytes)) {
146
+ throw new Error(`bundled adapter source exceeds ${maximumSourceBytes} bytes: ${path}`);
147
+ }
148
+ const descriptor = openSync(
149
+ path,
150
+ constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0),
151
+ );
152
+ try {
153
+ const before = fstatSync(descriptor, { bigint: true });
154
+ if (
155
+ !before.isFile()
156
+ || !sameFileIdentity(lexical, before)
157
+ || before.size > BigInt(maximumSourceBytes)
158
+ ) {
159
+ throw new Error(`bundled adapter source changed before snapshot: ${path}`);
160
+ }
161
+ const bytes = readFileSync(descriptor);
162
+ const after = fstatSync(descriptor, { bigint: true });
163
+ const finalLexical = lstatSync(path, { bigint: true });
164
+ if (
165
+ bytes.byteLength > maximumSourceBytes
166
+ || !sameFileIdentity(before, after)
167
+ || !sameFileIdentity(after, finalLexical)
168
+ ) {
169
+ throw new Error(`bundled adapter source changed while being snapshotted: ${path}`);
170
+ }
171
+ let text: string;
172
+ try {
173
+ text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
174
+ } catch (error) {
175
+ throw new Error(`bundled adapter source is not valid UTF-8: ${path}`, {
176
+ cause: error,
177
+ });
178
+ }
179
+ let value: unknown;
180
+ try {
181
+ value = JSON.parse(text) as unknown;
182
+ } catch (error) {
183
+ throw new Error(`bundled adapter source is not valid JSON: ${path}`, {
184
+ cause: error,
185
+ });
186
+ }
187
+ return Object.freeze({
188
+ path,
189
+ sourceContentSha256: sha256(bytes),
190
+ bytes: Uint8Array.from(bytes),
191
+ value,
192
+ });
193
+ } finally {
194
+ closeSync(descriptor);
195
+ }
196
+ }
197
+
198
+ function routeKey(transport: string, surfaceId: string): string {
199
+ return `${transport}:${surfaceId}`;
200
+ }
201
+
202
+ function manifestRouteKey(
203
+ manifest: GhostgetManifest,
204
+ registry: ProviderPluginRegistry,
205
+ ): string {
206
+ if (manifest.surfaceId === undefined) {
207
+ throw new Error(`bundled adapter ${manifest.id} has no provider surface`);
208
+ }
209
+ const operations = Object.entries(manifest.operations);
210
+ const usesProviderApi = operations.every(([, operation]) =>
211
+ isProviderOperation(operation)
212
+ );
213
+ const usesSessionApi = operations.every(([, operation]) =>
214
+ isWebSessionOperation(operation)
215
+ );
216
+ const usesLocalCli = operations.every(([, operation]) =>
217
+ isLocalCliOperation(operation)
218
+ );
219
+ if (!usesProviderApi && !usesSessionApi && !usesLocalCli) {
220
+ throw new Error(`bundled adapter ${manifest.id} mixes provider transports`);
221
+ }
222
+ const candidates = registry.list().flatMap((plugin) =>
223
+ plugin.bindings.filter((binding) => {
224
+ if (binding.surfaceId !== manifest.surfaceId) return false;
225
+ if (
226
+ (usesProviderApi && binding.transport !== "provider-api")
227
+ || (
228
+ usesSessionApi
229
+ && binding.transport !== "web-session-api"
230
+ && binding.transport !== "linked-device"
231
+ )
232
+ || (usesLocalCli && binding.transport !== "local-cli")
233
+ ) {
234
+ return false;
235
+ }
236
+ return operations.every(
237
+ ([operationId, operation]) => {
238
+ if (
239
+ !isProviderOperation(operation)
240
+ && !isWebSessionOperation(operation)
241
+ && !isLocalCliOperation(operation)
242
+ ) {
243
+ return false;
244
+ }
245
+ const contractVersion = isProviderOperation(operation)
246
+ ? operation.provider.contractVersion
247
+ : isWebSessionOperation(operation)
248
+ ? operation.webSession.contractVersion
249
+ : operation.localCli.contractVersion;
250
+ return registry.resolveOperationDefinition(
251
+ binding.transport,
252
+ binding.surfaceId,
253
+ operationId,
254
+ contractVersion,
255
+ ) !== undefined;
256
+ },
257
+ );
258
+ })
259
+ );
260
+ if (candidates.length !== 1) {
261
+ throw new Error(
262
+ `bundled adapter ${manifest.id} does not resolve to exactly one provider plugin binding`,
263
+ );
264
+ }
265
+ return routeKey(candidates[0]!.transport, candidates[0]!.surfaceId);
266
+ }
267
+
268
+ /**
269
+ * Discover the distribution inventory from assets, then prove inverse parity
270
+ * with the built-in provider registry. Neither side can silently add a route.
271
+ */
272
+ export function discoverBundledAdapters(
273
+ assetsDirectory: string = defaultAssetsDirectory,
274
+ registry: ProviderPluginRegistry = providerPluginRegistry,
275
+ ): readonly DiscoveredBundledAdapter[] {
276
+ const rootStats = lstatSync(assetsDirectory);
277
+ if (rootStats.isSymbolicLink() || !rootStats.isDirectory()) {
278
+ throw new Error("bundled adapter asset root must be a real directory");
279
+ }
280
+ const discovered: DiscoveredBundledAdapter[] = [];
281
+ const surfaceEntries = readdirSync(assetsDirectory, {
282
+ withFileTypes: true,
283
+ }).sort((left, right) => left.name.localeCompare(right.name));
284
+ for (const surfaceEntry of surfaceEntries) {
285
+ if (surfaceEntry.isSymbolicLink() || !surfaceEntry.isDirectory()) {
286
+ throw new Error(
287
+ `bundled adapter asset root contains an unsafe entry: ${surfaceEntry.name}`,
288
+ );
289
+ }
290
+ const surfaceDirectory = join(assetsDirectory, surfaceEntry.name);
291
+ const surfaceStats = lstatSync(surfaceDirectory);
292
+ if (surfaceStats.isSymbolicLink() || !surfaceStats.isDirectory()) {
293
+ throw new Error(`bundled adapter surface is not a real directory: ${surfaceEntry.name}`);
294
+ }
295
+ const files = readdirSync(surfaceDirectory, {
296
+ withFileTypes: true,
297
+ }).sort((left, right) => left.name.localeCompare(right.name));
298
+ for (const file of files) {
299
+ if (file.isSymbolicLink()) {
300
+ throw new Error(
301
+ `bundled adapter surface contains a symbolic link: ${surfaceEntry.name}/${file.name}`,
302
+ );
303
+ }
304
+ }
305
+ const currentFiles = files.filter(
306
+ (file) => file.isFile() && currentManifestNames.has(file.name),
307
+ );
308
+ if (currentFiles.length === 0) {
309
+ throw new Error(`bundled adapter surface has no current manifest: ${surfaceEntry.name}`);
310
+ }
311
+ for (const currentFile of currentFiles) {
312
+ const current = readSourceSnapshot(
313
+ join(surfaceDirectory, currentFile.name),
314
+ );
315
+ const currentParsed = parseRuntimeManifest(current.value, registry);
316
+ if (!currentParsed.ok) {
317
+ throw new Error(
318
+ `bundled adapter ${currentFile.name} is invalid: ${currentParsed.issues.join("; ")}`,
319
+ );
320
+ }
321
+ const currentStem = currentFile.name.slice(0, -".json".length);
322
+ const archived = files.filter((file) => {
323
+ const match = archivedManifestNamePattern.exec(file.name);
324
+ return file.isFile() && match?.[1] === currentStem;
325
+ }).map((file) => {
326
+ const snapshot = readSourceSnapshot(join(surfaceDirectory, file.name));
327
+ const parsed = parseDiagnosticManifest(snapshot.value, registry);
328
+ if (!parsed.ok) {
329
+ throw new Error(
330
+ `bundled adapter baseline ${file.name} is invalid: ${parsed.issues.join("; ")}`,
331
+ );
332
+ }
333
+ if (parsed.value.id !== currentParsed.value.id) {
334
+ throw new Error(
335
+ `bundled adapter baseline ${file.name} has the wrong adapter ID`,
336
+ );
337
+ }
338
+ return Object.freeze({ ...snapshot, manifest: parsed.value });
339
+ });
340
+ const archivedHashes = archived.map((entry) =>
341
+ manifestHash(entry.manifest)
342
+ );
343
+ if (new Set(archivedHashes).size !== archivedHashes.length) {
344
+ throw new Error(
345
+ `bundled adapter ${currentParsed.value.id} has duplicate upgrade baselines`,
346
+ );
347
+ }
348
+ discovered.push(Object.freeze({
349
+ id: currentParsed.value.id,
350
+ current: Object.freeze({
351
+ ...current,
352
+ manifest: currentParsed.value,
353
+ }),
354
+ upgradeFrom: Object.freeze(archived),
355
+ routeKey: manifestRouteKey(currentParsed.value, registry),
356
+ }));
357
+ }
358
+ }
359
+ discovered.sort((left, right) => left.id.localeCompare(right.id));
360
+ const ids = discovered.map((adapter) => adapter.id);
361
+ const routes = discovered.map((adapter) => adapter.routeKey);
362
+ if (new Set(ids).size !== ids.length) {
363
+ throw new Error("bundled adapter inventory contains duplicate IDs");
364
+ }
365
+ if (new Set(routes).size !== routes.length) {
366
+ throw new Error("bundled adapter inventory contains duplicate provider routes");
367
+ }
368
+ const expectedRoutes = registry.list().flatMap((plugin) =>
369
+ plugin.bindings.map((binding) =>
370
+ routeKey(binding.transport, binding.surfaceId)
371
+ )
372
+ ).sort();
373
+ const actualRoutes = [...routes].sort();
374
+ if (
375
+ expectedRoutes.length !== actualRoutes.length
376
+ || expectedRoutes.some((route, index) => route !== actualRoutes[index])
377
+ ) {
378
+ throw new Error(
379
+ `bundled adapter inventory and provider plugin registry differ (assets: ${actualRoutes.join(", ")}; registry: ${expectedRoutes.join(", ")})`,
380
+ );
381
+ }
382
+ return Object.freeze(discovered);
383
+ }
384
+
385
+ function captureOutput(): {
386
+ readonly output: SyncOutput;
387
+ readonly stdout: () => string;
388
+ readonly stderr: () => string;
389
+ } {
390
+ let stdout = "";
391
+ let stderr = "";
392
+ return {
393
+ output: {
394
+ stdout: (value) => { stdout += value; },
395
+ stderr: (value) => { stderr += value; },
396
+ },
397
+ stdout: () => stdout,
398
+ stderr: () => stderr,
399
+ };
400
+ }
401
+
402
+ function compactDetail(value: string): string {
403
+ return value.trim().slice(0, 4_096);
404
+ }
405
+
406
+ async function validateSnapshotWithCli(
407
+ adapter: DiscoveredBundledAdapter,
408
+ stagedPath: string,
409
+ environment: Readonly<Record<string, string | undefined>>,
410
+ ghostgetMain: GhostgetMain,
411
+ registry: ProviderPluginRegistry,
412
+ ): Promise<void> {
413
+ const captured = captureOutput();
414
+ const status = await ghostgetMain(
415
+ ["adapter", "validate", stagedPath, "--json"],
416
+ environment,
417
+ captured.output,
418
+ { providerPluginRegistry: registry },
419
+ );
420
+ if (status !== 0) {
421
+ const detail = compactDetail(captured.stderr() || captured.stdout());
422
+ throw new Error(
423
+ `bundled ${adapter.id} adapter failed validation${detail === "" ? "" : `: ${detail}`}`,
424
+ );
425
+ }
426
+ let response: unknown;
427
+ try {
428
+ response = JSON.parse(captured.stdout()) as unknown;
429
+ } catch {
430
+ throw new Error(`bundled ${adapter.id} adapter validation returned malformed JSON`);
431
+ }
432
+ if (
433
+ typeof response !== "object"
434
+ || response === null
435
+ || !("ok" in response)
436
+ || response.ok !== true
437
+ || !("id" in response)
438
+ || response.id !== adapter.id
439
+ || !("manifestHash" in response)
440
+ || response.manifestHash !== manifestHash(adapter.current.manifest)
441
+ ) {
442
+ throw new Error(
443
+ `bundled ${adapter.id} adapter validation returned the wrong identity`,
444
+ );
445
+ }
446
+ }
447
+
448
+ function publishBundledAdapterGeneration(
449
+ bundledAdapters: readonly DiscoveredBundledAdapter[],
450
+ environment: Readonly<Record<string, string | undefined>>,
451
+ output: SyncOutput,
452
+ registry: ProviderPluginRegistry,
453
+ installGeneration?: GenerationInstaller,
454
+ ): {
455
+ readonly installed: number;
456
+ readonly preserved: number;
457
+ readonly commitId: string;
458
+ } {
459
+ const portableAdapterIds = new Set(
460
+ registry.listOwnedManifests().map((manifest) =>
461
+ manifest.id
462
+ ),
463
+ );
464
+ const collision = bundledAdapters.find((adapter) =>
465
+ portableAdapterIds.has(adapter.id)
466
+ );
467
+ if (collision !== undefined) {
468
+ throw new Error(
469
+ `bundled adapter ${collision.id} is owned by an enabled portable provider plugin`,
470
+ );
471
+ }
472
+
473
+ const selections: BundledAdapterGenerationSelection[] = [];
474
+ const preservedIds: string[] = [];
475
+ const repairedIds: string[] = [];
476
+ let installed = 0;
477
+ const installedSnapshots = new Map(
478
+ listInstalledDiagnosticManifestSnapshots(environment, registry).map((entry) =>
479
+ [entry.id, entry.snapshot] as const
480
+ ),
481
+ );
482
+ for (const adapter of bundledAdapters) {
483
+ const snapshot = installedSnapshots.get(adapter.id) ?? {
484
+ result: {
485
+ ok: false as const,
486
+ issues: [`adapter ${adapter.id} is not installed`],
487
+ },
488
+ availability: "absent" as const,
489
+ contentSha256: null,
490
+ };
491
+ if (snapshot.availability === "unsafe") {
492
+ const detail = snapshot.result.ok
493
+ ? "unsafe installed-state snapshot"
494
+ : snapshot.result.issues.join("; ");
495
+ throw new Error(
496
+ `installed adapter ${adapter.id} cannot be snapshotted safely: ${detail}`,
497
+ );
498
+ }
499
+ if (snapshot.availability === "absent") {
500
+ selections.push({
501
+ id: adapter.id,
502
+ state: "present",
503
+ manifest: adapter.current.manifest,
504
+ sourceContentSha256: adapter.current.sourceContentSha256,
505
+ expectedCurrentContentSha256: null,
506
+ });
507
+ installed += 1;
508
+ continue;
509
+ }
510
+ if (!snapshot.result.ok) {
511
+ selections.push({
512
+ id: adapter.id,
513
+ state: "legacy",
514
+ expectedCurrentContentSha256: snapshot.contentSha256,
515
+ });
516
+ preservedIds.push(adapter.id);
517
+ continue;
518
+ }
519
+ const installedManifest = snapshot.result.value;
520
+ const installedHash = manifestHash(installedManifest);
521
+ const acceptedHashes = new Set([
522
+ manifestHash(adapter.current.manifest),
523
+ ...adapter.upgradeFrom.map((baseline) =>
524
+ manifestHash(baseline.manifest)
525
+ ),
526
+ ]);
527
+ const installedOlderGeneration = adapter.upgradeFrom.some((baseline) =>
528
+ baseline.manifest.version === installedManifest.version
529
+ );
530
+ if (acceptedHashes.has(installedHash) || installedOlderGeneration) {
531
+ selections.push({
532
+ id: adapter.id,
533
+ state: "present",
534
+ manifest: adapter.current.manifest,
535
+ sourceContentSha256: adapter.current.sourceContentSha256,
536
+ expectedCurrentContentSha256: snapshot.contentSha256,
537
+ });
538
+ installed += 1;
539
+ continue;
540
+ }
541
+ const runtime = parseRuntimeManifest(installedManifest, registry);
542
+ if (!runtime.ok) {
543
+ selections.push({
544
+ id: adapter.id,
545
+ state: "present",
546
+ manifest: adapter.current.manifest,
547
+ sourceContentSha256: adapter.current.sourceContentSha256,
548
+ expectedCurrentContentSha256: snapshot.contentSha256,
549
+ });
550
+ repairedIds.push(adapter.id);
551
+ installed += 1;
552
+ continue;
553
+ }
554
+ if (snapshot.contentSha256 === null) {
555
+ throw new Error(`installed adapter ${adapter.id} omitted its content hash`);
556
+ }
557
+ selections.push({
558
+ id: adapter.id,
559
+ state: "present",
560
+ manifest: installedManifest,
561
+ sourceContentSha256: snapshot.contentSha256,
562
+ expectedCurrentContentSha256: snapshot.contentSha256,
563
+ });
564
+ preservedIds.push(adapter.id);
565
+ }
566
+ const generation = (
567
+ installGeneration
568
+ ?? ((value, targetEnvironment) =>
569
+ installBundledAdapterGeneration(
570
+ value,
571
+ targetEnvironment,
572
+ { registry },
573
+ ))
574
+ )(selections, environment);
575
+ for (const adapter of bundledAdapters) {
576
+ if (preservedIds.includes(adapter.id)) continue;
577
+ output.stdout(
578
+ `Installed ${adapter.id} at ${adapterManifestPath(adapter.id, environment)}.\n`,
579
+ );
580
+ }
581
+ for (const id of preservedIds) {
582
+ output.stderr(
583
+ `ghostget installer: preserved the installed ${id} adapter because it differs from the bundled version; inspect it or replace it with ghostget adapter install of this release's bundled manifest and --force\n`,
584
+ );
585
+ }
586
+ for (const id of repairedIds) {
587
+ output.stderr(
588
+ `ghostget installer: repaired the incompatible installed ${id} adapter with this Ghostget release's bundled contract; reinstall a newer Ghostget release to restore newer contracts\n`,
589
+ );
590
+ }
591
+ return Object.freeze({
592
+ installed,
593
+ preserved: preservedIds.length,
594
+ commitId: generation.commitId,
595
+ });
596
+ }
597
+
598
+ export async function syncBundledAdapters(
599
+ options: {
600
+ readonly environment?: Readonly<Record<string, string | undefined>>;
601
+ readonly output?: SyncOutput;
602
+ readonly ghostgetMain?: GhostgetMain;
603
+ readonly installGeneration?: GenerationInstaller;
604
+ readonly assetsDirectory?: string;
605
+ readonly registry?: ProviderPluginRegistry;
606
+ } = {},
607
+ ): Promise<{
608
+ readonly installed: number;
609
+ readonly preserved: number;
610
+ readonly commitId: string;
611
+ }> {
612
+ const environment = options.environment ?? process.env;
613
+ const output = options.output ?? defaultOutput;
614
+ const ghostgetMain = options.ghostgetMain ?? defaultGhostgetMain;
615
+ const registry = options.registry ?? providerPluginRegistry;
616
+ const bundledAdapters = discoverBundledAdapters(
617
+ options.assetsDirectory ?? defaultAssetsDirectory,
618
+ registry,
619
+ );
620
+
621
+ const stagingDirectory = mkdtempSync(
622
+ join(tmpdir(), "wrench-bundled-adapters-"),
623
+ );
624
+ chmodSync(stagingDirectory, 0o700);
625
+ try {
626
+ for (const [index, adapter] of bundledAdapters.entries()) {
627
+ const stagedPath = join(
628
+ stagingDirectory,
629
+ `${String(index).padStart(4, "0")}-${basename(adapter.current.path)}`,
630
+ );
631
+ writeFileSync(stagedPath, adapter.current.bytes, {
632
+ flag: "wx",
633
+ mode: 0o600,
634
+ });
635
+ }
636
+ const storeRoot = portableProviderPluginStoreRoot(environment);
637
+ const initialCatalog = withPortableProviderPluginCatalogLock(
638
+ storeRoot,
639
+ new Date(),
640
+ () => createPortableProviderPluginCatalog(registry, environment),
641
+ );
642
+ const initialCatalogFingerprint =
643
+ portableCatalogFingerprint(initialCatalog);
644
+ for (const [index, adapter] of bundledAdapters.entries()) {
645
+ const stagedPath = join(
646
+ stagingDirectory,
647
+ `${String(index).padStart(4, "0")}-${basename(adapter.current.path)}`,
648
+ );
649
+ await validateSnapshotWithCli(
650
+ adapter,
651
+ stagedPath,
652
+ environment,
653
+ ghostgetMain,
654
+ initialCatalog.registry,
655
+ );
656
+ }
657
+
658
+ return withPortableProviderPluginCatalogLock(
659
+ storeRoot,
660
+ new Date(),
661
+ () => {
662
+ const currentCatalog =
663
+ createPortableProviderPluginCatalog(registry, environment);
664
+ if (
665
+ portableCatalogFingerprint(currentCatalog)
666
+ !== initialCatalogFingerprint
667
+ ) {
668
+ throw new Error(
669
+ "portable provider plugin catalog changed during bundled adapter validation; retry installation",
670
+ );
671
+ }
672
+ return publishBundledAdapterGeneration(
673
+ bundledAdapters,
674
+ environment,
675
+ output,
676
+ currentCatalog.registry,
677
+ options.installGeneration,
678
+ );
679
+ },
680
+ );
681
+ } finally {
682
+ rmSync(stagingDirectory, { recursive: true, force: true });
683
+ }
684
+ }
685
+
686
+ if (import.meta.main) {
687
+ try {
688
+ await syncBundledAdapters();
689
+ } catch (error) {
690
+ process.stderr.write(
691
+ `ghostget installer: ${error instanceof Error ? error.message : "unknown bundled adapter sync failure"}\n`,
692
+ );
693
+ process.exitCode = 1;
694
+ }
695
+ }