@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,470 @@
1
+ import {
2
+ chmodSync,
3
+ lstatSync,
4
+ mkdtempSync,
5
+ realpathSync,
6
+ rmdirSync,
7
+ type BigIntStats,
8
+ } from "node:fs";
9
+ import { tmpdir } from "node:os";
10
+ import { basename, dirname, isAbsolute, join, resolve } from "node:path";
11
+ import { types as nodeTypes } from "node:util";
12
+
13
+ import type { BrowserCleanupResourceIdentity } from "./browser";
14
+ import {
15
+ captureProcessOwnerIdentity,
16
+ processOwnerStatus,
17
+ type ProcessOwnerIdentity,
18
+ type ProcessOwnerStatus,
19
+ } from "./process-identity";
20
+
21
+ type JsonRecord = Record<string, unknown>;
22
+
23
+ const decimalPattern = /^(?:0|[1-9][0-9]{0,39})$/u;
24
+ const privateRootNamePattern = /^wrench-[a-z0-9][a-z0-9._-]{0,126}$/u;
25
+
26
+ function hasWellFormedUnicode(value: string): boolean {
27
+ for (let index = 0; index < value.length; index += 1) {
28
+ const code = value.charCodeAt(index);
29
+ if (code >= 0xd800 && code <= 0xdbff) {
30
+ if (index + 1 >= value.length) return false;
31
+ const next = value.charCodeAt(index + 1);
32
+ if (next < 0xdc00 || next > 0xdfff) return false;
33
+ index += 1;
34
+ } else if (code >= 0xdc00 && code <= 0xdfff) return false;
35
+ }
36
+ return true;
37
+ }
38
+
39
+ export type LocalCliPrivateRootIdentityV1 = {
40
+ /** Private durable state: never include this path in receipts or diagnostics. */
41
+ readonly path: string;
42
+ readonly device: string;
43
+ readonly inode: string;
44
+ readonly birthtimeNs: string;
45
+ /** Decimal POSIX mode. V1 admits only 0700 (`448`). */
46
+ readonly mode: "448";
47
+ /** Decimal owner UID captured with the directory identity. */
48
+ readonly uid: string;
49
+ };
50
+
51
+ export type LocalCliProcessGroupIdentityV1 = {
52
+ readonly kind: "posix-process-group-v1";
53
+ readonly platform: "darwin" | "linux";
54
+ readonly processGroupId: number;
55
+ readonly leader: ProcessOwnerIdentity;
56
+ };
57
+
58
+ /**
59
+ * Exact identity of a local-CLI operation root and, once spawned, its detached
60
+ * process group. A runtime publishes the root before placing credentials or an
61
+ * executable inside it, then may monotonically attach the process group.
62
+ */
63
+ export type LocalCliCleanupResourceIdentityV1 = {
64
+ readonly kind: "local-cli-private-root-v1";
65
+ readonly root: LocalCliPrivateRootIdentityV1;
66
+ /** Monotonic launch history; append immediately after every detached spawn. */
67
+ readonly processGroups?: readonly LocalCliProcessGroupIdentityV1[];
68
+ };
69
+
70
+ export type ProviderPluginCleanupResourceIdentity =
71
+ | BrowserCleanupResourceIdentity
72
+ | LocalCliCleanupResourceIdentityV1;
73
+
74
+ export type LocalCliCleanupFilesystemReadinessV1 =
75
+ | { readonly ready: true; readonly reason: null }
76
+ | { readonly ready: false; readonly reason: string };
77
+
78
+ const unsupportedCleanupFilesystemReason =
79
+ "the temporary filesystem does not expose an immutable local CLI cleanup directory identity";
80
+
81
+ function recoverablePrivateRootStats(
82
+ stats: BigIntStats,
83
+ currentUid: number | undefined,
84
+ ): boolean {
85
+ return stats.isDirectory()
86
+ && !stats.isSymbolicLink()
87
+ && currentUid !== undefined
88
+ && stats.uid === BigInt(currentUid)
89
+ && (stats.mode & 0o777n) === 0o700n
90
+ && stats.birthtimeNs > 0n;
91
+ }
92
+
93
+ /**
94
+ * Probes the same temporary filesystem used for operation-private roots.
95
+ * Filesystems without a nonzero immutable birth time are categorically
96
+ * unsupported: device/inode plus mutable ctime cannot safely identify a
97
+ * generation after a crash.
98
+ */
99
+ export function inspectLocalCliCleanupFilesystemReadiness(): LocalCliCleanupFilesystemReadinessV1 {
100
+ let probePath: string | undefined;
101
+ try {
102
+ probePath = mkdtempSync(join(
103
+ realpathSync(tmpdir()),
104
+ "wrench-local-cli-readiness-",
105
+ ));
106
+ chmodSync(probePath, 0o700);
107
+ const supported = recoverablePrivateRootStats(
108
+ lstatSync(probePath, { bigint: true }),
109
+ process.getuid?.(),
110
+ );
111
+ rmdirSync(probePath);
112
+ probePath = undefined;
113
+ return supported
114
+ ? Object.freeze({ ready: true, reason: null })
115
+ : Object.freeze({
116
+ ready: false,
117
+ reason: unsupportedCleanupFilesystemReason,
118
+ });
119
+ } catch {
120
+ return Object.freeze({
121
+ ready: false,
122
+ reason: unsupportedCleanupFilesystemReason,
123
+ });
124
+ } finally {
125
+ if (probePath !== undefined) {
126
+ try {
127
+ rmdirSync(probePath);
128
+ } catch {
129
+ // A failed empty-directory cleanup keeps readiness false. The random,
130
+ // credential-free probe contains no provider data.
131
+ }
132
+ }
133
+ }
134
+ }
135
+
136
+ function record(value: unknown, label: string): JsonRecord {
137
+ if (
138
+ typeof value !== "object"
139
+ || value === null
140
+ || Array.isArray(value)
141
+ || nodeTypes.isProxy(value)
142
+ ) {
143
+ throw new Error(`${label} must be a plain data object`);
144
+ }
145
+ const prototype: unknown = Object.getPrototypeOf(value) as unknown;
146
+ if (prototype !== Object.prototype && prototype !== null) {
147
+ throw new Error(`${label} must be a plain data object`);
148
+ }
149
+ const descriptors = Object.getOwnPropertyDescriptors(value);
150
+ const result: JsonRecord = {};
151
+ for (const key of Reflect.ownKeys(descriptors)) {
152
+ if (typeof key !== "string") {
153
+ throw new Error(`${label} has unsupported symbol fields`);
154
+ }
155
+ const descriptor = descriptors[key];
156
+ if (
157
+ descriptor === undefined
158
+ || !descriptor.enumerable
159
+ || !("value" in descriptor)
160
+ || !hasWellFormedUnicode(key)
161
+ || /[\u0000-\u001f\u007f-\u009f]/u.test(key)
162
+ ) {
163
+ throw new Error(`${label} has unsupported accessor fields`);
164
+ }
165
+ result[key] = descriptor.value as unknown;
166
+ }
167
+ return result;
168
+ }
169
+
170
+ function exactKeys(
171
+ value: JsonRecord,
172
+ required: readonly string[],
173
+ optional: readonly string[],
174
+ label: string,
175
+ ): void {
176
+ const allowed = new Set([...required, ...optional]);
177
+ if (
178
+ required.some((key) => !Object.hasOwn(value, key))
179
+ || Object.keys(value).some((key) => !allowed.has(key))
180
+ ) {
181
+ throw new Error(`${label} has unsupported fields`);
182
+ }
183
+ }
184
+
185
+ function decimal(value: unknown, label: string): string {
186
+ if (typeof value !== "string" || !decimalPattern.test(value)) {
187
+ throw new Error(`${label} is malformed`);
188
+ }
189
+ return value;
190
+ }
191
+
192
+ function pid(value: unknown, label: string): number {
193
+ if (
194
+ typeof value !== "number"
195
+ || !Number.isSafeInteger(value)
196
+ || value < 1
197
+ ) {
198
+ throw new Error(`${label} is malformed`);
199
+ }
200
+ return value;
201
+ }
202
+
203
+ function digest(value: unknown, label: string): string {
204
+ if (typeof value !== "string" || !/^[a-f0-9]{64}$/u.test(value)) {
205
+ throw new Error(`${label} is malformed`);
206
+ }
207
+ return value;
208
+ }
209
+
210
+ function parseProcessOwner(value: unknown): ProcessOwnerIdentity {
211
+ const owner = record(value, "local CLI cleanup process owner");
212
+ exactKeys(
213
+ owner,
214
+ ["pid", "bootId", "processStartId"],
215
+ [],
216
+ "local CLI cleanup process owner",
217
+ );
218
+ return Object.freeze({
219
+ pid: pid(owner.pid, "local CLI cleanup process owner PID"),
220
+ bootId: digest(owner.bootId, "local CLI cleanup process boot identity"),
221
+ processStartId: digest(
222
+ owner.processStartId,
223
+ "local CLI cleanup process start identity",
224
+ ),
225
+ });
226
+ }
227
+
228
+ function temporaryRootPath(value: unknown): string {
229
+ if (
230
+ typeof value !== "string"
231
+ || value.length < 1
232
+ || value.length > 4_096
233
+ || !isAbsolute(value)
234
+ || resolve(value) !== value
235
+ || dirname(value) !== realpathSync(tmpdir())
236
+ || !privateRootNamePattern.test(basename(value))
237
+ ) {
238
+ throw new Error("local CLI cleanup private root path is malformed");
239
+ }
240
+ return value;
241
+ }
242
+
243
+ function parsePrivateRoot(value: unknown): LocalCliPrivateRootIdentityV1 {
244
+ const root = record(value, "local CLI cleanup private root");
245
+ exactKeys(
246
+ root,
247
+ ["path", "device", "inode", "birthtimeNs", "mode", "uid"],
248
+ [],
249
+ "local CLI cleanup private root",
250
+ );
251
+ const mode = decimal(root.mode, "local CLI cleanup private root mode");
252
+ if (mode !== "448") {
253
+ throw new Error("local CLI cleanup private root must have mode 0700");
254
+ }
255
+ const birthtimeNs = decimal(
256
+ root.birthtimeNs,
257
+ "local CLI cleanup private root birth time",
258
+ );
259
+ if (birthtimeNs === "0") {
260
+ throw new Error("local CLI cleanup private root birth time is malformed");
261
+ }
262
+ return Object.freeze({
263
+ path: temporaryRootPath(root.path),
264
+ device: decimal(root.device, "local CLI cleanup private root device"),
265
+ inode: decimal(root.inode, "local CLI cleanup private root inode"),
266
+ birthtimeNs,
267
+ mode: "448",
268
+ uid: decimal(root.uid, "local CLI cleanup private root owner"),
269
+ });
270
+ }
271
+
272
+ function parseProcessGroup(value: unknown): LocalCliProcessGroupIdentityV1 {
273
+ const group = record(value, "local CLI cleanup process group");
274
+ exactKeys(
275
+ group,
276
+ ["kind", "platform", "processGroupId", "leader"],
277
+ [],
278
+ "local CLI cleanup process group",
279
+ );
280
+ if (
281
+ group.kind !== "posix-process-group-v1"
282
+ || (group.platform !== "darwin" && group.platform !== "linux")
283
+ ) {
284
+ throw new Error("local CLI cleanup process group is malformed");
285
+ }
286
+ const processGroupId = pid(
287
+ group.processGroupId,
288
+ "local CLI cleanup process group ID",
289
+ );
290
+ const leader = parseProcessOwner(group.leader);
291
+ if (leader.pid !== processGroupId) {
292
+ throw new Error("local CLI cleanup process group does not match its leader");
293
+ }
294
+ return Object.freeze({
295
+ kind: "posix-process-group-v1",
296
+ platform: group.platform,
297
+ processGroupId,
298
+ leader,
299
+ });
300
+ }
301
+
302
+ export function parseLocalCliCleanupResourceIdentityV1(
303
+ value: unknown,
304
+ ): LocalCliCleanupResourceIdentityV1 {
305
+ const resource = record(value, "local CLI cleanup resource identity");
306
+ exactKeys(
307
+ resource,
308
+ ["kind", "root"],
309
+ ["processGroups"],
310
+ "local CLI cleanup resource identity",
311
+ );
312
+ if (resource.kind !== "local-cli-private-root-v1") {
313
+ throw new Error("local CLI cleanup resource identity kind is unsupported");
314
+ }
315
+ const root = parsePrivateRoot(resource.root);
316
+ let processGroups: readonly LocalCliProcessGroupIdentityV1[] | undefined;
317
+ if (resource.processGroups !== undefined) {
318
+ const rawGroups = resource.processGroups;
319
+ if (
320
+ !Array.isArray(rawGroups)
321
+ || nodeTypes.isProxy(rawGroups)
322
+ || Object.getPrototypeOf(rawGroups) !== Array.prototype
323
+ || rawGroups.length < 1
324
+ || rawGroups.length > 64
325
+ ) {
326
+ throw new Error("local CLI cleanup process group history is malformed");
327
+ }
328
+ const descriptors = Object.getOwnPropertyDescriptors(rawGroups);
329
+ if (
330
+ Reflect.ownKeys(descriptors).some((key) => typeof key !== "string")
331
+ || Object.keys(descriptors).length !== rawGroups.length + 1
332
+ || !Object.entries(descriptors).every(([key, descriptor]) =>
333
+ key === "length"
334
+ ? !descriptor.enumerable
335
+ && "value" in descriptor
336
+ && descriptor.value === rawGroups.length
337
+ : descriptor.enumerable && "value" in descriptor)
338
+ ) {
339
+ throw new Error("local CLI cleanup process group history is malformed");
340
+ }
341
+ processGroups = Object.freeze(Array.from(
342
+ { length: rawGroups.length },
343
+ (_unused, index) => {
344
+ const descriptor = descriptors[String(index)];
345
+ if (descriptor === undefined || !("value" in descriptor)) {
346
+ throw new Error("local CLI cleanup process group history is sparse");
347
+ }
348
+ return parseProcessGroup(descriptor.value);
349
+ },
350
+ ));
351
+ }
352
+ return Object.freeze({
353
+ kind: "local-cli-private-root-v1",
354
+ root,
355
+ ...(processGroups === undefined ? {} : { processGroups }),
356
+ });
357
+ }
358
+
359
+ export function captureLocalCliCleanupResource(
360
+ path: string,
361
+ ): LocalCliCleanupResourceIdentityV1 {
362
+ const canonical = realpathSync(path);
363
+ const checkedPath = temporaryRootPath(canonical);
364
+ const stats = lstatSync(checkedPath, { bigint: true });
365
+ const currentUid = process.getuid?.();
366
+ if (!recoverablePrivateRootStats(stats, currentUid)) {
367
+ throw new Error(
368
+ "local CLI cleanup resource must be one owned mode-0700 temporary directory",
369
+ );
370
+ }
371
+ return parseLocalCliCleanupResourceIdentityV1({
372
+ kind: "local-cli-private-root-v1",
373
+ root: {
374
+ path: checkedPath,
375
+ device: stats.dev.toString(),
376
+ inode: stats.ino.toString(),
377
+ birthtimeNs: stats.birthtimeNs.toString(),
378
+ mode: "448",
379
+ uid: stats.uid.toString(),
380
+ },
381
+ });
382
+ }
383
+
384
+ function processGroupIsPresent(processGroupId: number): boolean | null {
385
+ try {
386
+ process.kill(-processGroupId, 0);
387
+ return true;
388
+ } catch (error) {
389
+ if (typeof error !== "object" || error === null || !("code" in error)) {
390
+ return null;
391
+ }
392
+ if (error.code === "ESRCH") return false;
393
+ if (error.code === "EPERM") return true;
394
+ return null;
395
+ }
396
+ }
397
+
398
+ export function attachLocalCliCleanupProcessGroup(
399
+ value: LocalCliCleanupResourceIdentityV1,
400
+ childPid: number,
401
+ ): LocalCliCleanupResourceIdentityV1 {
402
+ const resource = parseLocalCliCleanupResourceIdentityV1(value);
403
+ if ((resource.processGroups?.length ?? 0) >= 64) {
404
+ throw new Error("local CLI cleanup process group history exceeded its bound");
405
+ }
406
+ if (process.platform !== "darwin" && process.platform !== "linux") {
407
+ throw new Error("local CLI cleanup process groups require a POSIX runtime");
408
+ }
409
+ const leader = captureProcessOwnerIdentity(childPid);
410
+ if (processGroupIsPresent(childPid) !== true) {
411
+ throw new Error("local CLI cleanup child does not own a live process group");
412
+ }
413
+ return parseLocalCliCleanupResourceIdentityV1({
414
+ ...resource,
415
+ processGroups: [
416
+ ...(resource.processGroups ?? []),
417
+ {
418
+ kind: "posix-process-group-v1",
419
+ platform: process.platform,
420
+ processGroupId: childPid,
421
+ leader,
422
+ },
423
+ ],
424
+ });
425
+ }
426
+
427
+ export function localCliCleanupResourceExtends(
428
+ current: LocalCliCleanupResourceIdentityV1,
429
+ next: LocalCliCleanupResourceIdentityV1,
430
+ ): boolean {
431
+ const left = parseLocalCliCleanupResourceIdentityV1(current);
432
+ const right = parseLocalCliCleanupResourceIdentityV1(next);
433
+ if (JSON.stringify(left.root) !== JSON.stringify(right.root)) return false;
434
+ const leftGroups = left.processGroups ?? [];
435
+ const rightGroups = right.processGroups ?? [];
436
+ return rightGroups.length >= leftGroups.length
437
+ && leftGroups.every((group, index) =>
438
+ JSON.stringify(group) === JSON.stringify(rightGroups[index]));
439
+ }
440
+
441
+ export type LocalCliCleanupProcessGroupStatus =
442
+ | "active"
443
+ | "quiescent"
444
+ | "unknown";
445
+
446
+ export function localCliCleanupProcessGroupStatus(
447
+ resource: LocalCliCleanupResourceIdentityV1,
448
+ inspectOwner: (owner: ProcessOwnerIdentity) => ProcessOwnerStatus =
449
+ processOwnerStatus,
450
+ ): LocalCliCleanupProcessGroupStatus {
451
+ const checked = parseLocalCliCleanupResourceIdentityV1(resource);
452
+ const groups = checked.processGroups;
453
+ if (groups === undefined) {
454
+ return "unknown";
455
+ }
456
+ let unknown = false;
457
+ for (const group of groups) {
458
+ if (group.platform !== process.platform) return "unknown";
459
+ const leader = inspectOwner(group.leader);
460
+ if (leader === "exact-live-owner") return "active";
461
+ if (leader === "unknown") {
462
+ unknown = true;
463
+ continue;
464
+ }
465
+ const present = processGroupIsPresent(group.processGroupId);
466
+ if (present === true) return "active";
467
+ if (present === null) unknown = true;
468
+ }
469
+ return unknown ? "unknown" : "quiescent";
470
+ }