@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.
- package/CHANGELOG.md +458 -0
- package/LICENSE +21 -0
- package/README.md +1359 -0
- package/bunfig.toml +2 -0
- package/dist/apple-photos-client.js +704 -0
- package/dist/beeper-client.js +4602 -0
- package/dist/client.js +1605 -0
- package/dist/index-26yq8q16.js +31 -0
- package/dist/index-9t13b4k7.js +508 -0
- package/dist/index-axwm9b3v.js +5 -0
- package/dist/index-gwk7rbyj.js +30 -0
- package/dist/index.js +701 -0
- package/dist/messaging.js +1130 -0
- package/dist/omni-client.js +1406 -0
- package/dist/whatsapp-client.js +355 -0
- package/docs/imessage-direct-provider.md +106 -0
- package/docs/rental-listings.md +94 -0
- package/package.json +600 -0
- package/skills/ghostget/SKILL.md +251 -0
- package/skills/ghostget/agents/openai.yaml +4 -0
- package/skills/ghostget/references/adapter-contract.md +181 -0
- package/skills/ghostget/references/apple-photos.md +115 -0
- package/skills/ghostget/references/article-drafts.md +235 -0
- package/skills/ghostget/references/code-owned-provider-scaffold.md +134 -0
- package/skills/ghostget/references/cross-posting-video.md +139 -0
- package/skills/ghostget/references/cross-posting.md +82 -0
- package/skills/ghostget/references/derivation.md +390 -0
- package/skills/ghostget/references/hraness-social-profile-stats.json +269 -0
- package/skills/ghostget/references/install.md +66 -0
- package/skills/ghostget/references/linkedin-adapter.md +442 -0
- package/skills/ghostget/references/messaging.md +168 -0
- package/skills/ghostget/references/meta-comet-contract.md +153 -0
- package/skills/ghostget/references/platform-patterns.md +122 -0
- package/skills/ghostget/references/provider-plugins.md +496 -0
- package/skills/ghostget/references/reddit-flair.md +78 -0
- package/skills/ghostget/references/safety-and-state.md +214 -0
- package/skills/ghostget/references/settlement-and-duplicate-cleanup.md +79 -0
- package/skills/ghostget/references/social-platform-routing.md +66 -0
- package/skills/ghostget/references/social-profile-stats.md +195 -0
- package/skills/ghostget/references/social-video-platform-routing.md +89 -0
- package/skills/ghostget/references/whatsapp-adapter.md +101 -0
- package/skills/ghostget/references/x-adapter.md +332 -0
- package/skills/ghostget/references/x-ai-disclosure.md +71 -0
- package/src/apple-photos-cli.ts +639 -0
- package/src/apple-photos-client-types.ts +168 -0
- package/src/apple-photos-client.ts +201 -0
- package/src/apple-photos-contact-evidence.ts +838 -0
- package/src/apple-photos-local-source.ts +1131 -0
- package/src/args.ts +2053 -0
- package/src/article-draft-document.ts +417 -0
- package/src/article-draft-embeds.ts +123 -0
- package/src/article-draft-images.ts +214 -0
- package/src/assets/adapter-template/wrench-adapter.json +40 -0
- package/src/assets/adapters/beeper/wrench-web-adapter.json +1500 -0
- package/src/assets/adapters/beeper/wrench-web-adapter.v1.0.0.json +129 -0
- package/src/assets/adapters/beeper/wrench-web-adapter.v1.1.0.json +207 -0
- package/src/assets/adapters/beeper/wrench-web-adapter.v2.0.0.json +1463 -0
- package/src/assets/adapters/beeper/wrench-web-adapter.v2.1.0.json +1463 -0
- package/src/assets/adapters/beeper/wrench-web-adapter.v2.2.0.json +1475 -0
- package/src/assets/adapters/beeper/wrench-web-adapter.v2.3.0.json +1488 -0
- package/src/assets/adapters/bluesky/wrench-web-adapter.json +684 -0
- package/src/assets/adapters/bluesky/wrench-web-adapter.v1.0.0.json +581 -0
- package/src/assets/adapters/bluesky/wrench-web-adapter.v1.1.0.json +581 -0
- package/src/assets/adapters/bluesky/wrench-web-adapter.v1.2.0.json +581 -0
- package/src/assets/adapters/bluesky/wrench-web-adapter.v1.3.0.json +615 -0
- package/src/assets/adapters/bluesky/wrench-web-adapter.v1.4.0.json +684 -0
- package/src/assets/adapters/bluesky/wrench-web-adapter.v1.5.0.json +684 -0
- package/src/assets/adapters/bluesky/wrench-web-adapter.v1.6.0.json +684 -0
- package/src/assets/adapters/clasificados/wrench-web-adapter.json +54 -0
- package/src/assets/adapters/facebook/wrench-web-adapter.json +750 -0
- package/src/assets/adapters/facebook/wrench-web-adapter.v1.0.0.json +706 -0
- package/src/assets/adapters/facebook/wrench-web-adapter.v1.1.0.json +703 -0
- package/src/assets/adapters/facebook/wrench-web-adapter.v1.2.0.json +750 -0
- package/src/assets/adapters/facebook-group/wrench-web-adapter.json +682 -0
- package/src/assets/adapters/facebook-group/wrench-web-adapter.v1.0.0.json +583 -0
- package/src/assets/adapters/facebook-group/wrench-web-adapter.v1.1.0.json +682 -0
- package/src/assets/adapters/facebook-marketplace/wrench-web-adapter.json +437 -0
- package/src/assets/adapters/facebook-marketplace/wrench-web-adapter.v1.0.0.json +383 -0
- package/src/assets/adapters/facebook-marketplace/wrench-web-adapter.v1.1.0.json +437 -0
- package/src/assets/adapters/facebook-marketplace/wrench-web-adapter.v1.1.1.json +437 -0
- package/src/assets/adapters/facebook-page/wrench-web-adapter.json +880 -0
- package/src/assets/adapters/facebook-page/wrench-web-adapter.v1.0.0.json +740 -0
- package/src/assets/adapters/facebook-page/wrench-web-adapter.v1.1.0.json +880 -0
- package/src/assets/adapters/github/wrench-web-adapter.json +69 -0
- package/src/assets/adapters/github/wrench-web-adapter.v1.0.0.json +42 -0
- package/src/assets/adapters/github/wrench-web-adapter.v1.1.0.json +69 -0
- package/src/assets/adapters/gmail/wrench-adapter.json +161 -0
- package/src/assets/adapters/gmail/wrench-adapter.v1.2.0.json +157 -0
- package/src/assets/adapters/hacker-news/wrench-web-adapter.json +315 -0
- package/src/assets/adapters/hacker-news/wrench-web-adapter.v1.0.0.json +315 -0
- package/src/assets/adapters/imessage/wrench-web-adapter.json +236 -0
- package/src/assets/adapters/instagram/wrench-web-adapter.json +719 -0
- package/src/assets/adapters/instagram/wrench-web-adapter.v1.0.0.json +627 -0
- package/src/assets/adapters/instagram/wrench-web-adapter.v1.1.0.json +609 -0
- package/src/assets/adapters/instagram/wrench-web-adapter.v1.2.0.json +640 -0
- package/src/assets/adapters/instagram/wrench-web-adapter.v1.3.0.json +671 -0
- package/src/assets/adapters/instagram/wrench-web-adapter.v1.4.0.json +710 -0
- package/src/assets/adapters/instagram/wrench-web-adapter.v1.5.0.json +710 -0
- package/src/assets/adapters/instagram/wrench-web-adapter.v1.6.0.json +719 -0
- package/src/assets/adapters/instagram/wrench-web-adapter.v1.7.0.json +719 -0
- package/src/assets/adapters/linkedin/wrench-adapter.json +442 -0
- package/src/assets/adapters/linkedin/wrench-adapter.v0.4.0.json +124 -0
- package/src/assets/adapters/linkedin/wrench-adapter.v1.0.0.json +411 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.json +914 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.0.0.json +604 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.1.0.json +604 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.10.0.json +809 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.11.0.json +809 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.12.0.json +820 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.13.0.json +819 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.14.0.json +819 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.15.0.json +819 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.16.0.json +874 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.17.0.json +874 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.18.0.json +874 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.19.0.json +874 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.2.0.json +731 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.3.0.json +768 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.4.0.json +808 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.5.0.json +808 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.6.0.json +808 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.7.0.json +825 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.8.0.json +792 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.v1.9.0.json +809 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.json +855 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.0.0.json +577 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.1.0.json +604 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.10.0.json +712 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.11.0.json +712 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.12.0.json +712 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.2.0.json +653 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.3.0.json +712 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.4.0.json +713 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.5.0.json +712 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.6.0.json +713 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.7.0.json +713 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.8.0.json +713 -0
- package/src/assets/adapters/reddit/wrench-web-adapter.v1.9.0.json +713 -0
- package/src/assets/adapters/substack/wrench-web-adapter.json +936 -0
- package/src/assets/adapters/substack/wrench-web-adapter.v1.0.0.json +817 -0
- package/src/assets/adapters/substack/wrench-web-adapter.v1.1.0.json +812 -0
- package/src/assets/adapters/substack/wrench-web-adapter.v1.2.0.json +812 -0
- package/src/assets/adapters/substack/wrench-web-adapter.v1.3.0.json +902 -0
- package/src/assets/adapters/substack/wrench-web-adapter.v1.4.0.json +936 -0
- package/src/assets/adapters/substack/wrench-web-adapter.v1.5.0.json +936 -0
- package/src/assets/adapters/substack/wrench-web-adapter.v1.6.0.json +936 -0
- package/src/assets/adapters/threads/wrench-web-adapter.json +692 -0
- package/src/assets/adapters/threads/wrench-web-adapter.v1.0.0.json +629 -0
- package/src/assets/adapters/threads/wrench-web-adapter.v1.1.0.json +623 -0
- package/src/assets/adapters/threads/wrench-web-adapter.v1.2.0.json +622 -0
- package/src/assets/adapters/threads/wrench-web-adapter.v1.3.0.json +622 -0
- package/src/assets/adapters/threads/wrench-web-adapter.v1.4.0.json +622 -0
- package/src/assets/adapters/threads/wrench-web-adapter.v1.5.0.json +699 -0
- package/src/assets/adapters/threads/wrench-web-adapter.v1.6.0.json +693 -0
- package/src/assets/adapters/threads/wrench-web-adapter.v1.7.0.json +692 -0
- package/src/assets/adapters/tiktok/wrench-web-adapter.json +762 -0
- package/src/assets/adapters/tiktok/wrench-web-adapter.v1.0.0.json +681 -0
- package/src/assets/adapters/tiktok/wrench-web-adapter.v1.1.0.json +708 -0
- package/src/assets/adapters/tiktok/wrench-web-adapter.v1.2.0.json +762 -0
- package/src/assets/adapters/tiktok/wrench-web-adapter.v1.3.0.json +762 -0
- package/src/assets/adapters/twitch/wrench-web-adapter.json +42 -0
- package/src/assets/adapters/twitch/wrench-web-adapter.v1.0.0.json +42 -0
- package/src/assets/adapters/whatsapp/wrench-web-adapter.json +400 -0
- package/src/assets/adapters/whatsapp/wrench-web-adapter.v1.0.0.json +355 -0
- package/src/assets/adapters/whatsapp/wrench-web-adapter.v1.1.0.json +386 -0
- package/src/assets/adapters/whatsapp/wrench-web-adapter.v1.2.0.json +386 -0
- package/src/assets/adapters/whatsapp/wrench-web-adapter.v1.3.0.json +400 -0
- package/src/assets/adapters/x/wrench-adapter.json +749 -0
- package/src/assets/adapters/x/wrench-adapter.v1.0.0.json +700 -0
- package/src/assets/adapters/x/wrench-adapter.v1.1.0.json +707 -0
- package/src/assets/adapters/x/wrench-web-adapter.json +712 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.1.0.json +579 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.10.0.json +685 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.11.0.json +712 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.12.0.json +712 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.13.0.json +712 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.2.0.json +578 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.3.0.json +610 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.4.0.json +617 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.5.0.json +634 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.6.0.json +632 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.7.0.json +649 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.8.0.json +649 -0
- package/src/assets/adapters/x/wrench-web-adapter.v1.9.0.json +683 -0
- package/src/assets/adapters/youtube/wrench-web-adapter.json +561 -0
- package/src/assets/adapters/youtube/wrench-web-adapter.v1.0.0.json +465 -0
- package/src/assets/adapters/youtube/wrench-web-adapter.v1.1.0.json +519 -0
- package/src/assets/adapters/youtube/wrench-web-adapter.v1.2.0.json +561 -0
- package/src/assets/adapters/youtube/wrench-web-adapter.v1.3.0.json +561 -0
- package/src/assets/code-owned-provider-template/plugin.test.ts.template +54 -0
- package/src/assets/code-owned-provider-template/plugin.ts.template +102 -0
- package/src/assets/code-owned-provider-template/runtime.internal.test.ts.template +44 -0
- package/src/assets/code-owned-provider-template/runtime.ts.template +59 -0
- package/src/assets/code-owned-provider-template/wrench-adapter.json.template +33 -0
- package/src/assets/fonts/nebula-sans/LICENSE.txt +96 -0
- package/src/assets/fonts/nebula-sans/NebulaSans-Book.woff2 +0 -0
- package/src/assets/fonts/nebula-sans/PROVENANCE.md +14 -0
- package/src/assets.d.ts +4 -0
- package/src/auth.ts +1157 -0
- package/src/beeper-client-types.ts +169 -0
- package/src/beeper-client.ts +250 -0
- package/src/beeper-contact-interactions-cli.ts +180 -0
- package/src/beeper-contact-interactions.ts +1612 -0
- package/src/beeper-message-bundle-v1.ts +257 -0
- package/src/beeper-message-like-me-cli.ts +84 -0
- package/src/beeper-message-like-me-export.ts +2274 -0
- package/src/beeper-message-like-me-recovery.ts +931 -0
- package/src/beeper-message-like-me-source.ts +4034 -0
- package/src/browser-admission.ts +928 -0
- package/src/browser-snapshots.ts +260 -0
- package/src/browser.ts +3873 -0
- package/src/canonical-json.ts +60 -0
- package/src/catalog-cli.ts +638 -0
- package/src/cli.ts +208 -0
- package/src/client-types.ts +301 -0
- package/src/client.ts +2726 -0
- package/src/confirmed-write-failure.ts +44 -0
- package/src/confirmed-write-model.ts +72 -0
- package/src/confirmed-write-platform.ts +1055 -0
- package/src/confirmed-write-program.ts +224 -0
- package/src/confirmed-write-runtime.ts +16 -0
- package/src/cursor-token.ts +228 -0
- package/src/derivation-dnr-readiness.ts +367 -0
- package/src/derivation-file-chooser.ts +384 -0
- package/src/derivation-network-boundary.ts +835 -0
- package/src/derivation-network-guard.ts +782 -0
- package/src/derivation-network-proxy-helper.ts +440 -0
- package/src/derivation-network-proxy.ts +385 -0
- package/src/derive-command-helper.ts +693 -0
- package/src/derive-fixtures.ts +343 -0
- package/src/derive-review.ts +980 -0
- package/src/derive.ts +4754 -0
- package/src/fixtures/beeper-message-like-me-v1/accounts.ndjson +2 -0
- package/src/fixtures/beeper-message-like-me-v1/conversations.ndjson +1 -0
- package/src/fixtures/beeper-message-like-me-v1/manifest.json +1 -0
- package/src/fixtures/beeper-message-like-me-v1/messages.ndjson +2 -0
- package/src/fixtures/beeper-message-like-me-v1/participants.ndjson +3 -0
- package/src/fixtures/beeper-message-like-me-v1/reactions.ndjson +1 -0
- package/src/fixtures/beeper-message-like-me-v1/tombstones.ndjson +1 -0
- package/src/ghostget.ts +3672 -0
- package/src/gmail-capture.ts +1244 -0
- package/src/har-internal.ts +1242 -0
- package/src/har.ts +743 -0
- package/src/index.ts +218 -0
- package/src/invocation-read-platform.ts +55 -0
- package/src/invocation-read-program.ts +93 -0
- package/src/invocation-read-runtime.ts +11 -0
- package/src/linked-device-lifecycle-admission.ts +450 -0
- package/src/linked-device-lifecycle-journal.ts +1560 -0
- package/src/linked-device-lifecycle-runtime.ts +1602 -0
- package/src/local-cli-admission.ts +135 -0
- package/src/local-cli-contracts.ts +271 -0
- package/src/local-cli-execution.ts +98 -0
- package/src/local-cli-surface-contract.ts +1510 -0
- package/src/local-cli-tool-identity.ts +336 -0
- package/src/media/archive.ts +2325 -0
- package/src/media/args.ts +303 -0
- package/src/media/cli.ts +287 -0
- package/src/media/doctor.ts +475 -0
- package/src/media/ffmpeg.ts +1330 -0
- package/src/media/http-capture.ts +711 -0
- package/src/media/http-probe.ts +593 -0
- package/src/media/http.ts +387 -0
- package/src/media/index.ts +10 -0
- package/src/media/local-transcription.ts +613 -0
- package/src/media/lock.ts +321 -0
- package/src/media/manifest.ts +1712 -0
- package/src/media/metadata.ts +906 -0
- package/src/media/process.ts +723 -0
- package/src/media/revision.ts +166 -0
- package/src/media/runtime-closure.ts +1063 -0
- package/src/media/source-router.ts +187 -0
- package/src/media/transcriber-config.ts +1122 -0
- package/src/media/transcript-persistence-model.ts +15 -0
- package/src/media/transcript-persistence-platform.ts +89 -0
- package/src/media/transcript-persistence-program.ts +39 -0
- package/src/media/transcript-persistence-runtime.ts +24 -0
- package/src/media/transcript.ts +616 -0
- package/src/media/utf8-order.ts +30 -0
- package/src/media/whisper-cpp.ts +464 -0
- package/src/media/whisper-language.ts +58 -0
- package/src/media/yt-dlp.ts +439 -0
- package/src/message-like-me-agentic-messaging.ts +882 -0
- package/src/messaging-action-store.ts +793 -0
- package/src/messaging-runtime.ts +2136 -0
- package/src/messaging-store.ts +539 -0
- package/src/messaging-types.ts +1663 -0
- package/src/messaging.ts +334 -0
- package/src/model.ts +2671 -0
- package/src/oauth-google.ts +888 -0
- package/src/omni-client-types.ts +306 -0
- package/src/omni-client.ts +2225 -0
- package/src/omni-limits.ts +34 -0
- package/src/omni-model.ts +1614 -0
- package/src/omni-request.ts +379 -0
- package/src/omni-runtime.ts +1632 -0
- package/src/operation-deadline.ts +189 -0
- package/src/path-helper.ts +1656 -0
- package/src/pinned-https.ts +194 -0
- package/src/plan-assets.ts +832 -0
- package/src/platform-catalog.ts +1832 -0
- package/src/plugins/beeper-linked-device/plugin.ts +310 -0
- package/src/plugins/bluesky-web/plugin.ts +178 -0
- package/src/plugins/clasificados-web/plugin.ts +66 -0
- package/src/plugins/github-web/plugin.ts +80 -0
- package/src/plugins/gmail-official/plugin.ts +110 -0
- package/src/plugins/hacker-news-web/plugin.ts +52 -0
- package/src/plugins/imessage-direct/plugin.ts +195 -0
- package/src/plugins/imessage-direct/vendor/0001-fix-keep-AppleScript-send-payloads-out-of-child-argv.patch +1430 -0
- package/src/plugins/imessage-direct/vendor/0002-feat-rpc-add-exact-chat-lookup.patch +225 -0
- package/src/plugins/imessage-direct/vendor/provenance.json +80 -0
- package/src/plugins/linkedin-official/plugin.ts +84 -0
- package/src/plugins/linkedin-web/plugin.ts +412 -0
- package/src/plugins/meta-web/plugin.ts +317 -0
- package/src/plugins/reddit-web/flair.ts +492 -0
- package/src/plugins/reddit-web/plugin.ts +477 -0
- package/src/plugins/substack-web/plugin.ts +124 -0
- package/src/plugins/tiktok-web/plugin.ts +67 -0
- package/src/plugins/twitch-web/plugin.ts +54 -0
- package/src/plugins/whatsapp-linked-device/plugin.ts +105 -0
- package/src/plugins/x-official/plugin.ts +64 -0
- package/src/plugins/x-web/plugin.ts +488 -0
- package/src/plugins/youtube-web/plugin.ts +101 -0
- package/src/portable-run-recovery.ts +466 -0
- package/src/process-identity.ts +501 -0
- package/src/profile-clone-helper.ts +104 -0
- package/src/provider-catalog-views.ts +51 -0
- package/src/provider-context.ts +69 -0
- package/src/provider-contract-definitions-x.ts +45 -0
- package/src/provider-contract-definitions.ts +948 -0
- package/src/provider-contract-input-gmail.ts +176 -0
- package/src/provider-contract-input-linkedin.ts +77 -0
- package/src/provider-contract-input-x.ts +304 -0
- package/src/provider-contract-planning.ts +23 -0
- package/src/provider-contract-semantic-identity.ts +54 -0
- package/src/provider-contracts.ts +251 -0
- package/src/provider-http.ts +723 -0
- package/src/provider-plugin-auth.ts +36 -0
- package/src/provider-plugin-builtins.ts +229 -0
- package/src/provider-plugin-cleanup-barrier.ts +229 -0
- package/src/provider-plugin-cleanup-execution.ts +79 -0
- package/src/provider-plugin-cleanup-resource.ts +470 -0
- package/src/provider-plugin-contract-identity.ts +707 -0
- package/src/provider-plugin-host.ts +1972 -0
- package/src/provider-plugin-identifiers.ts +60 -0
- package/src/provider-plugin-invocation-lease.ts +889 -0
- package/src/provider-plugin-lifecycle-kernel.ts +566 -0
- package/src/provider-plugin-lifecycle.ts +1455 -0
- package/src/provider-plugin-module-analysis.ts +336 -0
- package/src/provider-plugin-package.ts +2530 -0
- package/src/provider-plugin-portable-authority.ts +106 -0
- package/src/provider-plugin-portable-catalog.ts +94 -0
- package/src/provider-plugin-portable-identity.ts +315 -0
- package/src/provider-plugin-portable-runtime.ts +2057 -0
- package/src/provider-plugin-protocol.ts +1625 -0
- package/src/provider-plugin-registry.ts +3342 -0
- package/src/provider-plugin-store.ts +2155 -0
- package/src/provider-plugin-test-fixture.ts +5 -0
- package/src/provider-plugin.ts +4907 -0
- package/src/provider-plugins.generated.ts +43 -0
- package/src/provider-plugins.ts +8 -0
- package/src/provider-subject.ts +41 -0
- package/src/provider.ts +315 -0
- package/src/providers/beeper-local-runtime.ts +5426 -0
- package/src/providers/beeper-local.ts +2739 -0
- package/src/providers/beeper-messaging.ts +462 -0
- package/src/providers/beeper-omni.ts +1159 -0
- package/src/providers/bluesky-web-runtime.ts +2895 -0
- package/src/providers/bluesky-web.ts +1614 -0
- package/src/providers/clasificados-web-runtime.ts +255 -0
- package/src/providers/clasificados-web.ts +503 -0
- package/src/providers/contact-projection.ts +301 -0
- package/src/providers/github-read-model.ts +94 -0
- package/src/providers/github-read-platform.ts +165 -0
- package/src/providers/github-read-program.ts +97 -0
- package/src/providers/github-web-runtime.ts +320 -0
- package/src/providers/github-web.ts +403 -0
- package/src/providers/gmail-api.ts +2834 -0
- package/src/providers/gmail-omni.ts +830 -0
- package/src/providers/gmail.ts +1130 -0
- package/src/providers/hacker-news-web-runtime.ts +220 -0
- package/src/providers/hacker-news-web.ts +809 -0
- package/src/providers/imessage-direct-install.ts +354 -0
- package/src/providers/imessage-direct-messaging.ts +532 -0
- package/src/providers/imessage-direct-omni.ts +400 -0
- package/src/providers/imessage-direct-runtime.ts +1498 -0
- package/src/providers/imessage-direct.ts +351 -0
- package/src/providers/instagram-video-foundations.ts +913 -0
- package/src/providers/instagram-web-profile-browser.ts +600 -0
- package/src/providers/iso-bmff.ts +338 -0
- package/src/providers/linkedin-company-platform.ts +42 -0
- package/src/providers/linkedin-company-program.ts +88 -0
- package/src/providers/linkedin-contact-failure.ts +84 -0
- package/src/providers/linkedin-contact-platform.ts +45 -0
- package/src/providers/linkedin-contact-program.ts +91 -0
- package/src/providers/linkedin-profile-activity-failure.ts +76 -0
- package/src/providers/linkedin-profile-activity-platform.ts +41 -0
- package/src/providers/linkedin-profile-activity-program.ts +67 -0
- package/src/providers/linkedin-read-failure.ts +52 -0
- package/src/providers/linkedin-self-platform.ts +53 -0
- package/src/providers/linkedin-self-program.ts +122 -0
- package/src/providers/linkedin-web-article-browser.ts +794 -0
- package/src/providers/linkedin-web-bootstrap.ts +146 -0
- package/src/providers/linkedin-web-contact.ts +830 -0
- package/src/providers/linkedin-web-feed-browser.ts +832 -0
- package/src/providers/linkedin-web-feed.ts +864 -0
- package/src/providers/linkedin-web-post-browser.ts +653 -0
- package/src/providers/linkedin-web-profile-browser.ts +683 -0
- package/src/providers/linkedin-web-runtime.ts +2388 -0
- package/src/providers/linkedin-web.ts +3305 -0
- package/src/providers/linkedin.ts +1885 -0
- package/src/providers/meta-bootstrap.ts +1043 -0
- package/src/providers/meta-facebook-group.ts +690 -0
- package/src/providers/meta-marketplace-relay.ts +747 -0
- package/src/providers/meta-omni.ts +373 -0
- package/src/providers/meta-relay-bundle.ts +1049 -0
- package/src/providers/meta-web-descriptors.ts +1740 -0
- package/src/providers/meta-web-runtime.ts +3388 -0
- package/src/providers/meta-web.ts +2931 -0
- package/src/providers/read-failure.ts +139 -0
- package/src/providers/reddit-omni.ts +462 -0
- package/src/providers/reddit-web-runtime.ts +1929 -0
- package/src/providers/reddit-web.ts +1611 -0
- package/src/providers/rental-listings.ts +460 -0
- package/src/providers/substack-omni.ts +406 -0
- package/src/providers/substack-video-mp4.ts +33 -0
- package/src/providers/substack-web-runtime.ts +2812 -0
- package/src/providers/substack-web.ts +1502 -0
- package/src/providers/tiktok-video-mp4.ts +33 -0
- package/src/providers/tiktok-web-runtime.ts +770 -0
- package/src/providers/tiktok-web.ts +2786 -0
- package/src/providers/twitch-web-runtime.ts +226 -0
- package/src/providers/twitch-web.ts +274 -0
- package/src/providers/whatsapp-account-identity.ts +55 -0
- package/src/providers/whatsapp-contact-projection-helper.ts +874 -0
- package/src/providers/whatsapp-contact-projection-protocol.ts +403 -0
- package/src/providers/whatsapp-interaction-projection-helper.ts +1452 -0
- package/src/providers/whatsapp-interaction-projection-protocol.ts +462 -0
- package/src/providers/whatsapp-message-export-projection-protocol.ts +532 -0
- package/src/providers/whatsapp-messaging.ts +132 -0
- package/src/providers/whatsapp-omni.ts +586 -0
- package/src/providers/whatsapp-web-runtime.ts +3108 -0
- package/src/providers/whatsapp-web.ts +1037 -0
- package/src/providers/x-image-provenance.ts +523 -0
- package/src/providers/x-made-with-ai.ts +106 -0
- package/src/providers/x-transaction-id.ts +413 -0
- package/src/providers/x-web-runtime.ts +3485 -0
- package/src/providers/x-web.ts +2332 -0
- package/src/providers/x.ts +1889 -0
- package/src/providers/youtube-web-runtime.ts +1400 -0
- package/src/providers/youtube-web.ts +1221 -0
- package/src/read-admission-runtime.ts +91 -0
- package/src/read-client.ts +521 -0
- package/src/read-effect-platform.ts +7 -0
- package/src/read-effect-runtime.ts +14 -0
- package/src/read-effect.ts +52 -0
- package/src/read-projection-admission.ts +866 -0
- package/src/read-projections.ts +3151 -0
- package/src/recovery.ts +1492 -0
- package/src/reviewed-template.ts +146 -0
- package/src/run-journal.ts +1272 -0
- package/src/runtime.ts +5116 -0
- package/src/scripts/generate-provider-plugin-catalog.ts +121 -0
- package/src/scripts/install-whatsapp-protocol.sh +232 -0
- package/src/scripts/recover-install-stages.ts +1491 -0
- package/src/scripts/resolve-state-home.ts +30 -0
- package/src/scripts/scaffold-web-provider.ts +973 -0
- package/src/scripts/sync-bundled-adapters.ts +695 -0
- package/src/session-secrets.ts +1183 -0
- package/src/state-helper.bunfig.toml +2 -0
- package/src/state-helper.ts +2914 -0
- package/src/storage.ts +3842 -0
- package/src/transport-policy.ts +2 -0
- package/src/usage.ts +182 -0
- package/src/version.ts +2 -0
- package/src/web-session-authentication-policy.ts +136 -0
- package/src/web-session-cleanup-admission.ts +2344 -0
- package/src/web-session-cleanup-join.ts +99 -0
- package/src/web-session-client.ts +996 -0
- package/src/web-session-contract-definitions.ts +820 -0
- package/src/web-session-contract-planning.ts +42 -0
- package/src/web-session-contracts.ts +228 -0
- package/src/web-session-cookies.ts +500 -0
- package/src/web-session-execution.ts +385 -0
- package/src/web-session-http.ts +373 -0
- package/src/web-session-read-errors.ts +19 -0
- package/src/web-session-read-runtime.ts +124 -0
- package/src/web-session-recovery.ts +818 -0
- package/src/web-session-sites.ts +58 -0
- package/src/web-session-template.ts +994 -0
- package/src/web-session.ts +93 -0
- package/src/whatsapp-client-binding.ts +21 -0
- package/src/whatsapp-client-types.ts +75 -0
- package/src/whatsapp-client.ts +395 -0
- package/src/whatsapp-export-coordinate.ts +17 -0
- package/src/whatsapp-message-bundle-v2.ts +195 -0
- package/src/whatsapp-message-like-me-cli.ts +195 -0
- package/src/whatsapp-message-like-me-export.ts +1072 -0
- package/src/whatsapp-message-like-me-source.ts +1012 -0
- package/tsconfig.json +67 -0
|
@@ -0,0 +1,695 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import {
|
|
3
|
+
chmodSync,
|
|
4
|
+
closeSync,
|
|
5
|
+
constants,
|
|
6
|
+
fstatSync,
|
|
7
|
+
lstatSync,
|
|
8
|
+
mkdtempSync,
|
|
9
|
+
openSync,
|
|
10
|
+
readFileSync,
|
|
11
|
+
readdirSync,
|
|
12
|
+
rmSync,
|
|
13
|
+
writeFileSync,
|
|
14
|
+
type BigIntStats,
|
|
15
|
+
} from "node:fs";
|
|
16
|
+
import { tmpdir } from "node:os";
|
|
17
|
+
import { basename, join } from "node:path";
|
|
18
|
+
|
|
19
|
+
import { main as defaultGhostgetMain, type GhostgetDependencies } from "../ghostget";
|
|
20
|
+
import {
|
|
21
|
+
isLocalCliOperation,
|
|
22
|
+
isProviderOperation,
|
|
23
|
+
isWebSessionOperation,
|
|
24
|
+
manifestHash,
|
|
25
|
+
parseDiagnosticManifest,
|
|
26
|
+
parseRuntimeManifest,
|
|
27
|
+
type GhostgetManifest,
|
|
28
|
+
} from "../model";
|
|
29
|
+
import type { ProviderPluginRegistry } from "../provider-plugin-registry";
|
|
30
|
+
import {
|
|
31
|
+
portableProviderPluginStoreRoot,
|
|
32
|
+
} from "../provider-plugin-lifecycle";
|
|
33
|
+
import {
|
|
34
|
+
createPortableProviderPluginCatalog,
|
|
35
|
+
type PortableProviderPluginCatalog,
|
|
36
|
+
} from "../provider-plugin-portable-catalog";
|
|
37
|
+
import {
|
|
38
|
+
withPortableProviderPluginCatalogLock,
|
|
39
|
+
} from "../provider-plugin-store";
|
|
40
|
+
import { providerPluginRegistry } from "../provider-plugins";
|
|
41
|
+
import {
|
|
42
|
+
adapterManifestPath,
|
|
43
|
+
installBundledAdapterGeneration,
|
|
44
|
+
listInstalledDiagnosticManifestSnapshots,
|
|
45
|
+
type BundledAdapterGenerationSelection,
|
|
46
|
+
} from "../storage";
|
|
47
|
+
|
|
48
|
+
type SyncOutput = {
|
|
49
|
+
readonly stdout: (value: string) => void;
|
|
50
|
+
readonly stderr: (value: string) => void;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
type GhostgetMain = (
|
|
54
|
+
rawArguments: readonly string[],
|
|
55
|
+
environment: Readonly<Record<string, string | undefined>>,
|
|
56
|
+
output: {
|
|
57
|
+
readonly stdout: (value: string) => void;
|
|
58
|
+
readonly stderr: (value: string) => void;
|
|
59
|
+
},
|
|
60
|
+
dependencyOverrides?: Partial<GhostgetDependencies>,
|
|
61
|
+
) => Promise<number>;
|
|
62
|
+
|
|
63
|
+
type GenerationInstaller = (
|
|
64
|
+
selections: readonly BundledAdapterGenerationSelection[],
|
|
65
|
+
environment: Readonly<Record<string, string | undefined>>,
|
|
66
|
+
) => {
|
|
67
|
+
readonly commitId: string;
|
|
68
|
+
readonly installed: number;
|
|
69
|
+
readonly preservedLegacy: number;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
type SourceSnapshot = {
|
|
73
|
+
readonly path: string;
|
|
74
|
+
readonly sourceContentSha256: string;
|
|
75
|
+
readonly bytes: Uint8Array;
|
|
76
|
+
readonly value: unknown;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export type DiscoveredBundledAdapter = {
|
|
80
|
+
readonly id: string;
|
|
81
|
+
readonly current: SourceSnapshot & { readonly manifest: GhostgetManifest };
|
|
82
|
+
readonly upgradeFrom: readonly (
|
|
83
|
+
SourceSnapshot & { readonly manifest: GhostgetManifest }
|
|
84
|
+
)[];
|
|
85
|
+
readonly routeKey: string;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const defaultOutput: SyncOutput = {
|
|
89
|
+
stdout: (value) => process.stdout.write(value),
|
|
90
|
+
stderr: (value) => process.stderr.write(value),
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const defaultAssetsDirectory = join(
|
|
94
|
+
import.meta.dir,
|
|
95
|
+
"..",
|
|
96
|
+
"assets",
|
|
97
|
+
"adapters",
|
|
98
|
+
);
|
|
99
|
+
const maximumSourceBytes = 1024 * 1024;
|
|
100
|
+
const currentManifestNames = new Set([
|
|
101
|
+
"wrench-adapter.json",
|
|
102
|
+
"wrench-web-adapter.json",
|
|
103
|
+
]);
|
|
104
|
+
const archivedManifestNamePattern =
|
|
105
|
+
/^(wrench(?:-web)?-adapter)\.v[0-9]+\.[0-9]+\.[0-9]+\.json$/u;
|
|
106
|
+
|
|
107
|
+
function sha256(value: Uint8Array | string): string {
|
|
108
|
+
return createHash("sha256").update(value).digest("hex");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function portableCatalogFingerprint(
|
|
112
|
+
catalog: PortableProviderPluginCatalog,
|
|
113
|
+
): string {
|
|
114
|
+
const identities = catalog.installed.map((entry) => ({
|
|
115
|
+
pluginId: entry.active.pluginId,
|
|
116
|
+
pluginVersion: entry.active.pluginVersion,
|
|
117
|
+
bundleSha256: entry.active.bundleSha256,
|
|
118
|
+
manifestSha256: entry.package.manifestSha256,
|
|
119
|
+
status: entry.active.status,
|
|
120
|
+
activatedAt: entry.active.activatedAt,
|
|
121
|
+
...(entry.active.status === "disabled"
|
|
122
|
+
? { disabledAt: entry.active.disabledAt }
|
|
123
|
+
: {}),
|
|
124
|
+
trustedAt: entry.trust.trustedAt,
|
|
125
|
+
})).sort((left, right) =>
|
|
126
|
+
left.pluginId.localeCompare(right.pluginId)
|
|
127
|
+
|| left.bundleSha256.localeCompare(right.bundleSha256));
|
|
128
|
+
return sha256(JSON.stringify(identities));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function sameFileIdentity(left: BigIntStats, right: BigIntStats): boolean {
|
|
132
|
+
return left.dev === right.dev
|
|
133
|
+
&& left.ino === right.ino
|
|
134
|
+
&& left.size === right.size
|
|
135
|
+
&& left.mode === right.mode
|
|
136
|
+
&& left.mtimeNs === right.mtimeNs
|
|
137
|
+
&& left.ctimeNs === right.ctimeNs;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function readSourceSnapshot(path: string): SourceSnapshot {
|
|
141
|
+
const lexical = lstatSync(path, { bigint: true });
|
|
142
|
+
if (lexical.isSymbolicLink() || !lexical.isFile()) {
|
|
143
|
+
throw new Error(`bundled adapter source is not a real regular file: ${path}`);
|
|
144
|
+
}
|
|
145
|
+
if (lexical.size > BigInt(maximumSourceBytes)) {
|
|
146
|
+
throw new Error(`bundled adapter source exceeds ${maximumSourceBytes} bytes: ${path}`);
|
|
147
|
+
}
|
|
148
|
+
const descriptor = openSync(
|
|
149
|
+
path,
|
|
150
|
+
constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0),
|
|
151
|
+
);
|
|
152
|
+
try {
|
|
153
|
+
const before = fstatSync(descriptor, { bigint: true });
|
|
154
|
+
if (
|
|
155
|
+
!before.isFile()
|
|
156
|
+
|| !sameFileIdentity(lexical, before)
|
|
157
|
+
|| before.size > BigInt(maximumSourceBytes)
|
|
158
|
+
) {
|
|
159
|
+
throw new Error(`bundled adapter source changed before snapshot: ${path}`);
|
|
160
|
+
}
|
|
161
|
+
const bytes = readFileSync(descriptor);
|
|
162
|
+
const after = fstatSync(descriptor, { bigint: true });
|
|
163
|
+
const finalLexical = lstatSync(path, { bigint: true });
|
|
164
|
+
if (
|
|
165
|
+
bytes.byteLength > maximumSourceBytes
|
|
166
|
+
|| !sameFileIdentity(before, after)
|
|
167
|
+
|| !sameFileIdentity(after, finalLexical)
|
|
168
|
+
) {
|
|
169
|
+
throw new Error(`bundled adapter source changed while being snapshotted: ${path}`);
|
|
170
|
+
}
|
|
171
|
+
let text: string;
|
|
172
|
+
try {
|
|
173
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
174
|
+
} catch (error) {
|
|
175
|
+
throw new Error(`bundled adapter source is not valid UTF-8: ${path}`, {
|
|
176
|
+
cause: error,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
let value: unknown;
|
|
180
|
+
try {
|
|
181
|
+
value = JSON.parse(text) as unknown;
|
|
182
|
+
} catch (error) {
|
|
183
|
+
throw new Error(`bundled adapter source is not valid JSON: ${path}`, {
|
|
184
|
+
cause: error,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
return Object.freeze({
|
|
188
|
+
path,
|
|
189
|
+
sourceContentSha256: sha256(bytes),
|
|
190
|
+
bytes: Uint8Array.from(bytes),
|
|
191
|
+
value,
|
|
192
|
+
});
|
|
193
|
+
} finally {
|
|
194
|
+
closeSync(descriptor);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function routeKey(transport: string, surfaceId: string): string {
|
|
199
|
+
return `${transport}:${surfaceId}`;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function manifestRouteKey(
|
|
203
|
+
manifest: GhostgetManifest,
|
|
204
|
+
registry: ProviderPluginRegistry,
|
|
205
|
+
): string {
|
|
206
|
+
if (manifest.surfaceId === undefined) {
|
|
207
|
+
throw new Error(`bundled adapter ${manifest.id} has no provider surface`);
|
|
208
|
+
}
|
|
209
|
+
const operations = Object.entries(manifest.operations);
|
|
210
|
+
const usesProviderApi = operations.every(([, operation]) =>
|
|
211
|
+
isProviderOperation(operation)
|
|
212
|
+
);
|
|
213
|
+
const usesSessionApi = operations.every(([, operation]) =>
|
|
214
|
+
isWebSessionOperation(operation)
|
|
215
|
+
);
|
|
216
|
+
const usesLocalCli = operations.every(([, operation]) =>
|
|
217
|
+
isLocalCliOperation(operation)
|
|
218
|
+
);
|
|
219
|
+
if (!usesProviderApi && !usesSessionApi && !usesLocalCli) {
|
|
220
|
+
throw new Error(`bundled adapter ${manifest.id} mixes provider transports`);
|
|
221
|
+
}
|
|
222
|
+
const candidates = registry.list().flatMap((plugin) =>
|
|
223
|
+
plugin.bindings.filter((binding) => {
|
|
224
|
+
if (binding.surfaceId !== manifest.surfaceId) return false;
|
|
225
|
+
if (
|
|
226
|
+
(usesProviderApi && binding.transport !== "provider-api")
|
|
227
|
+
|| (
|
|
228
|
+
usesSessionApi
|
|
229
|
+
&& binding.transport !== "web-session-api"
|
|
230
|
+
&& binding.transport !== "linked-device"
|
|
231
|
+
)
|
|
232
|
+
|| (usesLocalCli && binding.transport !== "local-cli")
|
|
233
|
+
) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
return operations.every(
|
|
237
|
+
([operationId, operation]) => {
|
|
238
|
+
if (
|
|
239
|
+
!isProviderOperation(operation)
|
|
240
|
+
&& !isWebSessionOperation(operation)
|
|
241
|
+
&& !isLocalCliOperation(operation)
|
|
242
|
+
) {
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
const contractVersion = isProviderOperation(operation)
|
|
246
|
+
? operation.provider.contractVersion
|
|
247
|
+
: isWebSessionOperation(operation)
|
|
248
|
+
? operation.webSession.contractVersion
|
|
249
|
+
: operation.localCli.contractVersion;
|
|
250
|
+
return registry.resolveOperationDefinition(
|
|
251
|
+
binding.transport,
|
|
252
|
+
binding.surfaceId,
|
|
253
|
+
operationId,
|
|
254
|
+
contractVersion,
|
|
255
|
+
) !== undefined;
|
|
256
|
+
},
|
|
257
|
+
);
|
|
258
|
+
})
|
|
259
|
+
);
|
|
260
|
+
if (candidates.length !== 1) {
|
|
261
|
+
throw new Error(
|
|
262
|
+
`bundled adapter ${manifest.id} does not resolve to exactly one provider plugin binding`,
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
return routeKey(candidates[0]!.transport, candidates[0]!.surfaceId);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Discover the distribution inventory from assets, then prove inverse parity
|
|
270
|
+
* with the built-in provider registry. Neither side can silently add a route.
|
|
271
|
+
*/
|
|
272
|
+
export function discoverBundledAdapters(
|
|
273
|
+
assetsDirectory: string = defaultAssetsDirectory,
|
|
274
|
+
registry: ProviderPluginRegistry = providerPluginRegistry,
|
|
275
|
+
): readonly DiscoveredBundledAdapter[] {
|
|
276
|
+
const rootStats = lstatSync(assetsDirectory);
|
|
277
|
+
if (rootStats.isSymbolicLink() || !rootStats.isDirectory()) {
|
|
278
|
+
throw new Error("bundled adapter asset root must be a real directory");
|
|
279
|
+
}
|
|
280
|
+
const discovered: DiscoveredBundledAdapter[] = [];
|
|
281
|
+
const surfaceEntries = readdirSync(assetsDirectory, {
|
|
282
|
+
withFileTypes: true,
|
|
283
|
+
}).sort((left, right) => left.name.localeCompare(right.name));
|
|
284
|
+
for (const surfaceEntry of surfaceEntries) {
|
|
285
|
+
if (surfaceEntry.isSymbolicLink() || !surfaceEntry.isDirectory()) {
|
|
286
|
+
throw new Error(
|
|
287
|
+
`bundled adapter asset root contains an unsafe entry: ${surfaceEntry.name}`,
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
const surfaceDirectory = join(assetsDirectory, surfaceEntry.name);
|
|
291
|
+
const surfaceStats = lstatSync(surfaceDirectory);
|
|
292
|
+
if (surfaceStats.isSymbolicLink() || !surfaceStats.isDirectory()) {
|
|
293
|
+
throw new Error(`bundled adapter surface is not a real directory: ${surfaceEntry.name}`);
|
|
294
|
+
}
|
|
295
|
+
const files = readdirSync(surfaceDirectory, {
|
|
296
|
+
withFileTypes: true,
|
|
297
|
+
}).sort((left, right) => left.name.localeCompare(right.name));
|
|
298
|
+
for (const file of files) {
|
|
299
|
+
if (file.isSymbolicLink()) {
|
|
300
|
+
throw new Error(
|
|
301
|
+
`bundled adapter surface contains a symbolic link: ${surfaceEntry.name}/${file.name}`,
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
const currentFiles = files.filter(
|
|
306
|
+
(file) => file.isFile() && currentManifestNames.has(file.name),
|
|
307
|
+
);
|
|
308
|
+
if (currentFiles.length === 0) {
|
|
309
|
+
throw new Error(`bundled adapter surface has no current manifest: ${surfaceEntry.name}`);
|
|
310
|
+
}
|
|
311
|
+
for (const currentFile of currentFiles) {
|
|
312
|
+
const current = readSourceSnapshot(
|
|
313
|
+
join(surfaceDirectory, currentFile.name),
|
|
314
|
+
);
|
|
315
|
+
const currentParsed = parseRuntimeManifest(current.value, registry);
|
|
316
|
+
if (!currentParsed.ok) {
|
|
317
|
+
throw new Error(
|
|
318
|
+
`bundled adapter ${currentFile.name} is invalid: ${currentParsed.issues.join("; ")}`,
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
const currentStem = currentFile.name.slice(0, -".json".length);
|
|
322
|
+
const archived = files.filter((file) => {
|
|
323
|
+
const match = archivedManifestNamePattern.exec(file.name);
|
|
324
|
+
return file.isFile() && match?.[1] === currentStem;
|
|
325
|
+
}).map((file) => {
|
|
326
|
+
const snapshot = readSourceSnapshot(join(surfaceDirectory, file.name));
|
|
327
|
+
const parsed = parseDiagnosticManifest(snapshot.value, registry);
|
|
328
|
+
if (!parsed.ok) {
|
|
329
|
+
throw new Error(
|
|
330
|
+
`bundled adapter baseline ${file.name} is invalid: ${parsed.issues.join("; ")}`,
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
if (parsed.value.id !== currentParsed.value.id) {
|
|
334
|
+
throw new Error(
|
|
335
|
+
`bundled adapter baseline ${file.name} has the wrong adapter ID`,
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
return Object.freeze({ ...snapshot, manifest: parsed.value });
|
|
339
|
+
});
|
|
340
|
+
const archivedHashes = archived.map((entry) =>
|
|
341
|
+
manifestHash(entry.manifest)
|
|
342
|
+
);
|
|
343
|
+
if (new Set(archivedHashes).size !== archivedHashes.length) {
|
|
344
|
+
throw new Error(
|
|
345
|
+
`bundled adapter ${currentParsed.value.id} has duplicate upgrade baselines`,
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
discovered.push(Object.freeze({
|
|
349
|
+
id: currentParsed.value.id,
|
|
350
|
+
current: Object.freeze({
|
|
351
|
+
...current,
|
|
352
|
+
manifest: currentParsed.value,
|
|
353
|
+
}),
|
|
354
|
+
upgradeFrom: Object.freeze(archived),
|
|
355
|
+
routeKey: manifestRouteKey(currentParsed.value, registry),
|
|
356
|
+
}));
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
discovered.sort((left, right) => left.id.localeCompare(right.id));
|
|
360
|
+
const ids = discovered.map((adapter) => adapter.id);
|
|
361
|
+
const routes = discovered.map((adapter) => adapter.routeKey);
|
|
362
|
+
if (new Set(ids).size !== ids.length) {
|
|
363
|
+
throw new Error("bundled adapter inventory contains duplicate IDs");
|
|
364
|
+
}
|
|
365
|
+
if (new Set(routes).size !== routes.length) {
|
|
366
|
+
throw new Error("bundled adapter inventory contains duplicate provider routes");
|
|
367
|
+
}
|
|
368
|
+
const expectedRoutes = registry.list().flatMap((plugin) =>
|
|
369
|
+
plugin.bindings.map((binding) =>
|
|
370
|
+
routeKey(binding.transport, binding.surfaceId)
|
|
371
|
+
)
|
|
372
|
+
).sort();
|
|
373
|
+
const actualRoutes = [...routes].sort();
|
|
374
|
+
if (
|
|
375
|
+
expectedRoutes.length !== actualRoutes.length
|
|
376
|
+
|| expectedRoutes.some((route, index) => route !== actualRoutes[index])
|
|
377
|
+
) {
|
|
378
|
+
throw new Error(
|
|
379
|
+
`bundled adapter inventory and provider plugin registry differ (assets: ${actualRoutes.join(", ")}; registry: ${expectedRoutes.join(", ")})`,
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
return Object.freeze(discovered);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function captureOutput(): {
|
|
386
|
+
readonly output: SyncOutput;
|
|
387
|
+
readonly stdout: () => string;
|
|
388
|
+
readonly stderr: () => string;
|
|
389
|
+
} {
|
|
390
|
+
let stdout = "";
|
|
391
|
+
let stderr = "";
|
|
392
|
+
return {
|
|
393
|
+
output: {
|
|
394
|
+
stdout: (value) => { stdout += value; },
|
|
395
|
+
stderr: (value) => { stderr += value; },
|
|
396
|
+
},
|
|
397
|
+
stdout: () => stdout,
|
|
398
|
+
stderr: () => stderr,
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
function compactDetail(value: string): string {
|
|
403
|
+
return value.trim().slice(0, 4_096);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
async function validateSnapshotWithCli(
|
|
407
|
+
adapter: DiscoveredBundledAdapter,
|
|
408
|
+
stagedPath: string,
|
|
409
|
+
environment: Readonly<Record<string, string | undefined>>,
|
|
410
|
+
ghostgetMain: GhostgetMain,
|
|
411
|
+
registry: ProviderPluginRegistry,
|
|
412
|
+
): Promise<void> {
|
|
413
|
+
const captured = captureOutput();
|
|
414
|
+
const status = await ghostgetMain(
|
|
415
|
+
["adapter", "validate", stagedPath, "--json"],
|
|
416
|
+
environment,
|
|
417
|
+
captured.output,
|
|
418
|
+
{ providerPluginRegistry: registry },
|
|
419
|
+
);
|
|
420
|
+
if (status !== 0) {
|
|
421
|
+
const detail = compactDetail(captured.stderr() || captured.stdout());
|
|
422
|
+
throw new Error(
|
|
423
|
+
`bundled ${adapter.id} adapter failed validation${detail === "" ? "" : `: ${detail}`}`,
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
let response: unknown;
|
|
427
|
+
try {
|
|
428
|
+
response = JSON.parse(captured.stdout()) as unknown;
|
|
429
|
+
} catch {
|
|
430
|
+
throw new Error(`bundled ${adapter.id} adapter validation returned malformed JSON`);
|
|
431
|
+
}
|
|
432
|
+
if (
|
|
433
|
+
typeof response !== "object"
|
|
434
|
+
|| response === null
|
|
435
|
+
|| !("ok" in response)
|
|
436
|
+
|| response.ok !== true
|
|
437
|
+
|| !("id" in response)
|
|
438
|
+
|| response.id !== adapter.id
|
|
439
|
+
|| !("manifestHash" in response)
|
|
440
|
+
|| response.manifestHash !== manifestHash(adapter.current.manifest)
|
|
441
|
+
) {
|
|
442
|
+
throw new Error(
|
|
443
|
+
`bundled ${adapter.id} adapter validation returned the wrong identity`,
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function publishBundledAdapterGeneration(
|
|
449
|
+
bundledAdapters: readonly DiscoveredBundledAdapter[],
|
|
450
|
+
environment: Readonly<Record<string, string | undefined>>,
|
|
451
|
+
output: SyncOutput,
|
|
452
|
+
registry: ProviderPluginRegistry,
|
|
453
|
+
installGeneration?: GenerationInstaller,
|
|
454
|
+
): {
|
|
455
|
+
readonly installed: number;
|
|
456
|
+
readonly preserved: number;
|
|
457
|
+
readonly commitId: string;
|
|
458
|
+
} {
|
|
459
|
+
const portableAdapterIds = new Set(
|
|
460
|
+
registry.listOwnedManifests().map((manifest) =>
|
|
461
|
+
manifest.id
|
|
462
|
+
),
|
|
463
|
+
);
|
|
464
|
+
const collision = bundledAdapters.find((adapter) =>
|
|
465
|
+
portableAdapterIds.has(adapter.id)
|
|
466
|
+
);
|
|
467
|
+
if (collision !== undefined) {
|
|
468
|
+
throw new Error(
|
|
469
|
+
`bundled adapter ${collision.id} is owned by an enabled portable provider plugin`,
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const selections: BundledAdapterGenerationSelection[] = [];
|
|
474
|
+
const preservedIds: string[] = [];
|
|
475
|
+
const repairedIds: string[] = [];
|
|
476
|
+
let installed = 0;
|
|
477
|
+
const installedSnapshots = new Map(
|
|
478
|
+
listInstalledDiagnosticManifestSnapshots(environment, registry).map((entry) =>
|
|
479
|
+
[entry.id, entry.snapshot] as const
|
|
480
|
+
),
|
|
481
|
+
);
|
|
482
|
+
for (const adapter of bundledAdapters) {
|
|
483
|
+
const snapshot = installedSnapshots.get(adapter.id) ?? {
|
|
484
|
+
result: {
|
|
485
|
+
ok: false as const,
|
|
486
|
+
issues: [`adapter ${adapter.id} is not installed`],
|
|
487
|
+
},
|
|
488
|
+
availability: "absent" as const,
|
|
489
|
+
contentSha256: null,
|
|
490
|
+
};
|
|
491
|
+
if (snapshot.availability === "unsafe") {
|
|
492
|
+
const detail = snapshot.result.ok
|
|
493
|
+
? "unsafe installed-state snapshot"
|
|
494
|
+
: snapshot.result.issues.join("; ");
|
|
495
|
+
throw new Error(
|
|
496
|
+
`installed adapter ${adapter.id} cannot be snapshotted safely: ${detail}`,
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
if (snapshot.availability === "absent") {
|
|
500
|
+
selections.push({
|
|
501
|
+
id: adapter.id,
|
|
502
|
+
state: "present",
|
|
503
|
+
manifest: adapter.current.manifest,
|
|
504
|
+
sourceContentSha256: adapter.current.sourceContentSha256,
|
|
505
|
+
expectedCurrentContentSha256: null,
|
|
506
|
+
});
|
|
507
|
+
installed += 1;
|
|
508
|
+
continue;
|
|
509
|
+
}
|
|
510
|
+
if (!snapshot.result.ok) {
|
|
511
|
+
selections.push({
|
|
512
|
+
id: adapter.id,
|
|
513
|
+
state: "legacy",
|
|
514
|
+
expectedCurrentContentSha256: snapshot.contentSha256,
|
|
515
|
+
});
|
|
516
|
+
preservedIds.push(adapter.id);
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
const installedManifest = snapshot.result.value;
|
|
520
|
+
const installedHash = manifestHash(installedManifest);
|
|
521
|
+
const acceptedHashes = new Set([
|
|
522
|
+
manifestHash(adapter.current.manifest),
|
|
523
|
+
...adapter.upgradeFrom.map((baseline) =>
|
|
524
|
+
manifestHash(baseline.manifest)
|
|
525
|
+
),
|
|
526
|
+
]);
|
|
527
|
+
const installedOlderGeneration = adapter.upgradeFrom.some((baseline) =>
|
|
528
|
+
baseline.manifest.version === installedManifest.version
|
|
529
|
+
);
|
|
530
|
+
if (acceptedHashes.has(installedHash) || installedOlderGeneration) {
|
|
531
|
+
selections.push({
|
|
532
|
+
id: adapter.id,
|
|
533
|
+
state: "present",
|
|
534
|
+
manifest: adapter.current.manifest,
|
|
535
|
+
sourceContentSha256: adapter.current.sourceContentSha256,
|
|
536
|
+
expectedCurrentContentSha256: snapshot.contentSha256,
|
|
537
|
+
});
|
|
538
|
+
installed += 1;
|
|
539
|
+
continue;
|
|
540
|
+
}
|
|
541
|
+
const runtime = parseRuntimeManifest(installedManifest, registry);
|
|
542
|
+
if (!runtime.ok) {
|
|
543
|
+
selections.push({
|
|
544
|
+
id: adapter.id,
|
|
545
|
+
state: "present",
|
|
546
|
+
manifest: adapter.current.manifest,
|
|
547
|
+
sourceContentSha256: adapter.current.sourceContentSha256,
|
|
548
|
+
expectedCurrentContentSha256: snapshot.contentSha256,
|
|
549
|
+
});
|
|
550
|
+
repairedIds.push(adapter.id);
|
|
551
|
+
installed += 1;
|
|
552
|
+
continue;
|
|
553
|
+
}
|
|
554
|
+
if (snapshot.contentSha256 === null) {
|
|
555
|
+
throw new Error(`installed adapter ${adapter.id} omitted its content hash`);
|
|
556
|
+
}
|
|
557
|
+
selections.push({
|
|
558
|
+
id: adapter.id,
|
|
559
|
+
state: "present",
|
|
560
|
+
manifest: installedManifest,
|
|
561
|
+
sourceContentSha256: snapshot.contentSha256,
|
|
562
|
+
expectedCurrentContentSha256: snapshot.contentSha256,
|
|
563
|
+
});
|
|
564
|
+
preservedIds.push(adapter.id);
|
|
565
|
+
}
|
|
566
|
+
const generation = (
|
|
567
|
+
installGeneration
|
|
568
|
+
?? ((value, targetEnvironment) =>
|
|
569
|
+
installBundledAdapterGeneration(
|
|
570
|
+
value,
|
|
571
|
+
targetEnvironment,
|
|
572
|
+
{ registry },
|
|
573
|
+
))
|
|
574
|
+
)(selections, environment);
|
|
575
|
+
for (const adapter of bundledAdapters) {
|
|
576
|
+
if (preservedIds.includes(adapter.id)) continue;
|
|
577
|
+
output.stdout(
|
|
578
|
+
`Installed ${adapter.id} at ${adapterManifestPath(adapter.id, environment)}.\n`,
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
for (const id of preservedIds) {
|
|
582
|
+
output.stderr(
|
|
583
|
+
`ghostget installer: preserved the installed ${id} adapter because it differs from the bundled version; inspect it or replace it with ghostget adapter install of this release's bundled manifest and --force\n`,
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
for (const id of repairedIds) {
|
|
587
|
+
output.stderr(
|
|
588
|
+
`ghostget installer: repaired the incompatible installed ${id} adapter with this Ghostget release's bundled contract; reinstall a newer Ghostget release to restore newer contracts\n`,
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
return Object.freeze({
|
|
592
|
+
installed,
|
|
593
|
+
preserved: preservedIds.length,
|
|
594
|
+
commitId: generation.commitId,
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
export async function syncBundledAdapters(
|
|
599
|
+
options: {
|
|
600
|
+
readonly environment?: Readonly<Record<string, string | undefined>>;
|
|
601
|
+
readonly output?: SyncOutput;
|
|
602
|
+
readonly ghostgetMain?: GhostgetMain;
|
|
603
|
+
readonly installGeneration?: GenerationInstaller;
|
|
604
|
+
readonly assetsDirectory?: string;
|
|
605
|
+
readonly registry?: ProviderPluginRegistry;
|
|
606
|
+
} = {},
|
|
607
|
+
): Promise<{
|
|
608
|
+
readonly installed: number;
|
|
609
|
+
readonly preserved: number;
|
|
610
|
+
readonly commitId: string;
|
|
611
|
+
}> {
|
|
612
|
+
const environment = options.environment ?? process.env;
|
|
613
|
+
const output = options.output ?? defaultOutput;
|
|
614
|
+
const ghostgetMain = options.ghostgetMain ?? defaultGhostgetMain;
|
|
615
|
+
const registry = options.registry ?? providerPluginRegistry;
|
|
616
|
+
const bundledAdapters = discoverBundledAdapters(
|
|
617
|
+
options.assetsDirectory ?? defaultAssetsDirectory,
|
|
618
|
+
registry,
|
|
619
|
+
);
|
|
620
|
+
|
|
621
|
+
const stagingDirectory = mkdtempSync(
|
|
622
|
+
join(tmpdir(), "wrench-bundled-adapters-"),
|
|
623
|
+
);
|
|
624
|
+
chmodSync(stagingDirectory, 0o700);
|
|
625
|
+
try {
|
|
626
|
+
for (const [index, adapter] of bundledAdapters.entries()) {
|
|
627
|
+
const stagedPath = join(
|
|
628
|
+
stagingDirectory,
|
|
629
|
+
`${String(index).padStart(4, "0")}-${basename(adapter.current.path)}`,
|
|
630
|
+
);
|
|
631
|
+
writeFileSync(stagedPath, adapter.current.bytes, {
|
|
632
|
+
flag: "wx",
|
|
633
|
+
mode: 0o600,
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
const storeRoot = portableProviderPluginStoreRoot(environment);
|
|
637
|
+
const initialCatalog = withPortableProviderPluginCatalogLock(
|
|
638
|
+
storeRoot,
|
|
639
|
+
new Date(),
|
|
640
|
+
() => createPortableProviderPluginCatalog(registry, environment),
|
|
641
|
+
);
|
|
642
|
+
const initialCatalogFingerprint =
|
|
643
|
+
portableCatalogFingerprint(initialCatalog);
|
|
644
|
+
for (const [index, adapter] of bundledAdapters.entries()) {
|
|
645
|
+
const stagedPath = join(
|
|
646
|
+
stagingDirectory,
|
|
647
|
+
`${String(index).padStart(4, "0")}-${basename(adapter.current.path)}`,
|
|
648
|
+
);
|
|
649
|
+
await validateSnapshotWithCli(
|
|
650
|
+
adapter,
|
|
651
|
+
stagedPath,
|
|
652
|
+
environment,
|
|
653
|
+
ghostgetMain,
|
|
654
|
+
initialCatalog.registry,
|
|
655
|
+
);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
return withPortableProviderPluginCatalogLock(
|
|
659
|
+
storeRoot,
|
|
660
|
+
new Date(),
|
|
661
|
+
() => {
|
|
662
|
+
const currentCatalog =
|
|
663
|
+
createPortableProviderPluginCatalog(registry, environment);
|
|
664
|
+
if (
|
|
665
|
+
portableCatalogFingerprint(currentCatalog)
|
|
666
|
+
!== initialCatalogFingerprint
|
|
667
|
+
) {
|
|
668
|
+
throw new Error(
|
|
669
|
+
"portable provider plugin catalog changed during bundled adapter validation; retry installation",
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
return publishBundledAdapterGeneration(
|
|
673
|
+
bundledAdapters,
|
|
674
|
+
environment,
|
|
675
|
+
output,
|
|
676
|
+
currentCatalog.registry,
|
|
677
|
+
options.installGeneration,
|
|
678
|
+
);
|
|
679
|
+
},
|
|
680
|
+
);
|
|
681
|
+
} finally {
|
|
682
|
+
rmSync(stagingDirectory, { recursive: true, force: true });
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
if (import.meta.main) {
|
|
687
|
+
try {
|
|
688
|
+
await syncBundledAdapters();
|
|
689
|
+
} catch (error) {
|
|
690
|
+
process.stderr.write(
|
|
691
|
+
`ghostget installer: ${error instanceof Error ? error.message : "unknown bundled adapter sync failure"}\n`,
|
|
692
|
+
);
|
|
693
|
+
process.exitCode = 1;
|
|
694
|
+
}
|
|
695
|
+
}
|