@hraness/ghostget 0.17.6 → 0.18.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 +301 -0
- package/README.md +16 -9
- package/dist/apple-photos-client.js +2 -1
- package/dist/beeper-client.js +2 -1
- package/dist/client.js +1 -0
- package/dist/imessage-direct-install-2gm3kge7.js +324 -0
- package/dist/index-01eeae9e.js +5 -0
- package/dist/index-2ymnp8xv.js +145 -0
- package/dist/index-en5hycxp.js +175 -0
- package/dist/{index-cytf8d9p.js → index-hfbygww8.js} +1 -1
- package/dist/index-n4szk3nw.js +50 -0
- package/dist/index-yq6maz71.js +1105 -0
- package/dist/index-z1w83f81.js +4 -0
- package/dist/index.js +4 -47
- package/dist/messaging-automation-api.js +21 -0
- package/dist/messaging-automation-j4274hvc.js +609 -0
- package/dist/messaging-native-install-8w1j36ah.js +16 -0
- package/dist/messaging.js +1 -0
- package/dist/omni-client.js +1 -0
- package/dist/whatsapp-automation-runtime-hgh1e9rm.js +845 -0
- package/dist/whatsapp-client.js +1 -0
- package/docs/control-panel.md +147 -0
- package/docs/imessage-direct-provider.md +31 -7
- package/docs/messaging-automation.md +103 -0
- package/package.json +66 -7
- package/skills/ghostget/SKILL.md +3 -1
- package/skills/ghostget/references/control-panel.md +43 -0
- package/skills/ghostget/references/install.md +5 -5
- package/skills/ghostget/references/linkedin-adapter.md +222 -12
- package/skills/ghostget/references/platform-patterns.md +1 -1
- package/src/args.ts +18 -5
- package/src/assets/adapters/imessage/wrench-web-adapter.json +126 -0
- package/src/assets/adapters/linkedin/wrench-web-adapter.json +1 -1
- package/src/assets/adapters/whatsapp/wrench-web-adapter.json +144 -0
- package/src/assets/messaging-runtime/NOTICE.txt +2580 -0
- package/src/assets/messaging-runtime/imsg-darwin-arm64.gz +0 -0
- package/src/assets/messaging-runtime/phone-number-info.plist.gz +0 -0
- package/src/assets/messaging-runtime/phone-number-metadata.json.gz +0 -0
- package/src/assets/messaging-runtime/phone-number-privacy.plist.gz +0 -0
- package/src/assets/messaging-runtime/wacli-darwin-arm64.gz +0 -0
- package/src/auth.ts +35 -1
- package/src/beeper-client-types.ts +1 -1
- package/src/cli.ts +18 -0
- package/src/confirmed-write-platform.ts +16 -1
- package/src/control/account-revision.ts +16 -0
- package/src/control/activity.ts +104 -0
- package/src/control/approval-broker.ts +59 -0
- package/src/control/approval-client.ts +49 -0
- package/src/control/bundled-interfaces.ts +20 -0
- package/src/control/cli.ts +20 -0
- package/src/control/connections.ts +87 -0
- package/src/control/credential-helper.ts +152 -0
- package/src/control/helper.ts +79 -0
- package/src/control/interface-cli.ts +22 -0
- package/src/control/interface-json.ts +94 -0
- package/src/control/interface-schema.ts +120 -0
- package/src/control/interfaces.ts +438 -0
- package/src/control/protocol.ts +182 -0
- package/src/control/service.ts +104 -0
- package/src/control/validation.ts +103 -0
- package/src/control/vault.ts +105 -0
- package/src/control/web-gateway.ts +62 -0
- package/src/control/web-policy.ts +56 -0
- package/src/ghostget.ts +18 -4
- package/src/messaging-automation-api.ts +12 -0
- package/src/messaging-automation-descriptors.ts +29 -0
- package/src/messaging-automation-factory.ts +148 -0
- package/src/messaging-automation-server.ts +183 -0
- package/src/messaging-automation-types.ts +155 -0
- package/src/messaging-automation-validation.ts +110 -0
- package/src/messaging-automation.ts +356 -0
- package/src/messaging-runtime.ts +3 -0
- package/src/oauth-google.ts +11 -5
- package/src/omni-runtime.ts +18 -3
- package/src/operation-permission-store.ts +92 -0
- package/src/operation-permission.ts +308 -0
- package/src/pinned-https.ts +5 -0
- package/src/plugins/imessage-direct/plugin.ts +12 -1
- package/src/plugins/imessage-direct/vendor/0003-feat-rpc-add-no-fetch-rich-cards.patch +276 -0
- package/src/plugins/imessage-direct/vendor/provenance.json +84 -10
- package/src/plugins/linkedin-web/plugin.ts +1 -1
- package/src/plugins/whatsapp-linked-device/plugin.ts +7 -2
- package/src/plugins/whatsapp-linked-device/vendor/0001-ghostget-private-messaging.patch +1093 -0
- package/src/plugins/whatsapp-linked-device/vendor/README.md +39 -0
- package/src/plugins/whatsapp-linked-device/vendor/provenance.json +45 -0
- package/src/provider-http.ts +11 -3
- package/src/provider-plugin-contract-identity.ts +2 -2
- package/src/provider-plugin-import-analysis.ts +52 -0
- package/src/provider-plugin-module-analysis.ts +21 -1
- package/src/provider-plugin-registry.ts +4 -8
- package/src/provider-plugin.ts +18 -8
- package/src/providers/imessage-automation.ts +250 -0
- package/src/providers/imessage-direct-install.ts +7 -0
- package/src/providers/imessage-direct-runtime.ts +32 -2
- package/src/providers/imessage-direct.ts +13 -3
- package/src/providers/linkedin-contact-failure.ts +21 -0
- package/src/providers/linkedin-contact-platform.ts +8 -1
- package/src/providers/linkedin-contact-program.ts +34 -5
- package/src/providers/linkedin-web-contact.ts +1223 -35
- package/src/providers/linkedin-web-profile-browser.ts +659 -45
- package/src/providers/linkedin-web-runtime.ts +1 -0
- package/src/providers/linkedin-web.ts +46 -2
- package/src/providers/messaging-native-artifacts.ts +38 -0
- package/src/providers/messaging-native-install.ts +75 -0
- package/src/providers/whatsapp-automation-runtime.ts +240 -0
- package/src/providers/whatsapp-automation.ts +153 -0
- package/src/read-client.ts +12 -2
- package/src/runtime.ts +81 -9
- package/src/state-helper.ts +2 -0
- package/src/storage.ts +71 -1
- package/src/usage.ts +9 -1
- package/src/version.ts +1 -1
- package/src/web-session-contract-definitions.ts +1 -1
- package/tsconfig.json +3 -0
|
@@ -891,7 +891,7 @@ function parseMessages(
|
|
|
891
891
|
|
|
892
892
|
function parseSendAccepted(
|
|
893
893
|
value: unknown,
|
|
894
|
-
input:
|
|
894
|
+
input: ImsgChatCoordinate,
|
|
895
895
|
): Readonly<Record<string, unknown>> {
|
|
896
896
|
const source = record(value, "imsg send result");
|
|
897
897
|
exactKeys(source, [
|
|
@@ -1033,6 +1033,9 @@ async function withRuntime<T>(
|
|
|
1033
1033
|
durableCleanupAdmissionRequired: boolean,
|
|
1034
1034
|
operation: (context: Readonly<{
|
|
1035
1035
|
subject: string;
|
|
1036
|
+
sourceGeneration: string;
|
|
1037
|
+
status: unknown;
|
|
1038
|
+
operationRoot: string;
|
|
1036
1039
|
run: (
|
|
1037
1040
|
requests: readonly ImsgRpcRequest[],
|
|
1038
1041
|
beforeSpawn?: () => Promise<void>,
|
|
@@ -1053,6 +1056,11 @@ async function withRuntime<T>(
|
|
|
1053
1056
|
?? join(homedir(), "Library", "Messages");
|
|
1054
1057
|
const store = await validateMessagesStore(auth.path, expectedStorePath);
|
|
1055
1058
|
const subject = subjectForStore(store.storePath);
|
|
1059
|
+
const databaseIdentity = await lstat(store.databasePath, { bigint: true });
|
|
1060
|
+
const sourceGeneration = createHash("sha256").update(canonicalJson({
|
|
1061
|
+
subject, device: String(databaseIdentity.dev), inode: String(databaseIdentity.ino),
|
|
1062
|
+
birthtime: String(databaseIdentity.birthtimeNs),
|
|
1063
|
+
})).digest("hex");
|
|
1056
1064
|
if (auth.subject !== undefined && auth.subject !== subject) {
|
|
1057
1065
|
throw new Error("current Messages device-default realm does not match the bound auth subject");
|
|
1058
1066
|
}
|
|
@@ -1107,7 +1115,12 @@ async function withRuntime<T>(
|
|
|
1107
1115
|
await realpath(reportedDatabasePath) !== reportedDatabasePath
|
|
1108
1116
|
|| reportedDatabasePath !== store.databasePath
|
|
1109
1117
|
) throw new Error("imsg status reported a different Messages database than the bound subject");
|
|
1110
|
-
|
|
1118
|
+
const result = await operation(Object.freeze({ subject, sourceGeneration, status: status.get("status"), operationRoot, run }));
|
|
1119
|
+
const after = await lstat(store.databasePath, { bigint: true });
|
|
1120
|
+
if (after.dev !== databaseIdentity.dev || after.ino !== databaseIdentity.ino || after.birthtimeNs !== databaseIdentity.birthtimeNs || after.isSymbolicLink()) {
|
|
1121
|
+
throw new Error("Messages database generation changed during the operation");
|
|
1122
|
+
}
|
|
1123
|
+
return result;
|
|
1111
1124
|
} finally {
|
|
1112
1125
|
try {
|
|
1113
1126
|
if (operationRoot === undefined) {
|
|
@@ -1137,6 +1150,23 @@ async function withRuntime<T>(
|
|
|
1137
1150
|
}
|
|
1138
1151
|
}
|
|
1139
1152
|
|
|
1153
|
+
/** Internal trusted host seam: retains the pinned executable, exact database,
|
|
1154
|
+
* durable process cleanup and deadline used by the existing provider runtime.
|
|
1155
|
+
* Callers build only reviewed semantic requests; this is never an agent tool. */
|
|
1156
|
+
export async function withImsgAutomationRuntime<T>(
|
|
1157
|
+
auth: GhostgetAuth,
|
|
1158
|
+
options: LocalCliExecutionOptions & Readonly<{ dependencies?: ImsgDirectRuntimeDependencies }>,
|
|
1159
|
+
operation: Parameters<typeof withRuntime<T>>[9],
|
|
1160
|
+
): Promise<T> {
|
|
1161
|
+
if (options.registerCleanupBarrier === undefined) throw new Error("Messaging automation requires durable provider cleanup custody");
|
|
1162
|
+
return startProviderPluginCleanupTrackedOperation(options.registerCleanupBarrier, (publish, cleanup) => withRuntime(
|
|
1163
|
+
requireImsgAuth(auth), 30_000, 10 * 1024 * 1024, options.dependencies,
|
|
1164
|
+
options.environment ?? process.env, options.operationDeadline, publish, cleanup, true, operation,
|
|
1165
|
+
));
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
export const imsgAutomationProjection = Object.freeze({ parseChats, parseChat, parseMessages, parseMessage, exactChat, parseSendAccepted });
|
|
1169
|
+
|
|
1140
1170
|
export async function inspectImsgDirectRuntime(
|
|
1141
1171
|
environment: Readonly<Record<string, string | undefined>>,
|
|
1142
1172
|
): Promise<LocalCliPluginRuntimeStatusV1> {
|
|
@@ -13,7 +13,11 @@ export const IMSG_EXACT_CHAT_PATCH_COMMIT =
|
|
|
13
13
|
"c5994f00d17969fd7772fd2772e7b3591089513a" as const;
|
|
14
14
|
export const IMSG_EXACT_CHAT_PATCH_SHA256 =
|
|
15
15
|
"b05aa92a078930f96fda611c674436638843f7b148d7bfa3b65ed1ccb0885c13" as const;
|
|
16
|
-
export const
|
|
16
|
+
export const IMSG_NO_FETCH_RICH_CARDS_PATCH_COMMIT =
|
|
17
|
+
"520b82ab025c1d4d57333b552aa65c9ae3fdb5fd" as const;
|
|
18
|
+
export const IMSG_NO_FETCH_RICH_CARDS_PATCH_SHA256 =
|
|
19
|
+
"c2346afca4dd0f9721c235db4f692d6a2d6dece36481e074d94b5ce78f2e019b" as const;
|
|
20
|
+
export const IMSG_REVIEWED_PATCH_COMMIT = IMSG_NO_FETCH_RICH_CARDS_PATCH_COMMIT;
|
|
17
21
|
export const IMSG_REVIEWED_PATCHES = Object.freeze([
|
|
18
22
|
Object.freeze({
|
|
19
23
|
commit: IMSG_PRIVATE_TRANSPORT_PATCH_COMMIT,
|
|
@@ -23,11 +27,17 @@ export const IMSG_REVIEWED_PATCHES = Object.freeze([
|
|
|
23
27
|
commit: IMSG_EXACT_CHAT_PATCH_COMMIT,
|
|
24
28
|
sha256: IMSG_EXACT_CHAT_PATCH_SHA256,
|
|
25
29
|
}),
|
|
30
|
+
Object.freeze({
|
|
31
|
+
commit: IMSG_NO_FETCH_RICH_CARDS_PATCH_COMMIT,
|
|
32
|
+
sha256: IMSG_NO_FETCH_RICH_CARDS_PATCH_SHA256,
|
|
33
|
+
}),
|
|
26
34
|
]);
|
|
27
35
|
export const IMSG_REVIEWED_VERSION =
|
|
28
|
-
"0.14.1+private-transport.
|
|
36
|
+
"0.14.1+private-transport.3" as const;
|
|
29
37
|
export const IMSG_DARWIN_ARM64_EXECUTABLE_SHA256 =
|
|
30
|
-
"
|
|
38
|
+
"46c4c73c81c7db2d516c2d467c66aff03c73de196996d646bc8afce0ea85cff6" as const;
|
|
39
|
+
// The exact .3 source and binary pins include the tested no-fetch RPC mode.
|
|
40
|
+
export const IMSG_NO_FETCH_RICH_CARDS_AVAILABLE = true;
|
|
31
41
|
|
|
32
42
|
export const IMSG_TOOL_PIN = Object.freeze({
|
|
33
43
|
id: "imsg-private-transport",
|
|
@@ -16,6 +16,27 @@ export class LinkedInContactIdentityMismatch extends Error {
|
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
export function isLinkedInContactGraphqlUnavailable(error: unknown): boolean {
|
|
20
|
+
let current: unknown = error;
|
|
21
|
+
for (let depth = 0; depth < 8 && current !== undefined; depth += 1) {
|
|
22
|
+
if (current instanceof LinkedInProfileBrowserResponseRejectedError) {
|
|
23
|
+
return current.status === 403
|
|
24
|
+
|| current.contentType === "text/html"
|
|
25
|
+
|| current.contentType === "missing";
|
|
26
|
+
}
|
|
27
|
+
if (
|
|
28
|
+
current instanceof Error
|
|
29
|
+
&& "cause" in current
|
|
30
|
+
&& current.cause !== current
|
|
31
|
+
) {
|
|
32
|
+
current = current.cause;
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
19
40
|
export function linkedInContactReadFailure(
|
|
20
41
|
error: unknown,
|
|
21
42
|
stage: LinkedInContactStage,
|
|
@@ -4,7 +4,10 @@ import * as Layer from "effect/Layer";
|
|
|
4
4
|
import { ReadEffectFailure, readAttempt } from "../read-effect";
|
|
5
5
|
import { readNative } from "../read-effect-platform";
|
|
6
6
|
import { LinkedInContactIdentityMismatch } from "./linkedin-contact-failure";
|
|
7
|
-
import type {
|
|
7
|
+
import type {
|
|
8
|
+
LinkedInContactInfoJsonInput,
|
|
9
|
+
LinkedInContactNavigationInput,
|
|
10
|
+
} from "./linkedin-web-contact";
|
|
8
11
|
import type { LinkedInProfileBrowserTransport } from "./linkedin-web-profile-browser";
|
|
9
12
|
|
|
10
13
|
export type LinkedInContactIdentity = { readonly subject: string };
|
|
@@ -30,6 +33,10 @@ function platform(ports: LinkedInContactNative) {
|
|
|
30
33
|
readNative(() => browser.readProfileHtml(profileUrl)).pipe(Effect.uninterruptible),
|
|
31
34
|
contactPayload: (browser: LinkedInProfileBrowserTransport, input: LinkedInContactInfoJsonInput) =>
|
|
32
35
|
readNative(() => browser.readContactInfoJson(input)).pipe(Effect.uninterruptible),
|
|
36
|
+
contactOverlay: (browser: LinkedInProfileBrowserTransport, input: LinkedInContactInfoJsonInput) =>
|
|
37
|
+
readNative(() => browser.readContactOverlayText(input)).pipe(Effect.uninterruptible),
|
|
38
|
+
contactNavigation: (browser: LinkedInProfileBrowserTransport, input: LinkedInContactNavigationInput) =>
|
|
39
|
+
readNative(() => browser.readContactNavigationText(input)).pipe(Effect.uninterruptible),
|
|
33
40
|
observedAt: readAttempt(ports.observedAt),
|
|
34
41
|
closeBrowser: (browser: LinkedInProfileBrowserTransport) =>
|
|
35
42
|
readNative(() => browser.close()).pipe(Effect.uninterruptible),
|
|
@@ -4,11 +4,14 @@ import { readAttempt, type ReadEffectFailure, withReadResource } from "../read-e
|
|
|
4
4
|
import type { WebSessionExecution } from "../web-session-execution";
|
|
5
5
|
import { LinkedInContactPlatform } from "./linkedin-contact-platform";
|
|
6
6
|
import {
|
|
7
|
+
isLinkedInContactGraphqlUnavailable,
|
|
7
8
|
linkedInContactDiagnostic,
|
|
8
9
|
linkedInContactReadFailure,
|
|
9
10
|
type LinkedInContactStage,
|
|
10
11
|
} from "./linkedin-contact-failure";
|
|
11
12
|
import {
|
|
13
|
+
extractLinkedInContactNavigationAction,
|
|
14
|
+
linkedInContactNavigationActionError,
|
|
12
15
|
projectLinkedInContactInfo,
|
|
13
16
|
projectLinkedInEmbeddedContactFields,
|
|
14
17
|
projectLinkedInProfileContactBinding,
|
|
@@ -50,12 +53,38 @@ export function linkedInContactReadProgram(
|
|
|
50
53
|
});
|
|
51
54
|
} else {
|
|
52
55
|
stage = "contact";
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
const navigation = yield* readAttempt(() => extractLinkedInContactNavigationAction({
|
|
57
|
+
profileHtml,
|
|
58
|
+
publicIdentifier: binding.vanity,
|
|
56
59
|
profileUrn: binding.profileUrn,
|
|
57
|
-
|
|
58
|
-
|
|
60
|
+
}));
|
|
61
|
+
if (navigation.kind === "action") {
|
|
62
|
+
contactPayload = yield* platform.contactNavigation(browser, {
|
|
63
|
+
profileUrl: target.url,
|
|
64
|
+
profileUrn: binding.profileUrn,
|
|
65
|
+
sduiid: navigation.action.sduiid,
|
|
66
|
+
clientArguments: navigation.action.clientArguments,
|
|
67
|
+
});
|
|
68
|
+
} else if (navigation.kind !== "absent") {
|
|
69
|
+
yield* readAttempt(() => {
|
|
70
|
+
throw linkedInContactNavigationActionError(navigation);
|
|
71
|
+
});
|
|
72
|
+
} else {
|
|
73
|
+
const queryId = resolveLinkedInProfileContactInfoQueryId(profileHtml);
|
|
74
|
+
const contactInput = {
|
|
75
|
+
profileUrl: target.url,
|
|
76
|
+
profileUrn: binding.profileUrn,
|
|
77
|
+
...(queryId === undefined ? {} : { queryId }),
|
|
78
|
+
};
|
|
79
|
+
contactPayload = queryId === undefined
|
|
80
|
+
? yield* platform.contactOverlay(browser, contactInput)
|
|
81
|
+
: yield* platform.contactPayload(browser, contactInput).pipe(
|
|
82
|
+
Effect.catchIf(
|
|
83
|
+
(error) => isLinkedInContactGraphqlUnavailable(error),
|
|
84
|
+
() => platform.contactOverlay(browser, contactInput),
|
|
85
|
+
),
|
|
86
|
+
);
|
|
87
|
+
}
|
|
59
88
|
}
|
|
60
89
|
stage = "projection";
|
|
61
90
|
const observedAt = yield* platform.observedAt;
|