@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.
Files changed (114) hide show
  1. package/CHANGELOG.md +301 -0
  2. package/README.md +16 -9
  3. package/dist/apple-photos-client.js +2 -1
  4. package/dist/beeper-client.js +2 -1
  5. package/dist/client.js +1 -0
  6. package/dist/imessage-direct-install-2gm3kge7.js +324 -0
  7. package/dist/index-01eeae9e.js +5 -0
  8. package/dist/index-2ymnp8xv.js +145 -0
  9. package/dist/index-en5hycxp.js +175 -0
  10. package/dist/{index-cytf8d9p.js → index-hfbygww8.js} +1 -1
  11. package/dist/index-n4szk3nw.js +50 -0
  12. package/dist/index-yq6maz71.js +1105 -0
  13. package/dist/index-z1w83f81.js +4 -0
  14. package/dist/index.js +4 -47
  15. package/dist/messaging-automation-api.js +21 -0
  16. package/dist/messaging-automation-j4274hvc.js +609 -0
  17. package/dist/messaging-native-install-8w1j36ah.js +16 -0
  18. package/dist/messaging.js +1 -0
  19. package/dist/omni-client.js +1 -0
  20. package/dist/whatsapp-automation-runtime-hgh1e9rm.js +845 -0
  21. package/dist/whatsapp-client.js +1 -0
  22. package/docs/control-panel.md +147 -0
  23. package/docs/imessage-direct-provider.md +31 -7
  24. package/docs/messaging-automation.md +103 -0
  25. package/package.json +66 -7
  26. package/skills/ghostget/SKILL.md +3 -1
  27. package/skills/ghostget/references/control-panel.md +43 -0
  28. package/skills/ghostget/references/install.md +5 -5
  29. package/skills/ghostget/references/linkedin-adapter.md +222 -12
  30. package/skills/ghostget/references/platform-patterns.md +1 -1
  31. package/src/args.ts +18 -5
  32. package/src/assets/adapters/imessage/wrench-web-adapter.json +126 -0
  33. package/src/assets/adapters/linkedin/wrench-web-adapter.json +1 -1
  34. package/src/assets/adapters/whatsapp/wrench-web-adapter.json +144 -0
  35. package/src/assets/messaging-runtime/NOTICE.txt +2580 -0
  36. package/src/assets/messaging-runtime/imsg-darwin-arm64.gz +0 -0
  37. package/src/assets/messaging-runtime/phone-number-info.plist.gz +0 -0
  38. package/src/assets/messaging-runtime/phone-number-metadata.json.gz +0 -0
  39. package/src/assets/messaging-runtime/phone-number-privacy.plist.gz +0 -0
  40. package/src/assets/messaging-runtime/wacli-darwin-arm64.gz +0 -0
  41. package/src/auth.ts +35 -1
  42. package/src/beeper-client-types.ts +1 -1
  43. package/src/cli.ts +18 -0
  44. package/src/confirmed-write-platform.ts +16 -1
  45. package/src/control/account-revision.ts +16 -0
  46. package/src/control/activity.ts +104 -0
  47. package/src/control/approval-broker.ts +59 -0
  48. package/src/control/approval-client.ts +49 -0
  49. package/src/control/bundled-interfaces.ts +20 -0
  50. package/src/control/cli.ts +20 -0
  51. package/src/control/connections.ts +87 -0
  52. package/src/control/credential-helper.ts +152 -0
  53. package/src/control/helper.ts +79 -0
  54. package/src/control/interface-cli.ts +22 -0
  55. package/src/control/interface-json.ts +94 -0
  56. package/src/control/interface-schema.ts +120 -0
  57. package/src/control/interfaces.ts +438 -0
  58. package/src/control/protocol.ts +182 -0
  59. package/src/control/service.ts +104 -0
  60. package/src/control/validation.ts +103 -0
  61. package/src/control/vault.ts +105 -0
  62. package/src/control/web-gateway.ts +62 -0
  63. package/src/control/web-policy.ts +56 -0
  64. package/src/ghostget.ts +18 -4
  65. package/src/messaging-automation-api.ts +12 -0
  66. package/src/messaging-automation-descriptors.ts +29 -0
  67. package/src/messaging-automation-factory.ts +148 -0
  68. package/src/messaging-automation-server.ts +183 -0
  69. package/src/messaging-automation-types.ts +155 -0
  70. package/src/messaging-automation-validation.ts +110 -0
  71. package/src/messaging-automation.ts +356 -0
  72. package/src/messaging-runtime.ts +3 -0
  73. package/src/oauth-google.ts +11 -5
  74. package/src/omni-runtime.ts +18 -3
  75. package/src/operation-permission-store.ts +92 -0
  76. package/src/operation-permission.ts +308 -0
  77. package/src/pinned-https.ts +5 -0
  78. package/src/plugins/imessage-direct/plugin.ts +12 -1
  79. package/src/plugins/imessage-direct/vendor/0003-feat-rpc-add-no-fetch-rich-cards.patch +276 -0
  80. package/src/plugins/imessage-direct/vendor/provenance.json +84 -10
  81. package/src/plugins/linkedin-web/plugin.ts +1 -1
  82. package/src/plugins/whatsapp-linked-device/plugin.ts +7 -2
  83. package/src/plugins/whatsapp-linked-device/vendor/0001-ghostget-private-messaging.patch +1093 -0
  84. package/src/plugins/whatsapp-linked-device/vendor/README.md +39 -0
  85. package/src/plugins/whatsapp-linked-device/vendor/provenance.json +45 -0
  86. package/src/provider-http.ts +11 -3
  87. package/src/provider-plugin-contract-identity.ts +2 -2
  88. package/src/provider-plugin-import-analysis.ts +52 -0
  89. package/src/provider-plugin-module-analysis.ts +21 -1
  90. package/src/provider-plugin-registry.ts +4 -8
  91. package/src/provider-plugin.ts +18 -8
  92. package/src/providers/imessage-automation.ts +250 -0
  93. package/src/providers/imessage-direct-install.ts +7 -0
  94. package/src/providers/imessage-direct-runtime.ts +32 -2
  95. package/src/providers/imessage-direct.ts +13 -3
  96. package/src/providers/linkedin-contact-failure.ts +21 -0
  97. package/src/providers/linkedin-contact-platform.ts +8 -1
  98. package/src/providers/linkedin-contact-program.ts +34 -5
  99. package/src/providers/linkedin-web-contact.ts +1223 -35
  100. package/src/providers/linkedin-web-profile-browser.ts +659 -45
  101. package/src/providers/linkedin-web-runtime.ts +1 -0
  102. package/src/providers/linkedin-web.ts +46 -2
  103. package/src/providers/messaging-native-artifacts.ts +38 -0
  104. package/src/providers/messaging-native-install.ts +75 -0
  105. package/src/providers/whatsapp-automation-runtime.ts +240 -0
  106. package/src/providers/whatsapp-automation.ts +153 -0
  107. package/src/read-client.ts +12 -2
  108. package/src/runtime.ts +81 -9
  109. package/src/state-helper.ts +2 -0
  110. package/src/storage.ts +71 -1
  111. package/src/usage.ts +9 -1
  112. package/src/version.ts +1 -1
  113. package/src/web-session-contract-definitions.ts +1 -1
  114. package/tsconfig.json +3 -0
@@ -891,7 +891,7 @@ function parseMessages(
891
891
 
892
892
  function parseSendAccepted(
893
893
  value: unknown,
894
- input: ImsgMessagingSendInput,
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
- return await operation(Object.freeze({ subject, run }));
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 IMSG_REVIEWED_PATCH_COMMIT = IMSG_EXACT_CHAT_PATCH_COMMIT;
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.2" as const;
36
+ "0.14.1+private-transport.3" as const;
29
37
  export const IMSG_DARWIN_ARM64_EXECUTABLE_SHA256 =
30
- "77a0db864dfd247cd0a9142dd98997960582e6f150f76ecd3bf1c38944f2bf71" as const;
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 { LinkedInContactInfoJsonInput } from "./linkedin-web-contact";
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 queryId = resolveLinkedInProfileContactInfoQueryId(profileHtml);
54
- contactPayload = yield* platform.contactPayload(browser, {
55
- profileUrl: target.url,
56
+ const navigation = yield* readAttempt(() => extractLinkedInContactNavigationAction({
57
+ profileHtml,
58
+ publicIdentifier: binding.vanity,
56
59
  profileUrn: binding.profileUrn,
57
- ...(queryId === undefined ? {} : { queryId }),
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;