@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,501 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { createHash } from "node:crypto";
3
+ import { readFileSync } from "node:fs";
4
+ import { dlopen, ptr } from "bun:ffi";
5
+
6
+ export type ProcessStartIdentity = {
7
+ readonly bootId: string;
8
+ readonly processStartId: string;
9
+ };
10
+
11
+ export type ProcessOwnerIdentity = ProcessStartIdentity & {
12
+ readonly pid: number;
13
+ };
14
+
15
+ export type ProcessOwnerStatus =
16
+ | "exact-live-owner"
17
+ | "different-or-dead"
18
+ | "unknown";
19
+
20
+ type ProcessInspection =
21
+ | { readonly status: "alive"; readonly processStartId: string }
22
+ | { readonly status: "dead" | "missing" | "unknown" };
23
+
24
+ type ProcessRecordInspection =
25
+ | { readonly status: "alive"; readonly rawStartId: string }
26
+ | { readonly status: "dead" | "unknown" };
27
+
28
+ type DarwinProcessIdentityRecordReader = (
29
+ pid: number,
30
+ ) => Uint8Array | null;
31
+
32
+ let cachedBootId: string | null = null;
33
+ let cachedCurrentProcessStartIdentity: {
34
+ readonly pid: number;
35
+ readonly bootId: string;
36
+ readonly processStartId: string;
37
+ } | null = null;
38
+ let cachedDarwinProcPidInfo:
39
+ | ((pid: number, flavor: number, buffer: Uint8Array) => number)
40
+ | undefined;
41
+
42
+ const DARWIN_PROCESS_STATE_PATTERN = /^[DIRSTUZ][+<>AELNSsVWX]*$/u;
43
+ const DARWIN_PROC_PID_T_BSDINFO_WITH_UNIQID = 18;
44
+ const DARWIN_PROC_BSDINFO_SIZE = 136;
45
+ const DARWIN_PROC_UNIQIDENTIFIERINFO_SIZE = 56;
46
+ const DARWIN_PROC_BSDINFO_WITH_UNIQID_SIZE =
47
+ DARWIN_PROC_BSDINFO_SIZE + DARWIN_PROC_UNIQIDENTIFIERINFO_SIZE;
48
+ const DARWIN_PROC_BSDINFO_FLAGS_OFFSET = 0;
49
+ const DARWIN_PROC_BSDINFO_STATUS_OFFSET = 4;
50
+ const DARWIN_PROC_BSDINFO_PID_OFFSET = 12;
51
+ const DARWIN_PROC_BSDINFO_START_SECONDS_OFFSET = 120;
52
+ const DARWIN_PROC_BSDINFO_START_MICROSECONDS_OFFSET = 128;
53
+ const DARWIN_PROC_UNIQUE_ID_OFFSET = 16;
54
+ const DARWIN_PROC_ID_VERSION_OFFSET = 32;
55
+ const DARWIN_PROC_FLAG_INEXIT = 0x4;
56
+ const DARWIN_PROCESS_STATUS_IDLE = 1;
57
+ const DARWIN_PROCESS_STATUS_RUNNING = 2;
58
+ const DARWIN_PROCESS_STATUS_SLEEPING = 3;
59
+ const DARWIN_PROCESS_STATUS_STOPPED = 4;
60
+ const DARWIN_PROCESS_STATUS_ZOMBIE = 5;
61
+ const DARWIN_PROCESS_INSPECTION_ATTEMPTS = 3;
62
+ const UUID_PATTERN =
63
+ /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/iu;
64
+
65
+ function identityDigest(kind: string, value: string): string {
66
+ return createHash("sha256")
67
+ .update(kind, "utf8")
68
+ .update("\0", "utf8")
69
+ .update(value, "utf8")
70
+ .digest("hex");
71
+ }
72
+
73
+ function commandText(command: string, arguments_: readonly string[]): string {
74
+ const environment: NodeJS.ProcessEnv = process.platform === "win32"
75
+ ? {
76
+ NODE_ENV: "production",
77
+ SystemRoot: "C:\\Windows",
78
+ WINDIR: "C:\\Windows",
79
+ PATH: "C:\\Windows\\System32",
80
+ }
81
+ : { LANG: "C", LC_ALL: "C", NODE_ENV: "production", TZ: "UTC" };
82
+ return execFileSync(command, arguments_, {
83
+ encoding: "utf8",
84
+ env: environment,
85
+ timeout: 2_000,
86
+ windowsHide: true,
87
+ }).trim();
88
+ }
89
+
90
+ function windowsPowerShellPath(): string {
91
+ return "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe";
92
+ }
93
+
94
+ function normalizeDarwinBootSessionUuid(raw: string): string {
95
+ const value = raw.trim();
96
+ if (!UUID_PATTERN.test(value)) {
97
+ throw new Error("system boot identity is malformed");
98
+ }
99
+ return value.toLowerCase();
100
+ }
101
+
102
+ function darwinBootId(raw: string): string {
103
+ return identityDigest("io-boot", normalizeDarwinBootSessionUuid(raw));
104
+ }
105
+
106
+ function currentBootId(): string {
107
+ if (cachedBootId !== null) return cachedBootId;
108
+ let raw: string;
109
+ if (process.platform === "linux") {
110
+ raw = readFileSync("/proc/sys/kernel/random/boot_id", "utf8").trim();
111
+ if (!/^[a-f0-9-]{36}$/iu.test(raw)) {
112
+ throw new Error("system boot identity is malformed");
113
+ }
114
+ } else if (process.platform === "darwin") {
115
+ cachedBootId = darwinBootId(
116
+ commandText(
117
+ "/usr/sbin/sysctl",
118
+ ["-n", "kern.bootsessionuuid"],
119
+ ),
120
+ );
121
+ return cachedBootId;
122
+ } else if (process.platform === "win32") {
123
+ raw = commandText(windowsPowerShellPath(), [
124
+ "-NoProfile",
125
+ "-NonInteractive",
126
+ "-Command",
127
+ "(Get-CimInstance Win32_OperatingSystem).LastBootUpTime.ToUniversalTime().Ticks",
128
+ ]);
129
+ if (!/^\d{10,30}$/u.test(raw)) {
130
+ throw new Error("system boot identity is malformed");
131
+ }
132
+ } else {
133
+ throw new Error(`system boot identity is unsupported on ${process.platform}`);
134
+ }
135
+ cachedBootId = identityDigest("io-boot", raw);
136
+ return cachedBootId;
137
+ }
138
+
139
+ function processIsDefinitelyMissing(pid: number): boolean {
140
+ try {
141
+ process.kill(pid, 0);
142
+ return false;
143
+ } catch (error) {
144
+ return (
145
+ typeof error === "object"
146
+ && error !== null
147
+ && "code" in error
148
+ && error.code === "ESRCH"
149
+ );
150
+ }
151
+ }
152
+
153
+ function inspectLinuxProcessRecord(raw: string): ProcessRecordInspection {
154
+ const close = raw.lastIndexOf(")");
155
+ if (close < 1) return { status: "unknown" };
156
+ const fields = raw.slice(close + 1).trim().split(/\s+/u);
157
+ const state = fields[0];
158
+ if (state === "Z" || state === "X" || state === "x") {
159
+ return { status: "dead" };
160
+ }
161
+ if (
162
+ state !== "R"
163
+ && state !== "S"
164
+ && state !== "D"
165
+ && state !== "T"
166
+ && state !== "t"
167
+ && state !== "W"
168
+ && state !== "K"
169
+ && state !== "P"
170
+ && state !== "I"
171
+ ) {
172
+ return { status: "unknown" };
173
+ }
174
+ const startTicks = fields[19];
175
+ if (startTicks === undefined || !/^\d+$/u.test(startTicks)) {
176
+ return { status: "unknown" };
177
+ }
178
+ return { status: "alive", rawStartId: startTicks };
179
+ }
180
+
181
+ function inspectDarwinProcessInfo(
182
+ raw: Uint8Array,
183
+ expectedPid: number,
184
+ ): ProcessRecordInspection {
185
+ if (raw.byteLength < DARWIN_PROC_BSDINFO_SIZE) {
186
+ return { status: "unknown" };
187
+ }
188
+ const view = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
189
+ const flags = view.getUint32(DARWIN_PROC_BSDINFO_FLAGS_OFFSET, true);
190
+ const status = view.getUint32(DARWIN_PROC_BSDINFO_STATUS_OFFSET, true);
191
+ const pid = view.getUint32(DARWIN_PROC_BSDINFO_PID_OFFSET, true);
192
+ // proc_pidinfo must return the exact requested PID. A mismatch is an
193
+ // untrusted read, not proof that the requested process has a different
194
+ // identity, so callers retain uncertainty and may retry.
195
+ if (pid !== expectedPid) return { status: "unknown" };
196
+ if (
197
+ status === DARWIN_PROCESS_STATUS_ZOMBIE
198
+ || (flags & DARWIN_PROC_FLAG_INEXIT) !== 0
199
+ ) {
200
+ return { status: "dead" };
201
+ }
202
+ if (
203
+ status !== DARWIN_PROCESS_STATUS_IDLE
204
+ && status !== DARWIN_PROCESS_STATUS_RUNNING
205
+ && status !== DARWIN_PROCESS_STATUS_SLEEPING
206
+ && status !== DARWIN_PROCESS_STATUS_STOPPED
207
+ ) {
208
+ return { status: "unknown" };
209
+ }
210
+ const seconds = view.getBigUint64(
211
+ DARWIN_PROC_BSDINFO_START_SECONDS_OFFSET,
212
+ true,
213
+ );
214
+ const microseconds = view.getBigUint64(
215
+ DARWIN_PROC_BSDINFO_START_MICROSECONDS_OFFSET,
216
+ true,
217
+ );
218
+ if (seconds === 0n || microseconds >= 1_000_000n) {
219
+ return { status: "unknown" };
220
+ }
221
+ return {
222
+ status: "alive",
223
+ rawStartId: `${seconds}:${microseconds}`,
224
+ };
225
+ }
226
+
227
+ function darwinUniqueProcessIdentity(raw: Uint8Array): string | null {
228
+ if (raw.byteLength < DARWIN_PROC_UNIQIDENTIFIERINFO_SIZE) return null;
229
+ const view = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
230
+ const uniqueId = view.getBigUint64(DARWIN_PROC_UNIQUE_ID_OFFSET, true);
231
+ const idVersion = view.getUint32(DARWIN_PROC_ID_VERSION_OFFSET, true);
232
+ if (uniqueId === 0n || idVersion === 0) return null;
233
+ return `${uniqueId}:${idVersion}`;
234
+ }
235
+
236
+ function inspectDarwinProcessIdentity(
237
+ raw: Uint8Array,
238
+ expectedPid: number,
239
+ ): ProcessRecordInspection {
240
+ if (raw.byteLength < DARWIN_PROC_BSDINFO_WITH_UNIQID_SIZE) {
241
+ return { status: "unknown" };
242
+ }
243
+ const bsdInfo = raw.subarray(0, DARWIN_PROC_BSDINFO_SIZE);
244
+ const uniqueInfo = raw.subarray(
245
+ DARWIN_PROC_BSDINFO_SIZE,
246
+ DARWIN_PROC_BSDINFO_WITH_UNIQID_SIZE,
247
+ );
248
+ const record = inspectDarwinProcessInfo(bsdInfo, expectedPid);
249
+ if (record.status !== "alive") return record;
250
+ const uniqueIdentity = darwinUniqueProcessIdentity(uniqueInfo);
251
+ if (uniqueIdentity === null) return { status: "unknown" };
252
+ return {
253
+ status: "alive",
254
+ rawStartId: `${uniqueIdentity}:${record.rawStartId}`,
255
+ };
256
+ }
257
+
258
+ function darwinProcPidInfo():
259
+ ((pid: number, flavor: number, buffer: Uint8Array) => number) | null {
260
+ if (cachedDarwinProcPidInfo !== undefined) return cachedDarwinProcPidInfo;
261
+ try {
262
+ const library = dlopen("/usr/lib/libproc.dylib", {
263
+ proc_pidinfo: {
264
+ args: ["int", "int", "u64", "ptr", "int"],
265
+ returns: "int",
266
+ },
267
+ } as const);
268
+ cachedDarwinProcPidInfo = (pid, flavor, buffer) =>
269
+ library.symbols.proc_pidinfo(
270
+ pid,
271
+ flavor,
272
+ 0,
273
+ ptr(buffer),
274
+ buffer.byteLength,
275
+ );
276
+ } catch {
277
+ // A transient loader failure must not disable exact process inspection for
278
+ // the rest of this process. Cache a successfully opened symbol only.
279
+ return null;
280
+ }
281
+ return cachedDarwinProcPidInfo;
282
+ }
283
+
284
+ function darwinProcessIsDefinitelyDead(pid: number): boolean {
285
+ if (processIsDefinitelyMissing(pid)) return true;
286
+ try {
287
+ const state = commandText("/bin/ps", [
288
+ "-o",
289
+ "state=",
290
+ "-p",
291
+ String(pid),
292
+ ]);
293
+ if (
294
+ DARWIN_PROCESS_STATE_PATTERN.test(state)
295
+ && state.startsWith("Z")
296
+ ) {
297
+ return true;
298
+ }
299
+ } catch {
300
+ // A state-only fallback may fail during exit; retain unknown.
301
+ }
302
+ return processIsDefinitelyMissing(pid);
303
+ }
304
+
305
+ function inspectDarwinProcessWithReader(
306
+ pid: number,
307
+ readRecord: DarwinProcessIdentityRecordReader,
308
+ isDefinitelyDead: (pid: number) => boolean,
309
+ ): ProcessRecordInspection {
310
+ for (let attempt = 0; attempt < DARWIN_PROCESS_INSPECTION_ATTEMPTS; attempt += 1) {
311
+ let record: ProcessRecordInspection = { status: "unknown" };
312
+ try {
313
+ const raw = readRecord(pid);
314
+ if (raw !== null) record = inspectDarwinProcessIdentity(raw, pid);
315
+ } catch {
316
+ // A failed kernel read is uncertain and receives the same bounded retry.
317
+ }
318
+ if (
319
+ record.status === "alive"
320
+ || record.status === "dead"
321
+ ) {
322
+ return record;
323
+ }
324
+ if (isDefinitelyDead(pid)) return { status: "dead" };
325
+ }
326
+ return { status: "unknown" };
327
+ }
328
+
329
+ function inspectDarwinProcess(pid: number): ProcessRecordInspection {
330
+ // Darwin flavor 18 returns the public BSD record and the kernel's 64-bit
331
+ // process-unique ID from one proc reference. Short or temporarily unknown
332
+ // reads receive a small bounded retry while the PID remains present. A
333
+ // parsed dead record is terminal and never gets replaced by a later read.
334
+ // Persistent uncertainty stays unknown rather than falling back to a
335
+ // timestamp that can collide after PID reuse.
336
+ return inspectDarwinProcessWithReader(
337
+ pid,
338
+ (targetPid) => {
339
+ const inspect = darwinProcPidInfo();
340
+ if (inspect === null) return null;
341
+ const processInfo = Buffer.alloc(DARWIN_PROC_BSDINFO_WITH_UNIQID_SIZE);
342
+ const bytesRead = inspect(
343
+ targetPid,
344
+ DARWIN_PROC_PID_T_BSDINFO_WITH_UNIQID,
345
+ processInfo,
346
+ );
347
+ if (
348
+ !Number.isSafeInteger(bytesRead)
349
+ || bytesRead < 0
350
+ || bytesRead > DARWIN_PROC_BSDINFO_WITH_UNIQID_SIZE
351
+ ) {
352
+ return null;
353
+ }
354
+ return processInfo.subarray(0, bytesRead);
355
+ },
356
+ darwinProcessIsDefinitelyDead,
357
+ );
358
+ }
359
+
360
+ export function inspectLinuxProcessRecordForTest(
361
+ raw: string,
362
+ ): ProcessRecordInspection {
363
+ return inspectLinuxProcessRecord(raw);
364
+ }
365
+
366
+ export function inspectDarwinProcessInfoForTest(
367
+ raw: Uint8Array,
368
+ expectedPid: number,
369
+ ): ProcessRecordInspection {
370
+ return inspectDarwinProcessInfo(raw, expectedPid);
371
+ }
372
+
373
+ export function inspectDarwinProcessIdentityForTest(
374
+ raw: Uint8Array,
375
+ expectedPid: number,
376
+ ): ProcessRecordInspection {
377
+ return inspectDarwinProcessIdentity(raw, expectedPid);
378
+ }
379
+
380
+ export function darwinBootIdForTest(raw: string): string {
381
+ return darwinBootId(raw);
382
+ }
383
+
384
+ export function normalizeDarwinBootSessionUuidForTest(raw: string): string {
385
+ return normalizeDarwinBootSessionUuid(raw);
386
+ }
387
+
388
+ export function inspectDarwinProcessWithReaderForTest(
389
+ pid: number,
390
+ readRecord: DarwinProcessIdentityRecordReader,
391
+ isDefinitelyDead: (pid: number) => boolean,
392
+ ): ProcessRecordInspection {
393
+ return inspectDarwinProcessWithReader(pid, readRecord, isDefinitelyDead);
394
+ }
395
+
396
+ function inspectProcessStartId(
397
+ pid: number,
398
+ bootId: string,
399
+ ): ProcessInspection {
400
+ if (
401
+ pid === process.pid
402
+ && cachedCurrentProcessStartIdentity?.pid === pid
403
+ && cachedCurrentProcessStartIdentity.bootId === bootId
404
+ ) {
405
+ return {
406
+ status: "alive",
407
+ processStartId: cachedCurrentProcessStartIdentity.processStartId,
408
+ };
409
+ }
410
+ try {
411
+ let raw: string;
412
+ if (process.platform === "linux") {
413
+ const record = inspectLinuxProcessRecord(
414
+ readFileSync(`/proc/${pid}/stat`, "utf8").trim(),
415
+ );
416
+ if (record.status !== "alive") return record;
417
+ raw = record.rawStartId;
418
+ } else if (process.platform === "win32") {
419
+ raw = commandText(windowsPowerShellPath(), [
420
+ "-NoProfile",
421
+ "-NonInteractive",
422
+ "-Command",
423
+ "$p=[int]$args[0]; (Get-Process -Id $p -ErrorAction Stop).StartTime.ToUniversalTime().Ticks",
424
+ String(pid),
425
+ ]);
426
+ if (!/^\d{10,30}$/u.test(raw)) return { status: "unknown" };
427
+ } else if (process.platform === "darwin") {
428
+ const record = inspectDarwinProcess(pid);
429
+ if (record.status !== "alive") return record;
430
+ raw = record.rawStartId;
431
+ } else {
432
+ return { status: "unknown" };
433
+ }
434
+ const processStartId = identityDigest(
435
+ "io-process-start",
436
+ `${bootId}\0${raw}`,
437
+ );
438
+ if (pid === process.pid) {
439
+ cachedCurrentProcessStartIdentity = { pid, bootId, processStartId };
440
+ }
441
+ return { status: "alive", processStartId };
442
+ } catch (error) {
443
+ if (
444
+ processIsDefinitelyMissing(pid)
445
+ || (
446
+ process.platform === "linux"
447
+ && typeof error === "object"
448
+ && error !== null
449
+ && "code" in error
450
+ && error.code === "ENOENT"
451
+ )
452
+ ) {
453
+ return { status: "missing" };
454
+ }
455
+ return { status: "unknown" };
456
+ }
457
+ }
458
+
459
+ export function currentProcessStartIdentity(): ProcessStartIdentity {
460
+ const owner = captureProcessOwnerIdentity(process.pid);
461
+ return Object.freeze({
462
+ bootId: owner.bootId,
463
+ processStartId: owner.processStartId,
464
+ });
465
+ }
466
+
467
+ /**
468
+ * Capture one exact live process identity. Callers use the start identity, not
469
+ * PID alone, so a later PID reuse cannot satisfy containment proof.
470
+ */
471
+ export function captureProcessOwnerIdentity(
472
+ pid: number,
473
+ ): ProcessOwnerIdentity {
474
+ if (!Number.isSafeInteger(pid) || pid < 1) {
475
+ throw new Error("process identity PID is malformed");
476
+ }
477
+ const bootId = currentBootId();
478
+ const inspection = inspectProcessStartId(pid, bootId);
479
+ if (inspection.status !== "alive") {
480
+ throw new Error("exact live process identity is unavailable");
481
+ }
482
+ return Object.freeze({
483
+ pid,
484
+ bootId,
485
+ processStartId: inspection.processStartId,
486
+ });
487
+ }
488
+
489
+ export function processOwnerStatus(
490
+ owner: ProcessOwnerIdentity,
491
+ ): ProcessOwnerStatus {
492
+ const bootId = currentBootId();
493
+ if (bootId !== owner.bootId) return "different-or-dead";
494
+ const inspection = inspectProcessStartId(owner.pid, bootId);
495
+ if (inspection.status !== "alive") {
496
+ return inspection.status === "unknown" ? "unknown" : "different-or-dead";
497
+ }
498
+ return inspection.processStartId === owner.processStartId
499
+ ? "exact-live-owner"
500
+ : "different-or-dead";
501
+ }
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env bun
2
+ import { closeSync, constants, fstatSync, openSync, readSync, rmSync } from "node:fs";
3
+ import { isAbsolute } from "node:path";
4
+
5
+ import { cloneBrowserProfile } from "./browser";
6
+
7
+ const MAX_REQUEST_BYTES = 16 * 1024;
8
+
9
+ type Identity = { readonly device: string; readonly inode: string };
10
+
11
+ function isRecord(value: unknown): value is Record<string, unknown> {
12
+ return typeof value === "object" && value !== null && !Array.isArray(value);
13
+ }
14
+
15
+ function exactKeys(value: Record<string, unknown>, expected: readonly string[]): boolean {
16
+ const actual = Object.keys(value).sort();
17
+ const sorted = [...expected].sort();
18
+ return actual.length === sorted.length && actual.every((key, index) => key === sorted[index]);
19
+ }
20
+
21
+ function parseIdentity(value: unknown): Identity {
22
+ if (
23
+ !isRecord(value)
24
+ || !exactKeys(value, ["device", "inode"])
25
+ || typeof value.device !== "string"
26
+ || !/^\d{1,40}$/u.test(value.device)
27
+ || typeof value.inode !== "string"
28
+ || !/^\d{1,40}$/u.test(value.inode)
29
+ ) throw new Error("expected profile destination identity is invalid");
30
+ return { device: value.device, inode: value.inode };
31
+ }
32
+
33
+ function readBoundedStdin(): string {
34
+ const buffer = Buffer.allocUnsafe(MAX_REQUEST_BYTES + 1);
35
+ let total = 0;
36
+ for (;;) {
37
+ const count = readSync(0, buffer, total, buffer.byteLength - total, null);
38
+ if (count === 0) break;
39
+ total += count;
40
+ if (total > MAX_REQUEST_BYTES) throw new Error("profile clone request exceeds its byte bound");
41
+ }
42
+ return new TextDecoder("utf-8", { fatal: true }).decode(buffer.subarray(0, total));
43
+ }
44
+
45
+ function assertBoundDirectory(expected: Identity): void {
46
+ const descriptor = openSync(
47
+ ".",
48
+ constants.O_RDONLY
49
+ | ("O_NOFOLLOW" in constants ? constants.O_NOFOLLOW : 0)
50
+ | ("O_DIRECTORY" in constants ? constants.O_DIRECTORY : 0),
51
+ );
52
+ try {
53
+ const stats = fstatSync(descriptor, { bigint: true });
54
+ const currentUid = typeof process.getuid === "function" ? BigInt(process.getuid()) : stats.uid;
55
+ if (
56
+ !stats.isDirectory()
57
+ || stats.uid !== currentUid
58
+ || (stats.mode & 0o777n) !== 0o700n
59
+ || stats.dev.toString() !== expected.device
60
+ || stats.ino.toString() !== expected.inode
61
+ ) throw new Error("bound profile destination no longer matches its private identity");
62
+ } finally {
63
+ closeSync(descriptor);
64
+ }
65
+ }
66
+
67
+ function main(): void {
68
+ const value = JSON.parse(readBoundedStdin()) as unknown;
69
+ if (
70
+ !isRecord(value)
71
+ || !exactKeys(value, ["schemaVersion", "requestId", "expectedDirectory", "source"])
72
+ || value.schemaVersion !== 1
73
+ || typeof value.requestId !== "string"
74
+ || !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u.test(value.requestId)
75
+ || typeof value.source !== "string"
76
+ || !isAbsolute(value.source)
77
+ || value.source.length > 4_096
78
+ || value.source.includes("\u0000")
79
+ ) throw new Error("profile clone request is invalid");
80
+ const expected = parseIdentity(value.expectedDirectory);
81
+ assertBoundDirectory(expected);
82
+ try {
83
+ const cloned = cloneBrowserProfile(value.source, ".");
84
+ assertBoundDirectory(expected);
85
+ process.stdout.write(`${JSON.stringify({
86
+ ok: true,
87
+ profile: cloned.profileDirectory === "Default" ? "profile-user-data" : "profile",
88
+ profileDirectory: cloned.profileDirectory ?? null,
89
+ })}\n`);
90
+ } catch (error) {
91
+ rmSync("profile", { recursive: true, force: true });
92
+ rmSync("profile-user-data", { recursive: true, force: true });
93
+ throw error;
94
+ }
95
+ }
96
+
97
+ if (import.meta.main) {
98
+ try {
99
+ main();
100
+ } catch (error) {
101
+ process.stderr.write(`profile clone helper: ${error instanceof Error ? error.message : "unknown failure"}\n`);
102
+ process.exitCode = 1;
103
+ }
104
+ }
@@ -0,0 +1,51 @@
1
+ import type {
2
+ OfficialProviderId,
3
+ } from "./model";
4
+ import { projectProviderContracts } from "./provider-contracts";
5
+ import type { ProviderPluginOperationName } from "./provider-plugin-identifiers";
6
+ import type { ProviderPluginRegistry } from "./provider-plugin-registry";
7
+ import { providerPluginRegistry } from "./provider-plugins";
8
+ import {
9
+ listWebSessionSiteIds,
10
+ projectWebSessionOperations,
11
+ projectWebSessionOrigins,
12
+ } from "./web-session-sites";
13
+
14
+ function providerApiBindings(registry: ProviderPluginRegistry) {
15
+ return registry.list().flatMap((plugin) =>
16
+ plugin.bindings.filter((binding) => binding.transport === "provider-api"));
17
+ }
18
+
19
+ export function listOfficialProviderIds(
20
+ registry: ProviderPluginRegistry,
21
+ ): readonly OfficialProviderId[] {
22
+ return Object.freeze(
23
+ providerApiBindings(registry).map((binding) => binding.surfaceId).sort(),
24
+ );
25
+ }
26
+
27
+ export function projectOfficialProviderOperations(
28
+ registry: ProviderPluginRegistry,
29
+ ): Readonly<
30
+ Partial<Record<OfficialProviderId, readonly ProviderPluginOperationName[]>>
31
+ > {
32
+ return Object.freeze(Object.fromEntries(
33
+ providerApiBindings(registry).map((binding) => [
34
+ binding.surfaceId,
35
+ Object.freeze([
36
+ ...new Set(binding.operations.map((operation) => operation.name)),
37
+ ]),
38
+ ]),
39
+ ));
40
+ }
41
+
42
+ /** Host-only compatibility views for the bundled composition. */
43
+ export const officialProviderIds = listOfficialProviderIds(providerPluginRegistry);
44
+ export const officialProviderOperations =
45
+ projectOfficialProviderOperations(providerPluginRegistry);
46
+ export const providerContracts =
47
+ projectProviderContracts(providerPluginRegistry);
48
+ export const webSessionSiteIds = listWebSessionSiteIds(providerPluginRegistry);
49
+ export const webSessionOrigins = projectWebSessionOrigins(providerPluginRegistry);
50
+ export const webSessionOperations =
51
+ projectWebSessionOperations(providerPluginRegistry);