@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,214 @@
1
+ # Authenticated API safety and state
2
+
3
+ Use this reference before recording signed-in traffic, resolving browser-held secrets, or invoking R2/R3 operations.
4
+
5
+ ## Contents
6
+
7
+ - [Separate authority from mechanism](#separate-authority-from-mechanism)
8
+ - [Bind the authenticated account](#bind-the-authenticated-account)
9
+ - [Use persistent reads without changing their meaning](#use-persistent-reads-without-changing-their-meaning)
10
+ - [Constrain native provider CLIs](#constrain-native-provider-clis)
11
+ - [Keep browser authority narrow](#keep-browser-authority-narrow)
12
+ - [Constrain first-party HTTP](#constrain-first-party-http)
13
+ - [Minimize HAR exposure](#minimize-har-exposure)
14
+ - [Interpret execution states](#interpret-execution-states)
15
+ - [Reconcile uncertainty](#reconcile-uncertainty)
16
+ - [Clean up task-owned state](#clean-up-task-owned-state)
17
+
18
+ ## Separate authority from mechanism
19
+
20
+ Confirm that the user authorized the exact account, target, and remote effect. An exploratory request to inspect a site or derive a client does not authorize a live mutation.
21
+
22
+ The five-minute digest binds the installed adapter, code-owned contract hash, transport, exact input, attachment content, auth-realm fingerprint, risk, and complete dispatch schedule. It proves what will run. It does not decide whether the action is wise, lawful, permitted by provider rules, or authorized.
23
+
24
+ Use disposable or low-stakes fixtures. Keep employment, recruiting, financial, medical, legal, security, and intimate conversations out of pressure tests.
25
+
26
+ Schema-v5 version-1 reviewed-template manifests are inert derivation reservations, not request authority. Keep every operation `capture-required`; validation rejects `reviewed`, and planning or execution must fail before cookie acquisition, token resolution, or network I/O. Use a code-owned contract for executable operations until a future contract version 2 provides a reviewed current-account preflight and response-scope binding.
27
+
28
+ ## Bind the authenticated account
29
+
30
+ Treat every auth ID as one stable provider-account realm. A cookie/profile name is not account proof.
31
+
32
+ After adding a signed-in realm, probe and persist its current stable subject explicitly:
33
+
34
+ ```sh
35
+ ghostget auth bind linkedin-main --site linkedin
36
+ ghostget auth bind x-main --site x
37
+ ```
38
+
39
+ Before a private read or any dispatch:
40
+
41
+ 1. Resolve the current viewer/account through a reviewed first-party identity request.
42
+ 2. Require one stable provider ID.
43
+ 3. Compare it with the realm's expected account binding.
44
+ 4. For actor-bearing requests, require the request actor to equal that binding.
45
+ 5. Require the response actor and requested target/parent bindings to match the plan.
46
+
47
+ Fail before dispatch on a missing, ambiguous, changed, or mismatched identity. Use a new auth ID for a second account. Require an explicit reviewed rebind after a deliberate login change; do not mutate an existing realm silently.
48
+
49
+ Official OAuth auth is a separate realm and must satisfy its own subject/scope binding. Never fall back between browser-session and OAuth auth.
50
+
51
+ ## Use persistent reads without changing their meaning
52
+
53
+ A successful subject-bound R1 invocation publishes one encrypted snapshot of
54
+ its exact validated input and bounded output. Repeat the same invocation with
55
+ `--cache-only` to read it without a browser or provider roundtrip. Omit the flag
56
+ to rerun the reviewed R1 contract and publish a newer validation.
57
+
58
+ Treat the adapter hash, operation, full auth realm, verified subject, validated
59
+ input, transport, and exact executable contract as part of the query identity.
60
+ Do not drop a cursor, change a limit, expand a folder, or substitute an auth ID
61
+ to force a hit. A contract or account change intentionally produces a miss.
62
+
63
+ Cache freshness is an observation, not provider authority. An unchanged
64
+ revalidation advances validation time without fabricating a data revision.
65
+ Failed, partial, or indeterminate reads retain the last good snapshot.
66
+ Revalidation reruns the selected R1 operation; it does not silently
67
+ perform `auth sync`, and it must not introduce acknowledgement or presence
68
+ effects outside that operation's reviewed contract.
69
+
70
+ The separate omni storage class derives a strict shared Conversation, Message,
71
+ or Notification only through a provider-owned, versioned materializer. Its
72
+ account-lifetime identity includes the adapter, provider plugin closure,
73
+ surface, and auth incarnation. Provider pages retain explicit completeness,
74
+ membership, cursor, and tombstone evidence. Absence never means deletion
75
+ without a complete partition or explicit tombstone. Omni v1 has no
76
+ provider-authored write-invalidation tags. Auth-incarnation, materializer, and
77
+ plugin implementation identity changes strand the prior normalized
78
+ coordinates, while exact-query freshness advances only through explicit
79
+ revalidation. A materializer failure records the failed exact data revision and
80
+ retains the last good entities as `retained-after-drift`; it must not weaken
81
+ parsing or mutate the exact snapshot to make drift disappear.
82
+
83
+ Auth replacement and removal rotate a durable local lifetime identity before
84
+ cleanup. Projection and provider-session ciphertext from an earlier lifetime
85
+ must remain unreadable even if identical locator bytes are later recreated.
86
+
87
+ The projection key is bound to an authenticated store-ownership marker. Ghostget
88
+ refuses a missing, malformed, or replacement key while projection ciphertext
89
+ or that marker remains. If the key is irretrievably lost, remove exactly
90
+ `read-projections/`, `omni-read-projections/`, `.projection-encryption-key`, and
91
+ `read-projection-control/store-key.json` beneath `GHOSTGET_STATE_HOME`, retain the
92
+ other control records, and rebuild snapshots through live revalidation.
93
+
94
+ ## Constrain native provider CLIs
95
+
96
+ Treat a provider CLI as one reviewed transport, not as a shell. Require a
97
+ schema-v6 `localCli` selector backed by a source-plugin tool identity that pins
98
+ the final executable digest for the current platform. A package-manager name,
99
+ version range, release tag, reported version, or launcher digest is not enough.
100
+
101
+ Use only operation-owned fixed argument templates. Strip ambient credentials,
102
+ targets, account defaults, proxies, update settings, debug state, and user
103
+ plugin discovery from the child environment. Give the process private bounded
104
+ config, data, cache, and temporary roots. Require exact account, target,
105
+ conversation, message, and other resource IDs. Never use an interactive picker
106
+ or fuzzy selector for a mutation.
107
+
108
+ Parse stdout and stderr strictly from `unknown`; cap both and enforce a
109
+ Ghostget-owned deadline because an upstream timeout flag may not be effective.
110
+ Do not log or persist argv. When the upstream CLI accepts private text only in
111
+ argv, document the same-account process-inspection exposure and minimize the
112
+ child lifetime.
113
+
114
+ For a mutation, enter the durable dispatch boundary before process start. A
115
+ timeout, signal, malformed response, or lost response after that point is
116
+ indeterminate. Never let an upstream retry option or a new process invocation
117
+ bypass Ghostget's at-most-once fence. Reconcile only through a separate exact
118
+ read declared by the semantic operation.
119
+
120
+ ## Keep browser authority narrow
121
+
122
+ Prefer target-filtered cookies. Use a path-backed private profile snapshot only when capture or a reviewed token source needs storage beyond cookies. Schema-v1/v2 DOM recipes are retired and fail validation, installation, planning, and execution for every origin; the direct browser-recipe executor is disabled as well. Never automate a concurrently running source profile.
123
+
124
+ Use agent-browser only for:
125
+
126
+ - rendered capture or HAR recording;
127
+ - sign-in/session bootstrap in a task-owned profile;
128
+ - cookie acquisition;
129
+ - one reviewed meta/storage/captured-header secret source;
130
+ - one current registered-operation revision lookup.
131
+
132
+ Do not use it to click, type, upload, publish, react, or send at runtime for a supported capability. DOM state is neither the operation contract nor its verification result.
133
+
134
+ Profile mode may have broader public-host egress than filtered cookies. `--trust-profile-egress` acknowledges that exposure; it does not widen allowed API origins or permit private-network access.
135
+
136
+ ## Constrain first-party HTTP
137
+
138
+ Keep request construction in code. Fix the origin, method, path structure, query names, body shape, headers, timeout, response limit, successful status/content-type pairs, projections, and bindings. Reject redirects.
139
+
140
+ Send session cookies only to the reviewed exact origin. Send CSRF/XSRF and authorization values only from the reviewed source to the fixed matching header. Keep those values in memory and never return them from the bootstrap helper.
141
+
142
+ Do not add a generic HTTP, GraphQL, Rest.li, header, or URL interface. A captured endpoint is evidence, not authority. If a contract is absent or drifted, return `capture-required` and perform no request.
143
+
144
+ ## Minimize HAR exposure
145
+
146
+ - Default to `--content none`.
147
+ - Record one operation and one bounded fixture at a time.
148
+ - Use mode-`0700` directories and mode-`0600` files.
149
+ - Avoid printing or searching raw HAR values in terminal output.
150
+ - Finish or discard every managed derivation.
151
+ - Delete externally supplied HARs after `ghostget derive analyze`.
152
+ - Use `ghostget derive review` only while the managed HAR is task-owned private state. The first review seals recording, list output exposes only bounded sanitized entry metadata, and `--fixtures -` accepts labeled strings only over stdin without echoing or persisting their values. The entry-only `--field-names -` probe accepts 1–50 unique, bounded, non-credential schema-key hypotheses on stdin and reports only candidate indices, fixed structural locations, structural value types, and truncation. It compares exact own keys in bounded parsed JSON, never values, and keeps credential subtrees and dynamic-map positions opaque. The two stdin probes are mutually exclusive and invalid input fails before sealing. `--review-origin` may select one canonical exact HTTPS origin only when its hostname was admitted by the immutable `--domains` declaration at derivation start; undeclared origins fail before sealing. Review cannot replay a request.
153
+ - Serialize each derivation from preflight through cleanup with its fixed identity-bound lifecycle gate. Publish an initialization marker as soon as the socket boundary exists, and publish readiness only after HAR capture, final in-origin validation, and exact session-metadata binding. Only `list` and `discard` may inspect unready or post-reboot state; never delete a live helper that could not be closed.
154
+ - Treat the local OS account as the filesystem trust boundary. Inode binding, no-follow traversal, and unpredictable quarantine names protect against symlink swaps and accidental or cooperative same-account races; they cannot defend against hostile code already running as the same account, which can mutate `GHOSTGET_STATE_HOME` and browser state directly. Keep that account and machine trusted.
155
+ - Never commit a raw HAR, authenticated DOM, screenshot, profile, cookie file, or storage dump.
156
+
157
+ Successful finish deletes the managed raw HAR and emits inert structural evidence. Even that evidence can reveal operation names and response field names; review it before publishing.
158
+
159
+ ## Interpret execution states
160
+
161
+ - `capture-required`: no current reviewed runtime contract exists. No request or browser-action fallback may run.
162
+ - `pending`: ghostget durably reserved a confirmed action, but no terminal result exists. Reconcile it.
163
+ - `succeeded`: an R1 request passed its exact response contract.
164
+ - `submitted`: every planned R2/R3 dispatch passed its exact response and target/account bindings.
165
+ - `failed`: execution stopped before dispatch. Diagnose and create a fresh preview only if the action remains authorized.
166
+ - `partial`: earlier dispatches were verified, but the schedule stopped before completion.
167
+ - `indeterminate`: a dispatch started, but its response or binding could not be verified.
168
+
169
+ Never retry `pending`, `partial`, or `indeterminate` automatically. Do not clear the ledger or change whitespace/metadata to evade duplicate refusal.
170
+
171
+ `submitted` is stronger than a cleared composer because it requires a reviewed response contract. It still does not create a provider-side exactly-once transaction. Inspect remote state when the action matters.
172
+
173
+ ## Reconcile uncertainty
174
+
175
+ 1. Record the run ID and inspect `ghostget runs show <run-id>`.
176
+ 2. For a supported exact desired-state readback, run `ghostget runs reconcile
177
+ <run-id> --json`. Current runs recover their original input only from the
178
+ encrypted run-, auth-, and contract-bound capsule. The recognized legacy X
179
+ bookmark run instead requires its exact original input through `--input`;
180
+ ghostget verifies the receipt's canonical input hash before any read.
181
+ 3. Use only a separate reviewed R1 request that inspects the exact target
182
+ without acknowledgement traffic. The reconciler validates the returned
183
+ state kind and target before recording it.
184
+ 4. Treat every reconciliation as an append-only observation. It never changes
185
+ the original receipt, idempotency ledger, or provider state and never
186
+ creates retry authority.
187
+ Once an exact readback durably records `desired-state-observed`, ghostget
188
+ releases only that run's encrypted capsule and digest-bound attachment
189
+ bundle. A nonmatching or inconclusive observation retains both so another
190
+ bounded inspection remains possible.
191
+ 5. A currently absent desired state does not prove that an earlier write never
192
+ applied briefly. Leave the ledger intact whether the effect is present,
193
+ absent, or still uncertain.
194
+ 6. Wait and inspect again when provider processing may be delayed. Issue a
195
+ materially new action only after fresh authorization and a new exact
196
+ preview; never retry the unsettled action automatically.
197
+
198
+ Receipts keep hashes, contract identity, transport, account-realm fingerprint, dispatch counts, origin, timestamps, and categorical errors. They omit credentials, response bodies, message/post text, private identifiers not required for reconciliation, and original attachment paths.
199
+
200
+ Recovery capsules are private AES-GCM state under `GHOSTGET_STATE_HOME`. They contain
201
+ the exact confirmed input needed for a bounded readback but never appear in
202
+ receipts, plans, logs, or reconciliation observations. Do not delete the
203
+ recovery key or capsule for an unsettled run; a missing key is not regenerated
204
+ during readback, and new writes are refused while older capsules remain,
205
+ because replacing the key would only destroy recoverability. Confirmed
206
+ attachment bundles follow the same lifecycle: settled and proven pre-dispatch
207
+ outcomes remove them, while `pending`, `partial`, and `indeterminate` runs keep
208
+ them until an exact successful reconciliation is durably recorded.
209
+
210
+ ## Clean up task-owned state
211
+
212
+ Cancel unused plans with `ghostget plans cancel <digest> --yes`, discard derivations with `ghostget derive discard <id> --yes`, and remove obsolete auth locators explicitly. Uninstalling the wrapper does not recursively remove browser credentials or ghostget state.
213
+
214
+ If browser capture/bootstrap shutdown cannot be verified, preserve the exact recovery handle and close only that task-owned session before deleting its directories. Do not use broad recursive cleanup against shared browser state.
@@ -0,0 +1,79 @@
1
+ # Social settlement and duplicate cleanup
2
+
3
+ Use this after every confirmation and before any possible repost or deletion.
4
+
5
+ ## Settle one publish attempt
6
+
7
+ 1. Run `ghostget runs show <run-id> --json` and append the result state to the task ledger.
8
+ 2. Record any response-bound provider locator. Do not recover a target by text search, profile-feed position, or approximate time.
9
+ 3. For `submitted`, use the publish contract's independently verified readback evidence. When it does not establish external availability and an observed `posts.read` accepts the exact returned locator, invoke that exact R1 schema and record the observation.
10
+ 4. For `pending`, `partial`, or `indeterminate`, preserve all evidence. Run `ghostget runs reconcile <run-id> --json` only when the installed exact contract advertises reconciliation. Reconciliation is read-only, append-only, and never repeats the mutation.
11
+ 5. Treat an absent or inconclusive read as unresolved, not as proof that the write never happened. Repeat only the bounded read/reconciliation when supported; never repeat the mutation.
12
+ 6. For pre-dispatch `failed`, create a new preview only while the exact original action remains authorized.
13
+
14
+ If a current legacy reconciler explicitly requests original input, supply only the exact confirmed input that Ghostget verifies against the receipt. Never reconstruct or alter it to force a match.
15
+
16
+ ## Keep an exact duplicate ledger
17
+
18
+ Maintain a private append-only event ledger with one attempt row containing:
19
+
20
+ - package identity and exact scalar-input hash;
21
+ - ordered attachment hashes and media types;
22
+ - platform, adapter, transport, auth-realm label, and bound subject;
23
+ - plan digest and expiry, run ID, and current run state;
24
+ - exact provider locator returned or retained after acceptance;
25
+ - readback kind and first observed time;
26
+ - `duplicate-risk-of` links to earlier attempt run IDs;
27
+ - any canonical delete plan/run and exact post-delete proof.
28
+
29
+ Do not put credentials, cookie values, response bodies, post text, or original local paths in the ledger. Never merge two attempts because their text looks alike. Record one provider object per exact locator, including an intentional duplicate.
30
+
31
+ ## Create a fresh duplicate-tolerant intent
32
+
33
+ Only proceed when the user freshly authorizes the exact platform, exact package, and possibility that the unresolved source run already created the post. Append the source link to the private task ledger, then create a fresh preview:
34
+
35
+ ```sh
36
+ ghostget invoke <adapter> posts.publish \
37
+ --input @/absolute/private/post-input.json \
38
+ --auth <bound-auth-id> \
39
+ --duplicate-risk-of <indeterminate-run-id> \
40
+ --preview --json
41
+ ```
42
+
43
+ Version 1 accepts exactly one source run and only a one-dispatch R3 `web-session-api` `posts.publish` operation. An official OAuth or other `provider-api` attempt is ineligible. Ghostget must prove that the source is an unclaimed, retained, terminal `indeterminate` run with the exact same adapter, auth realm, operation, risk, input, contract, receipt, journal, ledger, recovery capsule, and retained attachment bytes. A historical attempt under another contract or adapter remains in the task ledger but is not a valid source. Review the warning and successor fingerprint in the new preview, then confirm its digest once; never put `--duplicate-risk-of` on `ghostget confirm`.
44
+
45
+ Ghostget permanently elects only one successor for the source and keeps successful successor idempotency evidence from expiring. If the source changes, reconciles, lacks exact retained evidence, already elected a successor, or fails any binding check, stop and report the refusal. Do not select a looser source, add a nonce, clear state, or bypass the check.
46
+
47
+ If a duplicate-intent child fails before successor election, its dispatch remains at zero and the source can remain eligible; re-check both runs, then re-preview that same source to derive the same successor intent. If the source was elected but a later local journal step failed, the lineage is intentionally stranded and must not be retried. If a child becomes `indeterminate` after dispatch and another possible duplicate is freshly authorized, cite that eligible child—not any ancestor—to extend one linear chain. Never branch or reuse an already claimed source.
48
+
49
+ This does not settle or replace an older run. Keep its Ghostget ledger and recovery material intact, and reconcile it separately when exact evidence becomes available.
50
+
51
+ ## Delete a proven duplicate
52
+
53
+ Deletion is eligible only when all of these are true:
54
+
55
+ 1. The exact provider locator is in the duplicate ledger.
56
+ 2. An observed exact `posts.read` proves the object, current-account authorship, and content/media binding before deletion.
57
+ 3. The same installed adapter exposes canonical `content.delete` as observed and executable. An absent or `capture-required` operation, or an R4 runtime block, means deletion is unavailable.
58
+ 4. Its schema accepts that exact locator; the preview binds the account, target, side effect, and contract; and the user confirms that digest once.
59
+ 5. A separate exact post-delete R1 contract proves a target-bound tombstone or exact not-found result whose reviewed semantics establish deletion. General feed absence is not proof.
60
+
61
+ If deletion becomes `pending`, `partial`, or `indeterminate`, preserve it and reconcile only through its advertised exact readback. Never retry deletion. Never substitute `posts.delete`, another semantic name, direct browser interaction, raw HTTP, or capture replay for `content.delete`.
62
+
63
+ For the observed Bluesky contract, carry the exact authored `post_uri` and the
64
+ authoritative current `expected_cid` into the preview. CID drift is a refusal,
65
+ not permission to delete a newer revision. A successful mutation is settled
66
+ only by authoritative PDS `RecordNotFound`; AppView/feed absence alone is not
67
+ proof. Never use this cleanup path for an intended post merely because another
68
+ platform attempt is uncertain.
69
+
70
+ ## Report availability time precisely
71
+
72
+ Keep these times distinct:
73
+
74
+ - plan creation/confirmation: local authorization, not publication;
75
+ - dispatch start/finish: Ghostget transport timing, not external availability;
76
+ - provider-created time: a provider-authored value, when strictly bound;
77
+ - first observed time: when exact independent readback saw the object.
78
+
79
+ Report first observation as “available no later than” that time; the actual visibility onset may have been earlier. When readback remains unresolved, say “provider accepted” only when proven and “external availability unverified.”
@@ -0,0 +1,66 @@
1
+ # Social platform routing
2
+
3
+ Use this as routing guidance only. Always inspect `ghostget capabilities <adapter> --json`; installed adapter state and schemas are authoritative and may change.
4
+
5
+ | Surface | Candidate adapter | Signed-in realm | Reference post shape | Meaning |
6
+ | --- | --- | --- | --- | --- |
7
+ | X | `x-web` | Browser cookies/profile | `body`; optional image fields when exposed | Consumer X post |
8
+ | X | `x` | Official OAuth | `body`, optional `media` and aligned alt-text fields; leave `made_with_ai` unset or `false` for user-supplied cross-post copy | Documented API post |
9
+ | LinkedIn | `linkedin-web` | Browser cookies/profile | `body`, `visibility`, optional image and accessibility fields | Member or explicitly bound organization post |
10
+ | LinkedIn | `linkedin` | Official OAuth | Inspect installed schema | Documented API post |
11
+ | Bluesky | `bluesky-web` | Profile-backed Bluesky web session | `body`, optional image, media type, and alt text | AT Protocol feed post |
12
+ | Substack | `substack-web` | Browser cookies/profile | `body`, optional Note media | Public Substack Note, not an article/newsletter |
13
+ | Threads | `meta-web` | Browser cookies/profile | Text/image `posts.publish`: `body`, audience, optional one PNG. Video `media.publish`: `body`, audience, one MP4. | Threads post |
14
+
15
+ Cleanup is capability-driven too. At this reference revision, `bluesky-web`
16
+ exposes observed `content.delete@1` only for one current-account post URI plus
17
+ its exact confirmed CID. `reddit-web` exposes observed `content.delete@1` only
18
+ for one exact current-account post fullname plus its confirmed title, followed
19
+ by independent absence readback. `x-web` reserves `content.delete@1` as
20
+ `capture-required`; `substack-web content.delete@1` is observed for one exact
21
+ authored personal Note with exact actor/body pre-read and independent 404
22
+ absence. LinkedIn and Threads
23
+ deletion remain unavailable unless their installed canonical capability
24
+ independently says otherwise.
25
+
26
+ ## Selection rules
27
+
28
+ - Use exactly one adapter and one stable bound account realm per surface.
29
+ - Prefer the transport the user named or already configured. Do not fall back from browser-session to OAuth, or vice versa, because one operation is unavailable.
30
+ - Require `posts.publish.state == "observed"`. An invalid adapter or `capture-required` operation must produce no request.
31
+ - Treat each current schema's required fields, file cardinality, byte/media bounds, and accessibility-field shape literally. The table is not a capability promise.
32
+ - Preserve input image order. Require alt-text arrays to align one-to-one when the schema exposes them.
33
+ - Re-check capabilities before every new preview. A plan or run remains governed by its bound contract identity when installed support later changes.
34
+ - A provider may reject an otherwise valid image for dimensions, animation, color profile, or account entitlement. Report that provider-owned failure without converting the file unless the user asks for a derivative.
35
+ - For user-supplied cross-post copy, never mark the package as AI-generated. Follow [X AI disclosure](x-ai-disclosure.md). Leave official `x` `made_with_ai` unset or `false`. `x-web` `posts.publish` has no such input field.
36
+ - Prefer a Ghostget transport over the X composer. If the user explicitly requested a composer fallback, require Content disclosure Made with AI OFF before Post, then open the live permalink. A sparkle label means that target failed.
37
+
38
+ ## Common invocation shape
39
+
40
+ Write exact input JSON to a private task file when shell quoting would be fragile, then invoke:
41
+
42
+ ```sh
43
+ ghostget invoke <adapter> posts.publish \
44
+ --input @/absolute/private/post-input.json \
45
+ --auth <bound-auth-id> \
46
+ --preview --json [--headed]
47
+ ```
48
+
49
+ Review the returned digest and confirm it within five minutes:
50
+
51
+ ```sh
52
+ ghostget confirm <plan-digest> --json [--headed]
53
+ ```
54
+
55
+ Use headed execution when the installed signed-in web adapter or bound realm requires it and the user authorized it. Follow the preview's returned `confirmCommand` exactly so headed mode is preserved.
56
+
57
+ Do not place credentials in the input file. Delete task input files after planning; Ghostget's plan owns encrypted confirmed input and attachment bundles for its lifecycle.
58
+
59
+ ## Parity decisions
60
+
61
+ - If text exceeds one platform's bound, request shorter shared copy or an explicit platform-specific variant. Do not silently use `threads.publish`.
62
+ - If the ordered image set exceeds one platform's bound, request a smaller shared set or an explicit per-platform set. Do not manufacture a collage.
63
+ - If LinkedIn requires visibility and the user requested a public cross-post, use `public`; otherwise obtain the user's audience choice.
64
+ - If Threads requires `audience` and the user requested ordinary posting, use the installed schema's ordinary/default audience only when that meaning is explicit in the capability description.
65
+ - At this reference revision, reviewed Threads text/image publication accepts no attachment or exactly one PNG, and reviewed video publication requires exactly one MP4. A dummy PNG, collage, or composer click-path changes the package and is not an installed fallback. JPEG and other image types remain unavailable unless the installed schema independently lists them.
66
+ - If image alt text is supported on only some targets, preserve the same factual description on every target that accepts it; unsupported alt text is not a reason to alter the visible post.
@@ -0,0 +1,195 @@
1
+ # Social profile statistics
2
+
3
+ Use this workflow for a scheduled, read-only collection of exact counters from
4
+ explicitly selected social profiles, owned publications, and organization
5
+ pages. Ghostget owns acquisition, invocation authority, and target binding. The consumer
6
+ owns history, public field selection, presentation, and delivery.
7
+
8
+ ## Preconditions
9
+
10
+ Run `ghostget operator doctor --json`, then inspect each named adapter with
11
+ `ghostget capabilities <adapter> --json`. Every requested operation must be
12
+ installed, `observed`, and R1. Every authenticated operation must be bound to
13
+ the intended account realm; a public operation must instead prove its exact
14
+ requested target. Record a gap for a missing, changed, ambiguous, or
15
+ cleanup-unsafe realm and continue with the independent rows. `capture-required`
16
+ is not a partial success and performs no provider request.
17
+
18
+ Use a normal invocation, never `--cache-only`, for today's observation. A
19
+ cached value may explain the last known level, but it cannot become today's
20
+ sample. Do not use general browser automation, selectors, raw HTTP, or a public
21
+ page's rounded display as a fallback.
22
+
23
+ ## Hraness account manifest
24
+
25
+ The authoritative ordered collection contract is the strict
26
+ [Hraness social-profile manifest](hraness-social-profile-stats.json). Load it
27
+ as foreign JSON, reject unknown fields and duplicate account keys, then flatten
28
+ each account's ordered `reads` array without changing order. Its auth IDs are
29
+ local Ghostget locators, not credentials.
30
+
31
+ Before invoking a read, confirm that the current installed adapter still owns
32
+ the named operation with `state: "observed"`, `risk: "R1"`, and
33
+ `sideEffect: "none"`. Confirm its public or authenticated authority kind, exact
34
+ input, output provider and canonical target URL, metric keys, expected gaps,
35
+ and `requiredDelayBeforeMs`. A mismatch is a categorical contract gap for that
36
+ read. Do not reinterpret the manifest or fall back to a different capability.
37
+ The current X accounts are `x-hraness` and `x-lifedaysleft`.
38
+ The second exact handle is `lifedaysleft`.
39
+
40
+ Bluesky and GitHub profile and organization statistics come from public target-bound APIs.
41
+ Invoke these rows without `--auth`. Ghostget assigns each reviewed operation a
42
+ deterministic public authority for receipts and exact R1 caching. Supplying an
43
+ auth locator is an error.
44
+
45
+ The Twitch row targets exactly
46
+ `https://www.twitch.tv/hranessdotcom`. Invoke the installed observed
47
+ `twitch-web profiles.read` capability with `{"profile":"hranessdotcom"}` and
48
+ the `twitch-chrome` realm. Ghostget binds the authenticated current viewer before
49
+ it binds the fixed login-parameterized channel response to that viewer's
50
+ immutable identity, then accepts followers only as an exact nonnegative
51
+ integer. A missing, changed, or mismatched realm, an ambiguous target, or
52
+ provider drift creates a categorical gap. Do not substitute browser
53
+ automation, raw HTTP, a rounded public display, a cached value, or an estimate.
54
+
55
+ Keep the two X calls sequential, both LinkedIn calls sequential, and both
56
+ Substack calls sequential because each pair shares one authenticated realm.
57
+ `linkedin-chrome` must be a path-backed `browser-profile` locator over a
58
+ private dormant Chrome snapshot, optionally overlaid with current filtered
59
+ cookies from the selected Chrome profile. A cookie-source-only LinkedIn realm
60
+ is not an acceptable scheduled fallback because LinkedIn invalidates the
61
+ exported session outside its browser/device context. Before the initial
62
+ snapshot, or after a contained identity preflight returns 401, load LinkedIn
63
+ normally in the source Chrome profile, confirm the session is current, fully
64
+ quit Chrome, and replace the dormant snapshot. A filtered cookie overlay does
65
+ not revive a stale source session.
66
+ Leave a 60-second idle interval after the LinkedIn personal read before the
67
+ company read; current live evidence shows shorter intervals can trigger a
68
+ temporary identity-preflight redirect even when the realm remains correctly
69
+ bound. Do not routinely rebind or rotate the locator.
70
+ The first scheduled version should run the whole table sequentially. This is a
71
+ small daily workload and avoids provider bootstrap, keychain, and session-lock
72
+ contention. A later caller may parallelize distinct realms with a small bound,
73
+ but must never overlap work on the same `(surface, auth ID)` pair.
74
+
75
+ Invoke each row with bounded stdin and exact JSON output:
76
+
77
+ ```sh
78
+ printf '%s' '<input-json>' \
79
+ | ghostget invoke <adapter> <operation> --input - --auth <auth-id> --json
80
+ ```
81
+
82
+ For the public Bluesky and GitHub rows, omit the auth option:
83
+
84
+ ```sh
85
+ printf '%s' '{"handle":"hraness.bsky.social"}' \
86
+ | ghostget invoke bluesky-web profiles.read --input - --json
87
+ printf '%s' '{"username":"0thernet"}' \
88
+ | ghostget invoke github-web profiles.read --input - --json
89
+ printf '%s' '{"organization":"hraness"}' \
90
+ | ghostget invoke github-web organizations.read --input - --json
91
+ ```
92
+
93
+ `status: "failed"` R1 envelopes include one secret-free `readFailure`
94
+ projection with a closed `category` and its only valid
95
+ `retryDisposition`. A caller may make at most one retry for the read, after
96
+ 60 seconds, and only when the disposition is
97
+ `retry-once-after-60s`. A transport retry consumes that same budget. Never
98
+ retry `repair-auth` or `do-not-retry`; report the bounded category and
99
+ continue with the next independent row. Do not parse receipt errors or
100
+ provider exception text to invent a retry policy. Do not clear durable cleanup
101
+ admission or reboot a host without separate operator authorization.
102
+
103
+ `github-web organizations.read` first binds the exact organization and its
104
+ declared public repository count, then completes the fixed public repository
105
+ pagination before summing `stargazers_count`. It returns `stars` only when the
106
+ complete repository set is available and bound; it never substitutes a partial
107
+ page, a rounded display total, or a prior observation.
108
+
109
+ The manifest marks Threads `recentViews` with the exact unavailable reason
110
+ `not-authorized` as an expected categorical gap until the account becomes
111
+ eligible. Keep reporting only that reason as unavailable. Treat
112
+ `provider-drift`, `not-exposed`, and every other unavailable reason as an
113
+ unexpected failure. Accept the metric normally once the same target-bound read
114
+ returns an exact available count.
115
+
116
+ Do not put an auth ID, provider receipt, cache key, run ID, subject identifier,
117
+ or raw provider response in the consumer snapshot. Do not print or persist
118
+ cookies, headers, tokens, HTML, first-party response bodies, or exception text.
119
+
120
+ ## Accept exact metric observations
121
+
122
+ Accept a row only when the live invocation reports a succeeded R1 receipt and
123
+ its live output binds the requested provider and canonical target, plus the
124
+ current realm for authenticated operations. The profile-stat envelope is
125
+ version 1 and contains:
126
+
127
+ - `provider`, `target`, `observedAt`, and `completeness`;
128
+ - one metric record per requested counter, including categorical unavailable
129
+ records when the provider cannot expose an exact value;
130
+ - bounded public metadata such as handle, display name, bio, or public website.
131
+
132
+ Each publishable metric must have `status: "available"`,
133
+ `precision: "exact"`, `unit: "count"`, and a nonnegative safe-integer `value`.
134
+ Reject `500+`, `1.2K`, estimated, lower-bound, rounded, hidden, unavailable, and
135
+ provider-drift values. A provider may return them as categorical unavailable
136
+ evidence, but the consumer must not coerce them. Accept each exact available
137
+ metric independently once the invocation and target are valid. A partial
138
+ provider output may therefore advance followers while leaving recent views
139
+ unavailable. Substack is an intentional two-read join, but either target-bound
140
+ read may contribute its own exact metrics when the other read fails.
141
+
142
+ An unavailable metric creates a gap only for that metric. Never write zero,
143
+ copy the previous day into the scheduled date, or suppress a different exact
144
+ metric from the same account. Report failed consumer keys and metric keys with
145
+ bounded categorical reasons after the sequential collection completes.
146
+
147
+ ## Install into Hraness
148
+
149
+ Build one mode-private temporary document with this exact public handoff:
150
+
151
+ ```json
152
+ {
153
+ "schemaVersion": 1,
154
+ "scheduledDate": "YYYY-MM-DD",
155
+ "timezone": "America/New_York",
156
+ "observations": [
157
+ {
158
+ "accountKey": "x-hraness",
159
+ "observedAt": "YYYY-MM-DDTHH:mm:ss.sssZ",
160
+ "metrics": {
161
+ "followers": 1,
162
+ "following": 1
163
+ }
164
+ }
165
+ ]
166
+ }
167
+ ```
168
+
169
+ Run the consumer's installer from a clean, current Jungle worktree:
170
+
171
+ ```sh
172
+ bun run --cwd projects/hraness social:install --input /absolute/private/run.json
173
+ bun run --cwd projects/hraness social:validate
174
+ bun run check:affected
175
+ ```
176
+
177
+ For the Hraness consumer, the preferred daily entry point performs the fixed
178
+ sequential collection and installs its validated public subset directly:
179
+
180
+ ```sh
181
+ bun run --cwd projects/hraness social:refresh
182
+ bun run --cwd projects/hraness social:validate
183
+ bun run check:affected
184
+ ```
185
+
186
+ The installer is the only process allowed to update
187
+ `projects/hraness/app/social-stats.generated.json`. It validates the exact
188
+ configured metric subset, derives the Eastern date from each observation time,
189
+ preserves a newer same-day success, retains fourteen days, and writes canonical
190
+ JSON. Remove the temporary document after installation.
191
+
192
+ Review that the task diff contains only the checked social snapshot. Commit and
193
+ deliver it through the repository's current-main workflow, then verify the
194
+ Hraness production deployment. Never commit an empty or synthetic observation,
195
+ raw Ghostget output, capture evidence, or local state.
@@ -0,0 +1,89 @@
1
+ # Social video platform routing
2
+
3
+ Use this as routing guidance only. Always inspect
4
+ `ghostget capabilities <adapter> --json`; installed adapter state and schemas
5
+ are authoritative and may change.
6
+
7
+ | Surface | Candidate adapter | Video operation | Meaning |
8
+ | --- | --- | --- | --- |
9
+ | X | `x-web` | `posts.publish` when the installed schema accepts `video/mp4` | Consumer X post. Observed `x-web` `posts.publish` now accepts one plan-bound PNG or one MP4. |
10
+ | X | `x` | `posts.publish` when the installed schema accepts `video/mp4` | Official OAuth post. Already schemas MP4. |
11
+ | LinkedIn | `linkedin` | video-capable `posts.publish` | Observed official OAuth member or explicitly bound organization post. |
12
+ | LinkedIn | `linkedin-web` | `media.publish` when observed | Consumer-web member video; currently a separate capture-required route so image `posts.publish` remains unchanged. |
13
+ | Bluesky | `bluesky-web` | `media.publish` | Observed AT Protocol video feed post; image `posts.publish` remains a separate observed contract. |
14
+ | Substack | `substack-web` | `media.publish` when observed | Public Substack Note, not an article or newsletter. |
15
+ | TikTok | `tiktok-web` | `media.publish` when observed | Native TikTok video |
16
+ | Instagram | `meta-web` on the Instagram surface | `media.publish` when observed | Instagram video or Reel only when the schema says so. |
17
+ | Threads | `meta-web` on the Threads surface | `media.publish` | Observed single-MP4 Threads video post; text/image `posts.publish` remains a separate contract. |
18
+ | YouTube Shorts | `youtube-web` | `media.publish` when observed | Studio video upload. Community `posts.publish` is not a Short. |
19
+ | Reddit | `reddit-web` | `media.publish` when observed | One video post in one exact confirmed subreddit. |
20
+
21
+ At the 2026-08-23 reference revision, `x-web` `posts.publish` is observed
22
+ for one plan-bound `image/png` or one plan-bound `video/mp4`. Official `x`
23
+ and official `linkedin` already observe MP4 post contracts. `reddit-web`
24
+ `media.publish@9` observes one plan-bound MP4 plus a required plan-bound
25
+ PNG/JPEG poster and explicit NSFW, spoiler, and reply declarations. Threads
26
+ `media.publish@1` observes one plan-bound ISO BMFF MP4, exact dimensions, its
27
+ single-request video upload, durable created-post identity, and independent
28
+ permalink actor/text/video readback. Bluesky `media.publish@2` observes one
29
+ plan-bound ISO BMFF MP4, the fixed first-party legacy upload and response-bound
30
+ processing job, processed blob, exact repository record, durable accepted
31
+ target, and authoritative PDS plus public AppView readbacks. LinkedIn web,
32
+ Substack Notes, TikTok, Instagram, and YouTube expose bounded video `media.publish`
33
+ reservations. Those routes stay `capture-required` until their exact upload,
34
+ processing, request, response, actor/target, and independent readback contracts
35
+ are implemented and proven.
36
+ For Substack specifically, an authorized profile-backed fixture proved 200
37
+ initialization, ordered raw multipart transfer, transcode, status polling, and
38
+ video-attachment creation. The final Note create returned 403 twice, including
39
+ one Ghostget-native attempt, so there is no provider-created video Note or exact
40
+ readback to graduate. `content.delete@1` is independently observed for cleanup
41
+ of an exact authored personal Note; that does not imply video publication.
42
+ Treat them as unavailable until the installed capability independently says
43
+ `observed`.
44
+
45
+ ## Selection rules
46
+
47
+ - Use exactly one adapter and one stable bound account realm per surface.
48
+ - Prefer the transport the user named or already configured. Do not fall
49
+ back from browser-session to OAuth, or vice versa, because one operation
50
+ is unavailable.
51
+ - Require the chosen video operation's `state == "observed"`. An invalid
52
+ adapter or `capture-required` operation must produce no request.
53
+ - A text or image `posts.publish` is not a substitute for video.
54
+ - Re-check capabilities before every new preview.
55
+ - Tags are an explicit platform-specific variant only for TikTok,
56
+ Instagram, and YouTube Shorts. Leave X, LinkedIn, Substack, Bluesky,
57
+ Threads, and Reddit tag-free.
58
+ - Set each supported synthetic-media or AI declaration explicitly and
59
+ truthfully from the actual video's provenance; caption authorship does not
60
+ determine the media declaration. Follow [X AI disclosure](x-ai-disclosure.md)
61
+ for the official `x` `made_with_ai` choice, and do not invent a disclosure
62
+ field on an adapter whose installed schema does not expose one.
63
+
64
+ ## Common invocation shape
65
+
66
+ Write exact input JSON to a private task file when shell quoting would be
67
+ fragile, then invoke:
68
+
69
+ ```sh
70
+ ghostget invoke <adapter> media.publish \
71
+ --input @/absolute/private/video-input.json \
72
+ --auth <bound-auth-id> \
73
+ --preview --json [--headed]
74
+ ```
75
+
76
+ Use `posts.publish` instead only when the installed schema for that
77
+ adapter accepts `video/mp4` on that operation.
78
+
79
+ Review the returned digest and confirm it within five minutes:
80
+
81
+ ```sh
82
+ ghostget confirm <plan-digest> --json [--headed]
83
+ ```
84
+
85
+ Follow the preview's returned `confirmCommand` exactly so headed mode is
86
+ preserved.
87
+
88
+ Do not place credentials in the input file. Delete task input files after
89
+ planning.