@hraness/peopleblade 0.2.1 → 0.3.0

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.
@@ -4312,20 +4312,21 @@ var peoplebladeCapabilities = Object.freeze({
4312
4312
  sources: [
4313
4313
  { id: "apple-contacts", command: "contacts sync", status: "supported", transport: "local-database", requirement: "macOS Contacts access" },
4314
4314
  { id: "imessage", command: "imessage sync", status: "supported", transport: "local-metadata", requirement: "macOS Messages access; no message bodies" },
4315
- { id: "google-contacts", command: "google sync", status: "supported", transport: "wrench", requirement: "Reviewed Gmail/People contacts.list and contact scopes" },
4316
- { id: "beeper", command: "beeper sync", status: "supported", transport: "wrench", requirement: "Wrench 0.16.8, Beeper adapter 2.4.0, CLI 0.6.2; body-free relationships require macOS arm64" },
4317
- { id: "whatsapp", command: "whatsapp sync", status: "supported", transport: "wrench", requirement: "Reviewed linked-device contacts.list v2" },
4318
- { id: "linkedin", command: "linkedin import", status: "supported", transport: "official-archive", requirement: "Owner-selected official ZIP; no authenticated browser collection" },
4315
+ { id: "google-contacts", command: "google sync", status: "supported", transport: "ghostget", requirement: "Reviewed Gmail/People contacts.list and contact scopes" },
4316
+ { id: "beeper", command: "beeper sync", status: "supported", transport: "ghostget", requirement: "Ghostget 0.17.3, Beeper adapter 2.4.0, CLI 0.6.2; body-free relationships require macOS arm64" },
4317
+ { id: "whatsapp", command: "whatsapp sync", status: "supported", transport: "ghostget", requirement: "Reviewed linked-device contacts.list v2" },
4318
+ { id: "linkedin", command: "linkedin import", status: "supported", transport: "official-archive", requirement: "Owner-selected official ZIP; connection lists are not collected from a signed-in browser" },
4319
4319
  { id: "instagram", command: "instagram import", status: "supported", transport: "official-archive", requirement: "Owner-selected JSON ZIP and exact owner username" },
4320
4320
  { id: "x-archive", command: "x import", status: "bounded", transport: "official-archive", requirement: "Owner-selected ZIP; unresolved IDs remain inert" },
4321
- { id: "x-live", command: "x mutuals sync", status: "blocked", transport: "unavailable", requirement: "A reviewed bounded Wrench mutuals capability is not yet available" },
4321
+ { id: "x-live", command: "x mutuals sync", status: "blocked", transport: "unavailable", requirement: "A reviewed bounded Ghostget mutuals capability is not yet available" },
4322
4322
  { id: "telegram", command: "telegram status", status: "planned", transport: "unavailable", requirement: "First real export and importer validation remain pending" }
4323
4323
  ],
4324
4324
  enrichment: [
4325
4325
  { id: "local-anchors", priority: 1, status: "supported", commands: ["identity audit", "identity suggest", "identity decide"], paid: false, boundary: "Exact source evidence first; joins require reversible evidence-bound decisions" },
4326
- { id: "manual-public-research", priority: 2, status: "supported", commands: ["research prepare", "research apply"], paid: false, boundary: "Agent or human supplies cited public evidence; PeopleBlade performs no provider calls" },
4327
- { id: "cloud-professional-research", priority: 3, status: "optional", commands: ["cloud enrich --person-id ID", "cloud enrich --confirm TOKEN"], paid: true, boundary: "Exa exact profiles or bounded search, then cited model extraction; device-bound preview approval required" },
4328
- { id: "cloud-email-fallback", priority: 4, status: "optional", commands: ["cloud enrich --person-id ID"], paid: true, boundary: "Hunter is a separately configured narrow fallback, not a substitute for identity evidence" }
4326
+ { id: "linkedin-contact-info", priority: 2, status: "supported", commands: ["linkedin contact-info --person-id ID"], paid: false, boundary: "Reviewed Ghostget linkedin-web contacts.read for one exact first-degree connection already imported from the official export; signed-in browser profile, one bounded read, no connect, message, or feed access" },
4327
+ { id: "manual-public-research", priority: 3, status: "supported", commands: ["research prepare", "research apply"], paid: false, boundary: "Agent or human supplies cited public evidence; PeopleBlade performs no provider calls" },
4328
+ { id: "cloud-professional-research", priority: 4, status: "optional", commands: ["cloud enrich --person-id ID", "cloud enrich --confirm TOKEN"], paid: true, boundary: "Exa exact profiles or bounded search, then cited model extraction; device-bound preview approval required" },
4329
+ { id: "cloud-email-fallback", priority: 5, status: "optional", commands: ["cloud enrich --person-id ID"], paid: true, boundary: "Hunter is a separately configured narrow fallback, not a substitute for identity evidence" }
4329
4330
  ],
4330
4331
  interfaces: {
4331
4332
  workspace: { command: "ui [--port N]", availability: "included-in-this-build", binding: "127.0.0.1", defaultPort: "random", authentication: "per-process capability file", remoteAssets: false, noteUpload: false },
@@ -12341,7 +12342,7 @@ function importContactSourceSnapshot(database, value) {
12341
12342
  }
12342
12343
  }
12343
12344
 
12344
- // node_modules/@hraness/wrench/dist/index-26yq8q16.js
12345
+ // node_modules/@hraness/ghostget/dist/index-26yq8q16.js
12345
12346
  var PROVIDER_PLUGIN_ID_MAX_LENGTH = 63;
12346
12347
  var PROVIDER_PLUGIN_OPERATION_NAME_MAX_LENGTH = 163;
12347
12348
  var strictKebabPattern = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/u;
@@ -12360,7 +12361,7 @@ function isProviderPluginOperationName(value) {
12360
12361
  return segments.length >= 2 && segments.length <= 4 && segments.every((segment) => segment.length <= 40 && strictKebabSegmentPattern.test(segment));
12361
12362
  }
12362
12363
 
12363
- // node_modules/@hraness/wrench/dist/index-dqv16dt0.js
12364
+ // node_modules/@hraness/ghostget/dist/index-gwk7rbyj.js
12364
12365
  import { createHash as createHash4 } from "crypto";
12365
12366
  function isRecord(value) {
12366
12367
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -12388,7 +12389,7 @@ function sha2563(value) {
12388
12389
  return createHash4("sha256").update(value).digest("hex");
12389
12390
  }
12390
12391
 
12391
- // node_modules/@hraness/wrench/dist/client.js
12392
+ // node_modules/@hraness/ghostget/dist/client.js
12392
12393
  import { spawn, spawnSync } from "child_process";
12393
12394
  import { existsSync as existsSync3 } from "fs";
12394
12395
  import { fileURLToPath as fileURLToPath2 } from "url";
@@ -12485,7 +12486,7 @@ function publicWebSessionAuthority(request) {
12485
12486
  function expectedRequestAuthId(request, authKind) {
12486
12487
  if (authKind === PUBLIC_WEB_SESSION_AUTHORITY_KIND) {
12487
12488
  if (request.authId !== undefined) {
12488
- throw new Error("Wrench public invocation unexpectedly accepted an auth locator");
12489
+ throw new Error("Ghostget public invocation unexpectedly accepted an auth locator");
12489
12490
  }
12490
12491
  return publicWebSessionAuthority(request).id;
12491
12492
  }
@@ -12535,14 +12536,14 @@ var clientReadFailureRetryDisposition = Object.freeze({
12535
12536
  "cleanup-required": "do-not-retry"
12536
12537
  });
12537
12538
  function parseClientReadFailure(value) {
12538
- const failure = record(value, "Wrench read failure");
12539
- assertExactKeys(failure, ["category", "retryDisposition"], [], "Wrench read failure");
12539
+ const failure = record(value, "Ghostget read failure");
12540
+ assertExactKeys(failure, ["category", "retryDisposition"], [], "Ghostget read failure");
12540
12541
  const category = failure.category;
12541
12542
  if (typeof category !== "string" || !Object.hasOwn(clientReadFailureRetryDisposition, category))
12542
- throw new Error("Wrench read failure category is malformed");
12543
+ throw new Error("Ghostget read failure category is malformed");
12543
12544
  const retryDisposition = clientReadFailureRetryDisposition[category];
12544
12545
  if (failure.retryDisposition !== retryDisposition) {
12545
- throw new Error("Wrench read failure retry disposition is inconsistent");
12546
+ throw new Error("Ghostget read failure retry disposition is inconsistent");
12546
12547
  }
12547
12548
  return Object.freeze({ category, retryDisposition });
12548
12549
  }
@@ -12693,16 +12694,16 @@ function cliSourcePath() {
12693
12694
  const packagedSource = fileURLToPath2(new URL("../src/cli.ts", import.meta.url));
12694
12695
  if (existsSync3(packagedSource))
12695
12696
  return packagedSource;
12696
- throw new Error("the installed Wrench CLI source is unavailable");
12697
+ throw new Error("the installed Ghostget CLI source is unavailable");
12697
12698
  }
12698
12699
  function requireBunRuntime() {
12699
12700
  if (typeof process.versions.bun !== "string") {
12700
- throw new Error("@hraness/wrench/client requires Bun to run the installed Wrench CLI");
12701
+ throw new Error("@hraness/ghostget/client requires Bun to run the installed Ghostget CLI");
12701
12702
  }
12702
12703
  }
12703
12704
  function environmentName(value) {
12704
12705
  if (value.length < 1 || value.includes("=") || value.includes("\x00")) {
12705
- throw new Error("Wrench client environment name is malformed");
12706
+ throw new Error("Ghostget client environment name is malformed");
12706
12707
  }
12707
12708
  return value;
12708
12709
  }
@@ -12723,26 +12724,26 @@ function snapshotChildEnvironment(overrides) {
12723
12724
  if (overrides === undefined)
12724
12725
  return Object.freeze(environment);
12725
12726
  if (!isRecord2(overrides) || nodeTypes.isProxy(overrides) || Object.getPrototypeOf(overrides) !== Object.prototype && Object.getPrototypeOf(overrides) !== null) {
12726
- throw new Error("Wrench client environment must use a plain, non-proxy object");
12727
+ throw new Error("Ghostget client environment must use a plain, non-proxy object");
12727
12728
  }
12728
12729
  const descriptors = Object.getOwnPropertyDescriptors(overrides);
12729
12730
  const keys = Reflect.ownKeys(descriptors);
12730
12731
  if (keys.some((key) => typeof key !== "string")) {
12731
- throw new Error("Wrench client environment has unsupported symbol fields");
12732
+ throw new Error("Ghostget client environment has unsupported symbol fields");
12732
12733
  }
12733
12734
  for (const key of keys.sort((left, right) => left.localeCompare(right))) {
12734
12735
  const descriptor = descriptors[key];
12735
12736
  if (descriptor === undefined || !("value" in descriptor)) {
12736
- throw new Error("Wrench client environment must contain only data properties");
12737
+ throw new Error("Ghostget client environment must contain only data properties");
12737
12738
  }
12738
12739
  if (!descriptor.enumerable) {
12739
- throw new Error("Wrench client environment properties must be enumerable");
12740
+ throw new Error("Ghostget client environment properties must be enumerable");
12740
12741
  }
12741
12742
  const name = environmentName(key);
12742
12743
  if (descriptor.value === undefined) {
12743
12744
  delete environment[name];
12744
12745
  } else if (typeof descriptor.value !== "string" || descriptor.value.includes("\x00")) {
12745
- throw new Error("Wrench client environment value is malformed");
12746
+ throw new Error("Ghostget client environment value is malformed");
12746
12747
  } else {
12747
12748
  defineEnvironmentValue(environment, name, descriptor.value);
12748
12749
  }
@@ -12762,20 +12763,20 @@ function isBrandedAbortSignal(value) {
12762
12763
  }
12763
12764
  function snapshotClientOptions(optionsValue, mode) {
12764
12765
  if (!isRecord2(optionsValue) || nodeTypes.isProxy(optionsValue) || Object.getPrototypeOf(optionsValue) !== Object.prototype && Object.getPrototypeOf(optionsValue) !== null)
12765
- throw new Error("Wrench client options must use a plain, non-proxy object");
12766
+ throw new Error("Ghostget client options must use a plain, non-proxy object");
12766
12767
  const descriptors = Object.getOwnPropertyDescriptors(optionsValue);
12767
12768
  const keys = Reflect.ownKeys(descriptors);
12768
12769
  if (keys.some((key) => typeof key !== "string")) {
12769
- throw new Error("Wrench client options have unsupported symbol fields");
12770
+ throw new Error("Ghostget client options have unsupported symbol fields");
12770
12771
  }
12771
12772
  const allowed = new Set(mode === "read" ? ["environment", "freshForMs", "now"] : mode === "revalidation" ? ["environment", "freshForMs", "now", "headed", "signal"] : mode === "invoke-async" ? ["environment", "headed", "signal"] : ["environment", "headed"]);
12772
12773
  for (const key of keys) {
12773
12774
  const descriptor = descriptors[key];
12774
12775
  if (descriptor === undefined || !allowed.has(key)) {
12775
- throw new Error("Wrench client options contain an unsupported field");
12776
+ throw new Error("Ghostget client options contain an unsupported field");
12776
12777
  }
12777
12778
  if (!("value" in descriptor)) {
12778
- throw new Error("Wrench client options must contain only data properties");
12779
+ throw new Error("Ghostget client options must contain only data properties");
12779
12780
  }
12780
12781
  }
12781
12782
  const option = (key) => descriptors[key]?.value;
@@ -12783,27 +12784,27 @@ function snapshotClientOptions(optionsValue, mode) {
12783
12784
  const nowValue = option("now");
12784
12785
  const headedValue = option("headed");
12785
12786
  const signalValue = option("signal");
12786
- const freshForMs = freshForMsValue === undefined ? undefined : safeInteger(freshForMsValue, "Wrench client freshness window", 0, MAX_FRESH_FOR_MS);
12787
+ const freshForMs = freshForMsValue === undefined ? undefined : safeInteger(freshForMsValue, "Ghostget client freshness window", 0, MAX_FRESH_FOR_MS);
12787
12788
  let now;
12788
12789
  if (nowValue !== undefined) {
12789
12790
  if (nodeTypes.isProxy(nowValue) || !(nowValue instanceof Date) || Object.getPrototypeOf(nowValue) !== Date.prototype)
12790
- throw new Error("Wrench client observation time is invalid");
12791
+ throw new Error("Ghostget client observation time is invalid");
12791
12792
  let time;
12792
12793
  try {
12793
12794
  time = Date.prototype.getTime.call(nowValue);
12794
12795
  } catch {
12795
- throw new Error("Wrench client observation time is invalid");
12796
+ throw new Error("Ghostget client observation time is invalid");
12796
12797
  }
12797
12798
  if (!Number.isFinite(time)) {
12798
- throw new Error("Wrench client observation time is invalid");
12799
+ throw new Error("Ghostget client observation time is invalid");
12799
12800
  }
12800
12801
  now = new Date(time);
12801
12802
  }
12802
12803
  if (headedValue !== undefined && typeof headedValue !== "boolean") {
12803
- throw new Error("Wrench client headed option is malformed");
12804
+ throw new Error("Ghostget client headed option is malformed");
12804
12805
  }
12805
12806
  if (signalValue !== undefined && !isBrandedAbortSignal(signalValue))
12806
- throw new Error("Wrench client abort signal is malformed");
12807
+ throw new Error("Ghostget client abort signal is malformed");
12807
12808
  return Object.freeze({
12808
12809
  cwd: process.cwd(),
12809
12810
  environment: snapshotChildEnvironment(option("environment")),
@@ -12814,18 +12815,18 @@ function snapshotClientOptions(optionsValue, mode) {
12814
12815
  });
12815
12816
  }
12816
12817
  function prepareRequest(requestValue) {
12817
- const snapshot = snapshotJson(requestValue, "Wrench client request");
12818
- const request = record(snapshot, "Wrench client request");
12819
- assertExactKeys(request, ["adapterId", "operationId"], ["authId", "input"], "Wrench client request");
12820
- const adapterId = safeString(request.adapterId, "Wrench client adapter ID", 64);
12821
- const operationId = providerOperationName(request.operationId, "Wrench client operation ID");
12822
- const authId = Object.hasOwn(request, "authId") ? safeString(request.authId, "Wrench client auth ID", 64) : undefined;
12818
+ const snapshot = snapshotJson(requestValue, "Ghostget client request");
12819
+ const request = record(snapshot, "Ghostget client request");
12820
+ assertExactKeys(request, ["adapterId", "operationId"], ["authId", "input"], "Ghostget client request");
12821
+ const adapterId = safeString(request.adapterId, "Ghostget client adapter ID", 64);
12822
+ const operationId = providerOperationName(request.operationId, "Ghostget client operation ID");
12823
+ const authId = Object.hasOwn(request, "authId") ? safeString(request.authId, "Ghostget client auth ID", 64) : undefined;
12823
12824
  const rawInput = Object.hasOwn(request, "input") ? request.input : {};
12824
12825
  if (!isRecord2(rawInput))
12825
12826
  throw new Error("input must be a JSON object");
12826
12827
  const input = canonicalJson2(rawInput);
12827
12828
  if (Buffer.byteLength(input, "utf8") > MAX_INPUT_BYTES) {
12828
- throw new Error("Wrench client input exceeds its byte bound");
12829
+ throw new Error("Ghostget client input exceeds its byte bound");
12829
12830
  }
12830
12831
  return Object.freeze({
12831
12832
  adapterId,
@@ -12896,7 +12897,7 @@ function runIdentityCommand(command, options, label, responseLabel = `${label} r
12896
12897
  return parseOutput(stdout, responseLabel);
12897
12898
  }
12898
12899
  function runProjectionIdentityCommand(command, options) {
12899
- return runIdentityCommand(command, options, "Wrench projection identity preflight", "Wrench projection identity response");
12900
+ return runIdentityCommand(command, options, "Ghostget projection identity preflight", "Ghostget projection identity response");
12900
12901
  }
12901
12902
  function observeProjectionIdentity(request, options) {
12902
12903
  const value = runProjectionIdentityCommand(preparedCommand(request, {
@@ -12905,7 +12906,7 @@ function observeProjectionIdentity(request, options) {
12905
12906
  headed: false
12906
12907
  }), options);
12907
12908
  if (value.ok !== true || value.source !== "projection-identity")
12908
- throw new Error("Wrench projection identity response is malformed");
12909
+ throw new Error("Ghostget projection identity response is malformed");
12909
12910
  if (value.status === "ready") {
12910
12911
  assertExactKeys(value, [
12911
12912
  "ok",
@@ -12915,15 +12916,15 @@ function observeProjectionIdentity(request, options) {
12915
12916
  "authHash",
12916
12917
  "inputHash",
12917
12918
  "projection"
12918
- ], [], "Wrench projection identity response");
12919
- const projection = record(value.projection, "Wrench projection identity");
12920
- assertExactKeys(projection, ["key"], [], "Wrench projection identity");
12919
+ ], [], "Ghostget projection identity response");
12920
+ const projection = record(value.projection, "Ghostget projection identity");
12921
+ assertExactKeys(projection, ["key"], [], "Ghostget projection identity");
12921
12922
  return Object.freeze({
12922
12923
  status: "ready",
12923
- key: digest(projection.key, "Wrench projection identity key"),
12924
- authIdentity: digest(value.authIdentity, "Wrench projection auth identity"),
12925
- authHash: digest(value.authHash, "Wrench projection auth hash"),
12926
- inputHash: digest(value.inputHash, "Wrench projection validated input hash")
12924
+ key: digest(projection.key, "Ghostget projection identity key"),
12925
+ authIdentity: digest(value.authIdentity, "Ghostget projection auth identity"),
12926
+ authHash: digest(value.authHash, "Ghostget projection auth hash"),
12927
+ inputHash: digest(value.inputHash, "Ghostget projection validated input hash")
12927
12928
  });
12928
12929
  }
12929
12930
  if (value.status === "unbound") {
@@ -12934,15 +12935,15 @@ function observeProjectionIdentity(request, options) {
12934
12935
  "authIdentity",
12935
12936
  "authHash",
12936
12937
  "inputHash"
12937
- ], [], "Wrench projection identity response");
12938
+ ], [], "Ghostget projection identity response");
12938
12939
  return Object.freeze({
12939
12940
  status: "unbound",
12940
- authIdentity: digest(value.authIdentity, "Wrench projection auth identity"),
12941
- authHash: digest(value.authHash, "Wrench projection auth hash"),
12942
- inputHash: digest(value.inputHash, "Wrench projection validated input hash")
12941
+ authIdentity: digest(value.authIdentity, "Ghostget projection auth identity"),
12942
+ authHash: digest(value.authHash, "Ghostget projection auth hash"),
12943
+ inputHash: digest(value.inputHash, "Ghostget projection validated input hash")
12943
12944
  });
12944
12945
  }
12945
- throw new Error("Wrench projection identity response is malformed");
12946
+ throw new Error("Ghostget projection identity response is malformed");
12946
12947
  }
12947
12948
  function projectionIdentitiesMatch(before, after) {
12948
12949
  return before.status === "ready" ? after.status === "ready" && after.key === before.key && after.authIdentity === before.authIdentity && after.authHash === before.authHash && after.inputHash === before.inputHash : after.status === "unbound" && after.authIdentity === before.authIdentity && after.authHash === before.authHash && after.inputHash === before.inputHash;
@@ -12962,43 +12963,43 @@ function parseExecutionPreview(value, request) {
12962
12963
  "identityBinding",
12963
12964
  "transport",
12964
12965
  ...portable ? ["portablePluginContract"] : []
12965
- ], [], "Wrench execution identity preview");
12966
+ ], [], "Ghostget execution identity preview");
12966
12967
  if (value.ok !== true || value.status !== "preview" || value.requiresConfirmation !== false || value.risk !== "R1")
12967
- throw new Error("Wrench execution identity preview is malformed");
12968
- const adapterValue = record(value.adapter, "Wrench execution identity preview adapter");
12969
- const auth = record(value.auth, "Wrench execution identity preview auth");
12970
- const binding2 = record(value.identityBinding, "Wrench execution identity preview binding");
12971
- assertExactKeys(adapterValue, ["id", "version", "hash"], [], "Wrench execution identity preview adapter");
12972
- assertExactKeys(auth, ["id", "kind", "realmFingerprint"], [], "Wrench execution identity preview auth");
12973
- assertExactKeys(binding2, ["status", "subject", "accountActor", "requestedActor"], [], "Wrench execution identity preview binding");
12968
+ throw new Error("Ghostget execution identity preview is malformed");
12969
+ const adapterValue = record(value.adapter, "Ghostget execution identity preview adapter");
12970
+ const auth = record(value.auth, "Ghostget execution identity preview auth");
12971
+ const binding2 = record(value.identityBinding, "Ghostget execution identity preview binding");
12972
+ assertExactKeys(adapterValue, ["id", "version", "hash"], [], "Ghostget execution identity preview adapter");
12973
+ assertExactKeys(auth, ["id", "kind", "realmFingerprint"], [], "Ghostget execution identity preview auth");
12974
+ assertExactKeys(binding2, ["status", "subject", "accountActor", "requestedActor"], [], "Ghostget execution identity preview binding");
12974
12975
  const adapter = Object.freeze({
12975
- id: safeString(adapterValue.id, "Wrench execution identity preview adapter ID", 64),
12976
- version: safeString(adapterValue.version, "Wrench execution identity preview adapter version", 64),
12977
- hash: digest(adapterValue.hash, "Wrench execution identity preview adapter hash")
12976
+ id: safeString(adapterValue.id, "Ghostget execution identity preview adapter ID", 64),
12977
+ version: safeString(adapterValue.version, "Ghostget execution identity preview adapter version", 64),
12978
+ hash: digest(adapterValue.hash, "Ghostget execution identity preview adapter hash")
12978
12979
  });
12979
- const operation = providerOperationName(value.operation, "Wrench execution identity preview operation");
12980
+ const operation = providerOperationName(value.operation, "Ghostget execution identity preview operation");
12980
12981
  if (adapter.id !== request.adapterId || operation !== request.operationId) {
12981
- throw new Error("Wrench execution identity preview route is malformed");
12982
+ throw new Error("Ghostget execution identity preview route is malformed");
12982
12983
  }
12983
- const authKind = safeString(auth.kind, "Wrench execution identity preview auth kind", 64);
12984
- if (safeString(auth.id, "Wrench execution identity preview auth ID", 64) !== expectedRequestAuthId(request, authKind))
12985
- throw new Error("Wrench execution identity preview auth is malformed");
12986
- const realmFingerprint = safeString(auth.realmFingerprint, "Wrench execution identity preview auth fingerprint", 16);
12984
+ const authKind = safeString(auth.kind, "Ghostget execution identity preview auth kind", 64);
12985
+ if (safeString(auth.id, "Ghostget execution identity preview auth ID", 64) !== expectedRequestAuthId(request, authKind))
12986
+ throw new Error("Ghostget execution identity preview auth is malformed");
12987
+ const realmFingerprint = safeString(auth.realmFingerprint, "Ghostget execution identity preview auth fingerprint", 16);
12987
12988
  if (!/^[a-f0-9]{16}$/u.test(realmFingerprint)) {
12988
- throw new Error("Wrench execution identity preview auth fingerprint is malformed");
12989
+ throw new Error("Ghostget execution identity preview auth fingerprint is malformed");
12989
12990
  }
12990
12991
  if (authKind === PUBLIC_WEB_SESSION_AUTHORITY_KIND) {
12991
12992
  const authority = publicWebSessionAuthority(request);
12992
12993
  if (value.transport !== "web-session-api" || realmFingerprint !== sha2563(canonicalJson2(authority)).slice(0, 16) || binding2.status !== "public" || binding2.subject !== authority.subject || binding2.accountActor !== null || binding2.requestedActor !== null) {
12993
- throw new Error("Wrench execution identity preview public authority is malformed");
12994
+ throw new Error("Ghostget execution identity preview public authority is malformed");
12994
12995
  }
12995
12996
  }
12996
- safeString(value.sideEffect, "Wrench execution identity preview side effect", 64);
12997
+ safeString(value.sideEffect, "Ghostget execution identity preview side effect", 64);
12997
12998
  const transport = value.transport;
12998
12999
  if (transport === "portable-provider-plugin") {
12999
13000
  const portablePluginContract = parsePortableOperationIdentity(value.portablePluginContract);
13000
13001
  if (portablePluginContract.adapterId !== adapter.id || portablePluginContract.operation !== operation)
13001
- throw new Error("Wrench execution identity preview route is malformed");
13002
+ throw new Error("Ghostget execution identity preview route is malformed");
13002
13003
  return Object.freeze({
13003
13004
  adapter,
13004
13005
  operation,
@@ -13007,18 +13008,18 @@ function parseExecutionPreview(value, request) {
13007
13008
  });
13008
13009
  }
13009
13010
  if (transport !== "browser" && transport !== "provider-api" && transport !== "web-session-api" && transport !== "reviewed-template-api" && transport !== "local-cli")
13010
- throw new Error("Wrench execution identity preview transport is malformed");
13011
+ throw new Error("Ghostget execution identity preview transport is malformed");
13011
13012
  return Object.freeze({ adapter, operation, transport });
13012
13013
  }
13013
13014
  function parseCatalogExecutionIdentity(value, request, preview) {
13014
- assertExactKeys(value, ["ok", "adapters"], [], "Wrench execution identity catalog");
13015
+ assertExactKeys(value, ["ok", "adapters"], [], "Ghostget execution identity catalog");
13015
13016
  if (value.ok !== true || !isUnknownArray(value.adapters)) {
13016
- throw new Error("Wrench execution identity catalog is malformed");
13017
+ throw new Error("Ghostget execution identity catalog is malformed");
13017
13018
  }
13018
13019
  if (value.adapters.length !== 1) {
13019
- throw new Error("Wrench execution identity catalog is ambiguous");
13020
+ throw new Error("Ghostget execution identity catalog is ambiguous");
13020
13021
  }
13021
- const adapterValue = record(value.adapters[0], "Wrench execution identity catalog adapter");
13022
+ const adapterValue = record(value.adapters[0], "Ghostget execution identity catalog adapter");
13022
13023
  assertExactKeys(adapterValue, [
13023
13024
  "id",
13024
13025
  "version",
@@ -13027,17 +13028,17 @@ function parseCatalogExecutionIdentity(value, request, preview) {
13027
13028
  "origins",
13028
13029
  "manifestHash",
13029
13030
  "operations"
13030
- ], [], "Wrench execution identity catalog adapter");
13031
+ ], [], "Ghostget execution identity catalog adapter");
13031
13032
  const adapter = Object.freeze({
13032
- id: safeString(adapterValue.id, "Wrench execution identity catalog adapter ID", 64),
13033
- version: safeString(adapterValue.version, "Wrench execution identity catalog adapter version", 64),
13034
- hash: digest(adapterValue.manifestHash, "Wrench execution identity catalog adapter hash")
13033
+ id: safeString(adapterValue.id, "Ghostget execution identity catalog adapter ID", 64),
13034
+ version: safeString(adapterValue.version, "Ghostget execution identity catalog adapter version", 64),
13035
+ hash: digest(adapterValue.manifestHash, "Ghostget execution identity catalog adapter hash")
13035
13036
  });
13036
13037
  if (adapter.id !== request.adapterId || adapter.id !== preview.adapter.id || adapter.version !== preview.adapter.version || adapter.hash !== preview.adapter.hash || !isUnknownArray(adapterValue.operations))
13037
- throw new Error("Wrench execution identity preflights disagreed");
13038
+ throw new Error("Ghostget execution identity preflights disagreed");
13038
13039
  const operations = adapterValue.operations.filter((candidate) => isRecord2(candidate) && candidate.id === request.operationId);
13039
13040
  if (operations.length !== 1) {
13040
- throw new Error("Wrench execution identity catalog operation is ambiguous");
13041
+ throw new Error("Ghostget execution identity catalog operation is ambiguous");
13041
13042
  }
13042
13043
  const operation = operations[0];
13043
13044
  const commonKeys = [
@@ -13051,7 +13052,7 @@ function parseCatalogExecutionIdentity(value, request, preview) {
13051
13052
  "input"
13052
13053
  ];
13053
13054
  if (operation.risk !== "R1" || operation.transport !== preview.transport)
13054
- throw new Error("Wrench execution identity preflights disagreed");
13055
+ throw new Error("Ghostget execution identity preflights disagreed");
13055
13056
  const common = Object.freeze({
13056
13057
  adapter,
13057
13058
  operation: preview.operation
@@ -13066,18 +13067,18 @@ function parseCatalogExecutionIdentity(value, request, preview) {
13066
13067
  "requiredScopeSets",
13067
13068
  "coverage",
13068
13069
  "implementation"
13069
- ], [], "Wrench execution identity provider capability");
13070
- const catalogSurface = providerSurfaceId(adapterValue.surfaceId, "Wrench execution identity catalog surface");
13071
- const provider = providerSurfaceId(operation.provider, "Wrench execution identity provider surface");
13072
- const providerAction = providerOperationName(operation.providerAction, "Wrench execution identity provider action");
13073
- safeInteger(operation.providerContractVersion, "Wrench execution identity provider contract version", 1, 1e6);
13070
+ ], [], "Ghostget execution identity provider capability");
13071
+ const catalogSurface = providerSurfaceId(adapterValue.surfaceId, "Ghostget execution identity catalog surface");
13072
+ const provider = providerSurfaceId(operation.provider, "Ghostget execution identity provider surface");
13073
+ const providerAction = providerOperationName(operation.providerAction, "Ghostget execution identity provider action");
13074
+ safeInteger(operation.providerContractVersion, "Ghostget execution identity provider contract version", 1, 1e6);
13074
13075
  if (provider !== catalogSurface || providerAction !== preview.operation)
13075
- throw new Error("Wrench execution identity provider route is malformed");
13076
+ throw new Error("Ghostget execution identity provider route is malformed");
13076
13077
  return Object.freeze({
13077
13078
  ...common,
13078
13079
  schemaVersion: 3,
13079
13080
  transport: "provider-api",
13080
- providerContractHash: digest(operation.providerContractHash, "Wrench execution identity provider contract hash")
13081
+ providerContractHash: digest(operation.providerContractHash, "Ghostget execution identity provider contract hash")
13081
13082
  });
13082
13083
  }
13083
13084
  if (preview.transport === "web-session-api") {
@@ -13089,18 +13090,18 @@ function parseCatalogExecutionIdentity(value, request, preview) {
13089
13090
  "webSessionContractHash",
13090
13091
  "state",
13091
13092
  "implementation"
13092
- ], [], "Wrench execution identity web-session capability");
13093
- const catalogSurface = providerSurfaceId(adapterValue.surfaceId, "Wrench execution identity catalog surface");
13094
- const site = providerSurfaceId(operation.site, "Wrench execution identity web-session surface");
13095
- const webSessionAction = providerOperationName(operation.webSessionAction, "Wrench execution identity web-session action");
13096
- safeInteger(operation.webSessionContractVersion, "Wrench execution identity web-session contract version", 1, 1e6);
13093
+ ], [], "Ghostget execution identity web-session capability");
13094
+ const catalogSurface = providerSurfaceId(adapterValue.surfaceId, "Ghostget execution identity catalog surface");
13095
+ const site = providerSurfaceId(operation.site, "Ghostget execution identity web-session surface");
13096
+ const webSessionAction = providerOperationName(operation.webSessionAction, "Ghostget execution identity web-session action");
13097
+ safeInteger(operation.webSessionContractVersion, "Ghostget execution identity web-session contract version", 1, 1e6);
13097
13098
  if (site !== catalogSurface || webSessionAction !== preview.operation)
13098
- throw new Error("Wrench execution identity web-session route is malformed");
13099
+ throw new Error("Ghostget execution identity web-session route is malformed");
13099
13100
  return Object.freeze({
13100
13101
  ...common,
13101
13102
  schemaVersion: 4,
13102
13103
  transport: "web-session-api",
13103
- webSessionContractHash: digest(operation.webSessionContractHash, "Wrench execution identity web-session contract hash")
13104
+ webSessionContractHash: digest(operation.webSessionContractHash, "Ghostget execution identity web-session contract hash")
13104
13105
  });
13105
13106
  }
13106
13107
  if (preview.transport === "local-cli") {
@@ -13113,8 +13114,8 @@ function parseCatalogExecutionIdentity(value, request, preview) {
13113
13114
  "localCliTool",
13114
13115
  "state",
13115
13116
  "implementation"
13116
- ], [], "Wrench execution identity local CLI capability");
13117
- const catalogSurface = providerSurfaceId(adapterValue.surfaceId, "Wrench execution identity catalog surface");
13117
+ ], [], "Ghostget execution identity local CLI capability");
13118
+ const catalogSurface = providerSurfaceId(adapterValue.surfaceId, "Ghostget execution identity catalog surface");
13118
13119
  const localCliContract = parseLocalCliContractIdentity({
13119
13120
  surface: operation.surface,
13120
13121
  action: operation.localCliAction,
@@ -13123,7 +13124,7 @@ function parseCatalogExecutionIdentity(value, request, preview) {
13123
13124
  tool: operation.localCliTool
13124
13125
  });
13125
13126
  if (localCliContract.surface !== catalogSurface || localCliContract.action !== preview.operation) {
13126
- throw new Error("Wrench execution identity local CLI route is malformed");
13127
+ throw new Error("Ghostget execution identity local CLI route is malformed");
13127
13128
  }
13128
13129
  return Object.freeze({
13129
13130
  ...common,
@@ -13137,13 +13138,13 @@ function parseCatalogExecutionIdentity(value, request, preview) {
13137
13138
  "state",
13138
13139
  "reviewedTemplateContractVersion",
13139
13140
  "reviewedTemplateContractHash"
13140
- ], ["instructions", "reviewedAt", "evidenceSha256", "origin"], "Wrench execution identity reviewed-template capability");
13141
- safeInteger(operation.reviewedTemplateContractVersion, "Wrench execution identity reviewed-template contract version", 1, Number.MAX_SAFE_INTEGER);
13141
+ ], ["instructions", "reviewedAt", "evidenceSha256", "origin"], "Ghostget execution identity reviewed-template capability");
13142
+ safeInteger(operation.reviewedTemplateContractVersion, "Ghostget execution identity reviewed-template contract version", 1, Number.MAX_SAFE_INTEGER);
13142
13143
  return Object.freeze({
13143
13144
  ...common,
13144
13145
  schemaVersion: 5,
13145
13146
  transport: "reviewed-template-api",
13146
- reviewedTemplateContractHash: digest(operation.reviewedTemplateContractHash, "Wrench execution identity reviewed-template contract hash")
13147
+ reviewedTemplateContractHash: digest(operation.reviewedTemplateContractHash, "Ghostget execution identity reviewed-template contract hash")
13147
13148
  });
13148
13149
  }
13149
13150
  function observeExecutionIdentity(request, options) {
@@ -13152,7 +13153,7 @@ function observeExecutionIdentity(request, options) {
13152
13153
  projectionIdentityOnly: false,
13153
13154
  preview: true,
13154
13155
  headed: false
13155
- }), options, "Wrench execution identity preview"), request);
13156
+ }), options, "Ghostget execution identity preview"), request);
13156
13157
  if (preview.transport === "portable-provider-plugin") {
13157
13158
  return Object.freeze({
13158
13159
  adapter: preview.adapter,
@@ -13170,7 +13171,7 @@ function observeExecutionIdentity(request, options) {
13170
13171
  transport: preview.transport
13171
13172
  });
13172
13173
  }
13173
- return parseCatalogExecutionIdentity(runIdentityCommand(preparedCapabilitiesCommand(request), options, "Wrench execution identity catalog preflight"), request, preview);
13174
+ return parseCatalogExecutionIdentity(runIdentityCommand(preparedCapabilitiesCommand(request), options, "Ghostget execution identity catalog preflight"), request, preview);
13174
13175
  }
13175
13176
  function receiptExecutionIdentity(receipt) {
13176
13177
  const common = Object.freeze({
@@ -13240,59 +13241,59 @@ function runLiveCommandSync(command, options) {
13240
13241
  const stdout = String(result.stdout ?? "");
13241
13242
  const stderr = String(result.stderr ?? "");
13242
13243
  if (stdout.trim().length === 0) {
13243
- throw new Error(boundedMessage(stderr) || `Wrench live invocation exited ${String(code)}`);
13244
+ throw new Error(boundedMessage(stderr) || `Ghostget live invocation exited ${String(code)}`);
13244
13245
  }
13245
13246
  if (code !== 0 && code !== 3 && code !== 5) {
13246
- throw new Error(boundedMessage(stderr) || `Wrench live invocation exited ${String(code)}`);
13247
+ throw new Error(boundedMessage(stderr) || `Ghostget live invocation exited ${String(code)}`);
13247
13248
  }
13248
- return parseOutput(stdout, "Wrench live response");
13249
+ return parseOutput(stdout, "Ghostget live response");
13249
13250
  }
13250
13251
  function parsePublication(value) {
13251
- const publication = record(value, "Wrench cache publication");
13252
- assertExactKeys(publication, ["key", "dataRevision", "validatedAt", "dataChangedAt", "disposition"], ["currentDataRevision"], "Wrench cache publication");
13252
+ const publication = record(value, "Ghostget cache publication");
13253
+ assertExactKeys(publication, ["key", "dataRevision", "validatedAt", "dataChangedAt", "disposition"], ["currentDataRevision"], "Ghostget cache publication");
13253
13254
  const disposition = publication.disposition;
13254
13255
  if (disposition !== "created" && disposition !== "changed" && disposition !== "unchanged" && disposition !== "superseded")
13255
- throw new Error("Wrench cache publication disposition is malformed");
13256
+ throw new Error("Ghostget cache publication disposition is malformed");
13256
13257
  if (disposition === "superseded" !== Object.hasOwn(publication, "currentDataRevision"))
13257
- throw new Error("Wrench cache publication current revision is malformed");
13258
+ throw new Error("Ghostget cache publication current revision is malformed");
13258
13259
  return Object.freeze({
13259
- key: digest(publication.key, "Wrench cache publication key"),
13260
- dataRevision: digest(publication.dataRevision, "Wrench cache publication data revision"),
13261
- validatedAt: timestamp2(publication.validatedAt, "Wrench cache publication validation time"),
13262
- dataChangedAt: timestamp2(publication.dataChangedAt, "Wrench cache publication data-change time"),
13260
+ key: digest(publication.key, "Ghostget cache publication key"),
13261
+ dataRevision: digest(publication.dataRevision, "Ghostget cache publication data revision"),
13262
+ validatedAt: timestamp2(publication.validatedAt, "Ghostget cache publication validation time"),
13263
+ dataChangedAt: timestamp2(publication.dataChangedAt, "Ghostget cache publication data-change time"),
13263
13264
  disposition,
13264
13265
  ...publication.currentDataRevision === undefined ? {} : {
13265
- currentDataRevision: digest(publication.currentDataRevision, "Wrench current cache data revision")
13266
+ currentDataRevision: digest(publication.currentDataRevision, "Ghostget current cache data revision")
13266
13267
  }
13267
13268
  });
13268
13269
  }
13269
13270
  function parseCacheOutcome(value) {
13270
- const outcome = record(value, "Wrench cache outcome");
13271
+ const outcome = record(value, "Ghostget cache outcome");
13271
13272
  if (outcome.status === "stored") {
13272
- assertExactKeys(outcome, ["status", "publication"], [], "Wrench cache outcome");
13273
+ assertExactKeys(outcome, ["status", "publication"], [], "Ghostget cache outcome");
13273
13274
  return Object.freeze({ status: "stored", publication: parsePublication(outcome.publication) });
13274
13275
  }
13275
13276
  if (outcome.status === "retained" && outcome.reason === "live-read-failed") {
13276
- assertExactKeys(outcome, ["status", "reason"], [], "Wrench cache outcome");
13277
+ assertExactKeys(outcome, ["status", "reason"], [], "Ghostget cache outcome");
13277
13278
  return Object.freeze({ status: "retained", reason: "live-read-failed" });
13278
13279
  }
13279
13280
  if (outcome.status === "miss" && outcome.reason === "no-cached-snapshot") {
13280
- assertExactKeys(outcome, ["status", "reason"], [], "Wrench cache outcome");
13281
+ assertExactKeys(outcome, ["status", "reason"], [], "Ghostget cache outcome");
13281
13282
  return Object.freeze({ status: "miss", reason: "no-cached-snapshot" });
13282
13283
  }
13283
13284
  if (outcome.status === "skipped" && outcome.reason === "auth-subject-unbound") {
13284
- assertExactKeys(outcome, ["status", "reason"], [], "Wrench cache outcome");
13285
+ assertExactKeys(outcome, ["status", "reason"], [], "Ghostget cache outcome");
13285
13286
  return Object.freeze({ status: "skipped", reason: outcome.reason });
13286
13287
  }
13287
13288
  if (outcome.status === "error") {
13288
- assertExactKeys(outcome, ["status", "message"], [], "Wrench cache outcome");
13289
- return Object.freeze({ status: "error", message: safeString(outcome.message, "Wrench cache error", MAX_ERROR_BYTES) });
13289
+ assertExactKeys(outcome, ["status", "message"], [], "Ghostget cache outcome");
13290
+ return Object.freeze({ status: "error", message: safeString(outcome.message, "Ghostget cache error", MAX_ERROR_BYTES) });
13290
13291
  }
13291
- throw new Error("Wrench cache outcome is malformed");
13292
+ throw new Error("Ghostget cache outcome is malformed");
13292
13293
  }
13293
13294
  function parseReceiptStatus(value) {
13294
13295
  if (value !== "succeeded" && value !== "failed") {
13295
- throw new Error("Wrench live receipt status is malformed");
13296
+ throw new Error("Ghostget live receipt status is malformed");
13296
13297
  }
13297
13298
  return value;
13298
13299
  }
@@ -13367,7 +13368,7 @@ function parseLocalCliToolIdentity(value) {
13367
13368
  }
13368
13369
  return parsed;
13369
13370
  };
13370
- const tool = strictRecord(value, "Wrench local CLI tool identity");
13371
+ const tool = strictRecord(value, "Ghostget local CLI tool identity");
13371
13372
  assertExactKeys(tool, [
13372
13373
  "schemaVersion",
13373
13374
  "id",
@@ -13380,58 +13381,58 @@ function parseLocalCliToolIdentity(value) {
13380
13381
  "releaseCommit",
13381
13382
  "releaseManifestSha256",
13382
13383
  "releaseManifestUrl"
13383
- ], "Wrench local CLI tool identity");
13384
- const artifactValues = strictArray(tool.artifacts, "Wrench local CLI tool artifact table");
13384
+ ], "Ghostget local CLI tool identity");
13385
+ const artifactValues = strictArray(tool.artifacts, "Ghostget local CLI tool artifact table");
13385
13386
  if (tool.schemaVersion !== 1) {
13386
- throw new Error("Wrench local CLI tool identity is malformed");
13387
+ throw new Error("Ghostget local CLI tool identity is malformed");
13387
13388
  }
13388
13389
  if (artifactValues.length < 1) {
13389
- throw new Error("Wrench local CLI tool artifact table is malformed");
13390
+ throw new Error("Ghostget local CLI tool artifact table is malformed");
13390
13391
  }
13391
13392
  const artifacts = artifactValues.map((artifactValue, index) => {
13392
- const artifact = strictRecord(artifactValue, `Wrench local CLI tool artifact ${index}`);
13393
- assertExactKeys(artifact, ["platform", "arch", "executableSha256"], ["archiveSha256", "downloadUrl"], `Wrench local CLI tool artifact ${index}`);
13394
- const archiveSha256 = artifact.archiveSha256 === undefined ? undefined : digest(artifact.archiveSha256, `Wrench local CLI tool artifact ${index} archive hash`);
13395
- const downloadUrl = artifact.downloadUrl === undefined ? undefined : exactHttpsUrl(artifact.downloadUrl, `Wrench local CLI tool artifact ${index} download URL`);
13393
+ const artifact = strictRecord(artifactValue, `Ghostget local CLI tool artifact ${index}`);
13394
+ assertExactKeys(artifact, ["platform", "arch", "executableSha256"], ["archiveSha256", "downloadUrl"], `Ghostget local CLI tool artifact ${index}`);
13395
+ const archiveSha256 = artifact.archiveSha256 === undefined ? undefined : digest(artifact.archiveSha256, `Ghostget local CLI tool artifact ${index} archive hash`);
13396
+ const downloadUrl = artifact.downloadUrl === undefined ? undefined : exactHttpsUrl(artifact.downloadUrl, `Ghostget local CLI tool artifact ${index} download URL`);
13396
13397
  if (archiveSha256 === undefined !== (downloadUrl === undefined)) {
13397
- throw new Error("Wrench local CLI tool artifact archive provenance is malformed");
13398
+ throw new Error("Ghostget local CLI tool artifact archive provenance is malformed");
13398
13399
  }
13399
13400
  return Object.freeze({
13400
- platform: token(artifact.platform, `Wrench local CLI tool artifact ${index} platform`),
13401
- arch: token(artifact.arch, `Wrench local CLI tool artifact ${index} architecture`),
13402
- executableSha256: digest(artifact.executableSha256, `Wrench local CLI tool artifact ${index} executable hash`),
13401
+ platform: token(artifact.platform, `Ghostget local CLI tool artifact ${index} platform`),
13402
+ arch: token(artifact.arch, `Ghostget local CLI tool artifact ${index} architecture`),
13403
+ executableSha256: digest(artifact.executableSha256, `Ghostget local CLI tool artifact ${index} executable hash`),
13403
13404
  ...archiveSha256 === undefined ? {} : { archiveSha256 },
13404
13405
  ...downloadUrl === undefined ? {} : { downloadUrl }
13405
13406
  });
13406
13407
  });
13407
13408
  const coordinates = artifacts.map((artifact) => `${artifact.platform}\x00${artifact.arch}`);
13408
13409
  if (new Set(coordinates).size !== coordinates.length || coordinates.some((coordinate, index) => index > 0 && coordinates[index - 1] >= coordinate))
13409
- throw new Error("Wrench local CLI tool artifact table is not canonical");
13410
- const sourceUrl = tool.sourceUrl === undefined ? undefined : exactHttpsUrl(tool.sourceUrl, "Wrench local CLI tool source URL");
13411
- const releaseManifestSha256 = tool.releaseManifestSha256 === undefined ? undefined : digest(tool.releaseManifestSha256, "Wrench local CLI tool release manifest hash");
13412
- const releaseManifestUrl = tool.releaseManifestUrl === undefined ? undefined : exactHttpsUrl(tool.releaseManifestUrl, "Wrench local CLI tool release manifest URL");
13410
+ throw new Error("Ghostget local CLI tool artifact table is not canonical");
13411
+ const sourceUrl = tool.sourceUrl === undefined ? undefined : exactHttpsUrl(tool.sourceUrl, "Ghostget local CLI tool source URL");
13412
+ const releaseManifestSha256 = tool.releaseManifestSha256 === undefined ? undefined : digest(tool.releaseManifestSha256, "Ghostget local CLI tool release manifest hash");
13413
+ const releaseManifestUrl = tool.releaseManifestUrl === undefined ? undefined : exactHttpsUrl(tool.releaseManifestUrl, "Ghostget local CLI tool release manifest URL");
13413
13414
  if (releaseManifestSha256 === undefined !== (releaseManifestUrl === undefined))
13414
- throw new Error("Wrench local CLI tool release manifest provenance is malformed");
13415
+ throw new Error("Ghostget local CLI tool release manifest provenance is malformed");
13415
13416
  if (tool.versionScheme !== "semver" && tool.versionScheme !== "opaque") {
13416
- throw new Error("Wrench local CLI tool version scheme is malformed");
13417
+ throw new Error("Ghostget local CLI tool version scheme is malformed");
13417
13418
  }
13418
13419
  if (typeof tool.version !== "string" || tool.version.length < 1 || tool.version.length > 128)
13419
- throw new Error("Wrench local CLI tool version is malformed");
13420
+ throw new Error("Ghostget local CLI tool version is malformed");
13420
13421
  const version = tool.version;
13421
13422
  if (!wellFormedVisible(version) || tool.versionScheme === "semver" && !/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-(?:(?:0|[1-9]\d*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/u.test(version)) {
13422
- throw new Error("Wrench local CLI tool version is malformed");
13423
+ throw new Error("Ghostget local CLI tool version is malformed");
13423
13424
  }
13424
13425
  const hasReleaseCommit = tool.releaseCommit !== undefined;
13425
- const releaseCommit = hasReleaseCommit ? safeString(tool.releaseCommit, "Wrench local CLI tool release commit", 40) : undefined;
13426
+ const releaseCommit = hasReleaseCommit ? safeString(tool.releaseCommit, "Ghostget local CLI tool release commit", 40) : undefined;
13426
13427
  if (releaseCommit !== undefined && !/^[a-f0-9]{40}$/u.test(releaseCommit))
13427
- throw new Error("Wrench local CLI tool release commit is malformed");
13428
- const implementation = safeString(tool.implementation, "Wrench local CLI tool implementation", 256);
13428
+ throw new Error("Ghostget local CLI tool release commit is malformed");
13429
+ const implementation = safeString(tool.implementation, "Ghostget local CLI tool implementation", 256);
13429
13430
  if (!/^[A-Za-z0-9](?:[A-Za-z0-9._/+:-]{0,254}[A-Za-z0-9])?$/u.test(implementation)) {
13430
- throw new Error("Wrench local CLI tool implementation is malformed");
13431
+ throw new Error("Ghostget local CLI tool implementation is malformed");
13431
13432
  }
13432
13433
  return Object.freeze({
13433
13434
  schemaVersion: 1,
13434
- id: token(tool.id, "Wrench local CLI tool ID"),
13435
+ id: token(tool.id, "Ghostget local CLI tool ID"),
13435
13436
  implementation,
13436
13437
  versionScheme: tool.versionScheme,
13437
13438
  version,
@@ -13442,20 +13443,20 @@ function parseLocalCliToolIdentity(value) {
13442
13443
  });
13443
13444
  }
13444
13445
  function parseLocalCliContractIdentity(value) {
13445
- const identity = record(value, "Wrench local CLI contract identity");
13446
- assertExactKeys(identity, ["surface", "action", "version", "hash", "tool"], [], "Wrench local CLI contract identity");
13447
- const surface = providerSurfaceId(identity.surface, "Wrench local CLI surface");
13448
- const action = providerOperationName(identity.action, "Wrench local CLI action");
13446
+ const identity = record(value, "Ghostget local CLI contract identity");
13447
+ assertExactKeys(identity, ["surface", "action", "version", "hash", "tool"], [], "Ghostget local CLI contract identity");
13448
+ const surface = providerSurfaceId(identity.surface, "Ghostget local CLI surface");
13449
+ const action = providerOperationName(identity.action, "Ghostget local CLI action");
13449
13450
  return Object.freeze({
13450
13451
  surface,
13451
13452
  action,
13452
- version: safeInteger(identity.version, "Wrench local CLI contract version", 1, 1e6),
13453
- hash: digest(identity.hash, "Wrench local CLI contract hash"),
13453
+ version: safeInteger(identity.version, "Ghostget local CLI contract version", 1, 1e6),
13454
+ hash: digest(identity.hash, "Ghostget local CLI contract hash"),
13454
13455
  tool: parseLocalCliToolIdentity(identity.tool)
13455
13456
  });
13456
13457
  }
13457
13458
  function parseLiveReceipt(value, request, expectedInputHash) {
13458
- const receipt = record(value, "Wrench live receipt");
13459
+ const receipt = record(value, "Ghostget live receipt");
13459
13460
  const commonKeys = [
13460
13461
  "schemaVersion",
13461
13462
  "runId",
@@ -13475,66 +13476,66 @@ function parseLiveReceipt(value, request, expectedInputHash) {
13475
13476
  "error"
13476
13477
  ];
13477
13478
  if (receipt.schemaVersion === 2 && receipt.transport === "browser") {
13478
- assertExactKeys(receipt, commonKeys, [], "Wrench live receipt");
13479
+ assertExactKeys(receipt, commonKeys, [], "Ghostget live receipt");
13479
13480
  } else if (receipt.schemaVersion === 3 && receipt.transport === "provider-api") {
13480
- assertExactKeys(receipt, [...commonKeys, "providerContractHash"], [], "Wrench live receipt");
13481
+ assertExactKeys(receipt, [...commonKeys, "providerContractHash"], [], "Ghostget live receipt");
13481
13482
  } else if (receipt.schemaVersion === 4 && receipt.transport === "web-session-api") {
13482
- assertExactKeys(receipt, [...commonKeys, "webSessionContractHash"], [], "Wrench live receipt");
13483
+ assertExactKeys(receipt, [...commonKeys, "webSessionContractHash"], [], "Ghostget live receipt");
13483
13484
  } else if (receipt.schemaVersion === 5 && receipt.transport === "reviewed-template-api") {
13484
- assertExactKeys(receipt, [...commonKeys, "reviewedTemplateContractHash"], [], "Wrench live receipt");
13485
+ assertExactKeys(receipt, [...commonKeys, "reviewedTemplateContractHash"], [], "Ghostget live receipt");
13485
13486
  } else if (receipt.schemaVersion === 6 && receipt.transport === "portable-provider-plugin") {
13486
- assertExactKeys(receipt, [...commonKeys, "portablePluginContract"], [], "Wrench live receipt");
13487
+ assertExactKeys(receipt, [...commonKeys, "portablePluginContract"], [], "Ghostget live receipt");
13487
13488
  } else if (receipt.schemaVersion === 7 && receipt.transport === "local-cli") {
13488
- assertExactKeys(receipt, [...commonKeys, "localCliContract"], [], "Wrench live receipt");
13489
+ assertExactKeys(receipt, [...commonKeys, "localCliContract"], [], "Ghostget live receipt");
13489
13490
  } else {
13490
- throw new Error("Wrench live receipt schema and transport are malformed");
13491
- }
13492
- const adapter = record(receipt.adapter, "Wrench live receipt adapter");
13493
- const auth = record(receipt.auth, "Wrench live receipt auth");
13494
- const dispatch = record(receipt.dispatch, "Wrench live receipt dispatch");
13495
- assertExactKeys(adapter, ["id", "version", "hash"], [], "Wrench live receipt adapter");
13496
- assertExactKeys(auth, ["id", "hash", "kind"], [], "Wrench live receipt auth");
13497
- assertExactKeys(dispatch, ["planned", "started", "verified"], [], "Wrench live receipt dispatch");
13491
+ throw new Error("Ghostget live receipt schema and transport are malformed");
13492
+ }
13493
+ const adapter = record(receipt.adapter, "Ghostget live receipt adapter");
13494
+ const auth = record(receipt.auth, "Ghostget live receipt auth");
13495
+ const dispatch = record(receipt.dispatch, "Ghostget live receipt dispatch");
13496
+ assertExactKeys(adapter, ["id", "version", "hash"], [], "Ghostget live receipt adapter");
13497
+ assertExactKeys(auth, ["id", "hash", "kind"], [], "Ghostget live receipt auth");
13498
+ assertExactKeys(dispatch, ["planned", "started", "verified"], [], "Ghostget live receipt dispatch");
13498
13499
  if (receipt.risk !== "R1") {
13499
- throw new Error("Wrench live receipt risk is malformed");
13500
+ throw new Error("Ghostget live receipt risk is malformed");
13500
13501
  }
13501
13502
  const authKind = auth.kind;
13502
13503
  if (authKind !== "browser-profile" && authKind !== "cookie-source" && authKind !== "cookies-file" && authKind !== "linked-device-store" && authKind !== "oauth-token-file" && authKind !== PUBLIC_WEB_SESSION_AUTHORITY_KIND)
13503
- throw new Error("Wrench live receipt auth kind is malformed");
13504
+ throw new Error("Ghostget live receipt auth kind is malformed");
13504
13505
  if (receipt.dispatchStarted !== false) {
13505
- throw new Error("Wrench live receipt dispatch state is malformed");
13506
+ throw new Error("Ghostget live receipt dispatch state is malformed");
13506
13507
  }
13507
- const planned = safeInteger(dispatch.planned, "Wrench live receipt planned dispatch count", 0, Number.MAX_SAFE_INTEGER);
13508
- const started = safeInteger(dispatch.started, "Wrench live receipt started dispatch count", 0, Number.MAX_SAFE_INTEGER);
13509
- const verified = safeInteger(dispatch.verified, "Wrench live receipt verified dispatch count", 0, Number.MAX_SAFE_INTEGER);
13508
+ const planned = safeInteger(dispatch.planned, "Ghostget live receipt planned dispatch count", 0, Number.MAX_SAFE_INTEGER);
13509
+ const started = safeInteger(dispatch.started, "Ghostget live receipt started dispatch count", 0, Number.MAX_SAFE_INTEGER);
13510
+ const verified = safeInteger(dispatch.verified, "Ghostget live receipt verified dispatch count", 0, Number.MAX_SAFE_INTEGER);
13510
13511
  if (planned !== 0 || started !== 0 || verified !== 0) {
13511
- throw new Error("Wrench live receipt dispatch counts are inconsistent");
13512
+ throw new Error("Ghostget live receipt dispatch counts are inconsistent");
13512
13513
  }
13513
13514
  const status = parseReceiptStatus(receipt.status);
13514
- const finalOrigin = receipt.finalOrigin === null ? null : safeString(receipt.finalOrigin, "Wrench live receipt final origin", 4096);
13515
- const error = receipt.error === null ? null : boundedUtf8String(receipt.error, "Wrench live receipt error", MAX_RUN_RECEIPT_ERROR_BYTES);
13515
+ const finalOrigin = receipt.finalOrigin === null ? null : safeString(receipt.finalOrigin, "Ghostget live receipt final origin", 4096);
13516
+ const error = receipt.error === null ? null : boundedUtf8String(receipt.error, "Ghostget live receipt error", MAX_RUN_RECEIPT_ERROR_BYTES);
13516
13517
  if (receipt.planDigest !== null) {
13517
- throw new Error("Wrench live receipt plan digest is malformed");
13518
+ throw new Error("Ghostget live receipt plan digest is malformed");
13518
13519
  }
13519
- const startedAt = timestamp2(receipt.startedAt, "Wrench live receipt start time");
13520
- const finishedAt = timestamp2(receipt.finishedAt, "Wrench live receipt finish time");
13520
+ const startedAt = timestamp2(receipt.startedAt, "Ghostget live receipt start time");
13521
+ const finishedAt = timestamp2(receipt.finishedAt, "Ghostget live receipt finish time");
13521
13522
  if (startedAt > finishedAt) {
13522
- throw new Error("Wrench live receipt finished before it started");
13523
+ throw new Error("Ghostget live receipt finished before it started");
13523
13524
  }
13524
13525
  const common = Object.freeze({
13525
- runId: safeString(receipt.runId, "Wrench live receipt run ID", 64),
13526
+ runId: safeString(receipt.runId, "Ghostget live receipt run ID", 64),
13526
13527
  planDigest: null,
13527
13528
  adapter: Object.freeze({
13528
- id: safeString(adapter.id, "Wrench live receipt adapter ID", 64),
13529
- version: safeString(adapter.version, "Wrench live receipt adapter version", 64),
13530
- hash: digest(adapter.hash, "Wrench live receipt adapter hash")
13529
+ id: safeString(adapter.id, "Ghostget live receipt adapter ID", 64),
13530
+ version: safeString(adapter.version, "Ghostget live receipt adapter version", 64),
13531
+ hash: digest(adapter.hash, "Ghostget live receipt adapter hash")
13531
13532
  }),
13532
- operation: providerOperationName(receipt.operation, "Wrench live receipt operation"),
13533
+ operation: providerOperationName(receipt.operation, "Ghostget live receipt operation"),
13533
13534
  risk: "R1",
13534
- inputHash: digest(receipt.inputHash, "Wrench live receipt input hash"),
13535
+ inputHash: digest(receipt.inputHash, "Ghostget live receipt input hash"),
13535
13536
  auth: Object.freeze({
13536
- id: safeString(auth.id, "Wrench live receipt auth ID", 64),
13537
- hash: digest(auth.hash, "Wrench live receipt auth hash"),
13537
+ id: safeString(auth.id, "Ghostget live receipt auth ID", 64),
13538
+ hash: digest(auth.hash, "Ghostget live receipt auth hash"),
13538
13539
  kind: authKind
13539
13540
  }),
13540
13541
  status,
@@ -13550,18 +13551,18 @@ function parseLiveReceipt(value, request, expectedInputHash) {
13550
13551
  error
13551
13552
  });
13552
13553
  if (common.adapter.id !== request.adapterId || common.operation !== request.operationId)
13553
- throw new Error("Wrench live receipt route does not match its request");
13554
+ throw new Error("Ghostget live receipt route does not match its request");
13554
13555
  if (common.auth.id !== expectedRequestAuthId(request, common.auth.kind)) {
13555
- throw new Error("Wrench live receipt auth does not match its request");
13556
+ throw new Error("Ghostget live receipt auth does not match its request");
13556
13557
  }
13557
13558
  if (common.auth.kind === PUBLIC_WEB_SESSION_AUTHORITY_KIND) {
13558
13559
  const authority = publicWebSessionAuthority(request);
13559
13560
  if (receipt.schemaVersion !== 4 || receipt.transport !== "web-session-api" || common.auth.hash !== sha2563(canonicalJson2(authority))) {
13560
- throw new Error("Wrench live receipt public authority is malformed");
13561
+ throw new Error("Ghostget live receipt public authority is malformed");
13561
13562
  }
13562
13563
  }
13563
13564
  if (common.inputHash !== expectedInputHash) {
13564
- throw new Error("Wrench live receipt input does not match its request");
13565
+ throw new Error("Ghostget live receipt input does not match its request");
13565
13566
  }
13566
13567
  if (receipt.schemaVersion === 2 && receipt.transport === "browser") {
13567
13568
  return Object.freeze({ ...common, schemaVersion: 2, transport: "browser" });
@@ -13571,7 +13572,7 @@ function parseLiveReceipt(value, request, expectedInputHash) {
13571
13572
  ...common,
13572
13573
  schemaVersion: 3,
13573
13574
  transport: "provider-api",
13574
- providerContractHash: digest(receipt.providerContractHash, "Wrench live receipt provider contract hash")
13575
+ providerContractHash: digest(receipt.providerContractHash, "Ghostget live receipt provider contract hash")
13575
13576
  });
13576
13577
  }
13577
13578
  if (receipt.schemaVersion === 4 && receipt.transport === "web-session-api") {
@@ -13579,7 +13580,7 @@ function parseLiveReceipt(value, request, expectedInputHash) {
13579
13580
  ...common,
13580
13581
  schemaVersion: 4,
13581
13582
  transport: "web-session-api",
13582
- webSessionContractHash: digest(receipt.webSessionContractHash, "Wrench live receipt web-session contract hash")
13583
+ webSessionContractHash: digest(receipt.webSessionContractHash, "Ghostget live receipt web-session contract hash")
13583
13584
  });
13584
13585
  }
13585
13586
  if (receipt.schemaVersion === 5 && receipt.transport === "reviewed-template-api") {
@@ -13587,13 +13588,13 @@ function parseLiveReceipt(value, request, expectedInputHash) {
13587
13588
  ...common,
13588
13589
  schemaVersion: 5,
13589
13590
  transport: "reviewed-template-api",
13590
- reviewedTemplateContractHash: digest(receipt.reviewedTemplateContractHash, "Wrench live receipt reviewed-template contract hash")
13591
+ reviewedTemplateContractHash: digest(receipt.reviewedTemplateContractHash, "Ghostget live receipt reviewed-template contract hash")
13591
13592
  });
13592
13593
  }
13593
13594
  if (receipt.schemaVersion === 6 && receipt.transport === "portable-provider-plugin") {
13594
13595
  const portablePluginContract = parsePortableOperationIdentity(receipt.portablePluginContract);
13595
13596
  if (portablePluginContract.adapterId !== common.adapter.id || portablePluginContract.operation !== common.operation) {
13596
- throw new Error("Wrench live portable contract route is malformed");
13597
+ throw new Error("Ghostget live portable contract route is malformed");
13597
13598
  }
13598
13599
  return Object.freeze({
13599
13600
  ...common,
@@ -13605,7 +13606,7 @@ function parseLiveReceipt(value, request, expectedInputHash) {
13605
13606
  if (receipt.schemaVersion === 7 && receipt.transport === "local-cli") {
13606
13607
  const localCliContract = parseLocalCliContractIdentity(receipt.localCliContract);
13607
13608
  if (localCliContract.action !== common.operation) {
13608
- throw new Error("Wrench live local CLI contract route is malformed");
13609
+ throw new Error("Ghostget live local CLI contract route is malformed");
13609
13610
  }
13610
13611
  return Object.freeze({
13611
13612
  ...common,
@@ -13614,30 +13615,30 @@ function parseLiveReceipt(value, request, expectedInputHash) {
13614
13615
  localCliContract
13615
13616
  });
13616
13617
  }
13617
- throw new Error("Wrench live receipt schema and transport are malformed");
13618
+ throw new Error("Ghostget live receipt schema and transport are malformed");
13618
13619
  }
13619
13620
  function parseLiveResult(value, request, expectedInputHash) {
13620
- assertExactKeys(value, ["ok", "source", "status", "runId", "replayed", "receipt", "output", "cache"], ["readFailure"], "Wrench live response");
13621
+ assertExactKeys(value, ["ok", "source", "status", "runId", "replayed", "receipt", "output", "cache"], ["readFailure"], "Ghostget live response");
13621
13622
  if (value.source !== "live")
13622
- throw new Error("Wrench live response has the wrong source");
13623
+ throw new Error("Ghostget live response has the wrong source");
13623
13624
  const receipt = parseLiveReceipt(value.receipt, request, expectedInputHash);
13624
- const status = safeString(value.status, "Wrench live status", 32);
13625
- const responseRunId = safeString(value.runId, "Wrench live run ID", 64);
13625
+ const status = safeString(value.status, "Ghostget live status", 32);
13626
+ const responseRunId = safeString(value.runId, "Ghostget live run ID", 64);
13626
13627
  const expectedOk = receipt.status === "succeeded";
13627
13628
  if (status !== receipt.status || receipt.runId !== responseRunId || value.ok !== expectedOk) {
13628
- throw new Error("Wrench live response is not bound to its receipt");
13629
+ throw new Error("Ghostget live response is not bound to its receipt");
13629
13630
  }
13630
13631
  if (typeof value.replayed !== "boolean" || !("output" in value)) {
13631
- throw new Error("Wrench live response is incomplete");
13632
+ throw new Error("Ghostget live response is incomplete");
13632
13633
  }
13633
13634
  const cache = parseCacheOutcome(value.cache);
13634
13635
  const cacheMatchesReceipt = receipt.status === "succeeded" ? cache.status === "stored" || cache.status === "error" || cache.status === "skipped" : cache.status === "retained" || cache.status === "miss" || cache.status === "error" || cache.status === "skipped";
13635
13636
  if (!cacheMatchesReceipt) {
13636
- throw new Error("Wrench live cache outcome is inconsistent with its receipt");
13637
+ throw new Error("Ghostget live cache outcome is inconsistent with its receipt");
13637
13638
  }
13638
13639
  const live = receipt.status === "failed" ? (() => {
13639
13640
  if (value.output !== null) {
13640
- throw new Error("Wrench failed live response retained an output");
13641
+ throw new Error("Ghostget failed live response retained an output");
13641
13642
  }
13642
13643
  return Object.freeze({
13643
13644
  status: "failed",
@@ -13648,7 +13649,7 @@ function parseLiveResult(value, request, expectedInputHash) {
13648
13649
  });
13649
13650
  })() : (() => {
13650
13651
  if (value.readFailure !== undefined) {
13651
- throw new Error("Wrench successful live response included a read failure");
13652
+ throw new Error("Ghostget successful live response included a read failure");
13652
13653
  }
13653
13654
  return Object.freeze({
13654
13655
  status: "succeeded",
@@ -13665,22 +13666,22 @@ function parseLiveResult(value, request, expectedInputHash) {
13665
13666
  function assertLiveInvocationFences(request, options, executionIdentityBefore, identityBefore, parsed, activity) {
13666
13667
  const identityAfter = observeProjectionIdentity(request, options);
13667
13668
  if (!projectionIdentitiesMatch(identityBefore, identityAfter)) {
13668
- throw new Error(`Wrench projection identity changed while ${activity} was running; the live result was discarded`);
13669
+ throw new Error(`Ghostget projection identity changed while ${activity} was running; the live result was discarded`);
13669
13670
  }
13670
13671
  if (!executionIdentitiesMatch(executionIdentityBefore, receiptExecutionIdentity(parsed.live.receipt))) {
13671
- throw new Error(`Wrench execution identity changed while ${activity} was running; the live result was discarded`);
13672
+ throw new Error(`Ghostget execution identity changed while ${activity} was running; the live result was discarded`);
13672
13673
  }
13673
13674
  if (parsed.live.receipt.auth.hash !== identityBefore.authHash) {
13674
- throw new Error(`Wrench projection identity changed while ${activity} was running; the live result was discarded`);
13675
+ throw new Error(`Ghostget projection identity changed while ${activity} was running; the live result was discarded`);
13675
13676
  }
13676
13677
  if (identityBefore.status === "unbound") {
13677
13678
  if (parsed.cache.status !== "skipped") {
13678
- throw new Error(`Wrench projection identity changed while ${activity} was running; the live result was discarded`);
13679
+ throw new Error(`Ghostget projection identity changed while ${activity} was running; the live result was discarded`);
13679
13680
  }
13680
13681
  return;
13681
13682
  }
13682
13683
  if (parsed.cache.status === "skipped" || parsed.cache.status === "stored" && parsed.cache.publication.key !== identityBefore.key) {
13683
- throw new Error(`Wrench projection identity changed while ${activity} was running; the live result was discarded`);
13684
+ throw new Error(`Ghostget projection identity changed while ${activity} was running; the live result was discarded`);
13684
13685
  }
13685
13686
  }
13686
13687
  function invokeCapabilitySync(request, options = {}) {
@@ -13697,10 +13698,10 @@ function invokeCapabilitySync(request, options = {}) {
13697
13698
  return parsed.live;
13698
13699
  }
13699
13700
 
13700
- // node_modules/@hraness/wrench/dist/index-j1f3cp88.js
13701
- var WRENCH_VERSION = "0.16.8";
13701
+ // node_modules/@hraness/ghostget/dist/index-rxvsqb3f.js
13702
+ var GHOSTGET_VERSION = "0.17.3";
13702
13703
 
13703
- // node_modules/@hraness/wrench/dist/beeper-client.js
13704
+ // node_modules/@hraness/ghostget/dist/beeper-client.js
13704
13705
  import { spawnSync as spawnSync2 } from "child_process";
13705
13706
  import { existsSync as existsSync4 } from "fs";
13706
13707
  import { fileURLToPath as fileURLToPath3 } from "url";
@@ -13735,7 +13736,7 @@ var LOCAL_MESSAGE_BUNDLE_V1_ARTIFACTS = Object.freeze([
13735
13736
  Object.freeze({ path: "tombstones.ndjson", kind: "tombstone" })
13736
13737
  ]);
13737
13738
 
13738
- // node_modules/@hraness/wrench/dist/beeper-client.js
13739
+ // node_modules/@hraness/ghostget/dist/beeper-client.js
13739
13740
  import { types as nodeTypes4 } from "util";
13740
13741
  var wrench_web_adapter_default = {
13741
13742
  schemaVersion: 6,
@@ -17622,8 +17623,8 @@ var BEEPER_CONTACT_INTERACTION_TRANSFORM = Object.freeze({
17622
17623
  });
17623
17624
  var BEEPER_CONTACT_INTERACTION_IMPLEMENTATION = Object.freeze({
17624
17625
  producer: Object.freeze({
17625
- package: "@hraness/wrench",
17626
- version: WRENCH_VERSION
17626
+ package: "@hraness/ghostget",
17627
+ version: GHOSTGET_VERSION
17627
17628
  }),
17628
17629
  officialCli: Object.freeze({
17629
17630
  implementation: BEEPER_CLI_PIN.implementation,
@@ -18144,7 +18145,7 @@ function parseBeeperContactInteractionExportResult(value) {
18144
18145
  var MAX_STDERR_BYTES = 8 * 1024;
18145
18146
  var PROCESS_TIMEOUT_MS = 6 * 60 * 60 * 1000 + 60000;
18146
18147
  function fail22(message) {
18147
- throw new Error(`Wrench Beeper client: ${message}`);
18148
+ throw new Error(`Ghostget Beeper client: ${message}`);
18148
18149
  }
18149
18150
  function cliSourcePath2() {
18150
18151
  const besideSource = fileURLToPath3(new URL("./cli.ts", import.meta.url));
@@ -18153,11 +18154,11 @@ function cliSourcePath2() {
18153
18154
  const packagedSource = fileURLToPath3(new URL("../src/cli.ts", import.meta.url));
18154
18155
  if (existsSync4(packagedSource))
18155
18156
  return packagedSource;
18156
- return fail22("the installed Wrench CLI source is unavailable");
18157
+ return fail22("the installed Ghostget CLI source is unavailable");
18157
18158
  }
18158
18159
  function requireBunRuntime2() {
18159
18160
  if (typeof process.versions.bun !== "string") {
18160
- fail22("@hraness/wrench/beeper requires Bun to run the installed Wrench CLI");
18161
+ fail22("@hraness/ghostget/beeper requires Bun to run the installed Ghostget CLI");
18161
18162
  }
18162
18163
  }
18163
18164
  function plainDataObject(value, label) {
@@ -18391,7 +18392,7 @@ function recordSourceExecutionReceipt(database, input) {
18391
18392
  return { id: Number(inserted.lastInsertRowid), replayed: false };
18392
18393
  }
18393
18394
 
18394
- // src/local/wrench-adapter.ts
18395
+ // src/local/ghostget-adapter.ts
18395
18396
  var DIGEST3 = /^[a-f0-9]{64}$/u;
18396
18397
  var RUN_ID = /^(?:[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}|[a-z][a-z0-9._+-]{0,127})$/u;
18397
18398
  function contractSha256(receipt) {
@@ -18419,41 +18420,41 @@ function canonicalTimestamp(value, label) {
18419
18420
  }
18420
18421
  function boundedRunId(value) {
18421
18422
  if (!RUN_ID.test(value))
18422
- throw new Error("Wrench run ID is invalid");
18423
+ throw new Error("Ghostget run ID is invalid");
18423
18424
  return value;
18424
18425
  }
18425
- function validatePeopleBladeWrenchInvocation(result, request, policy) {
18426
+ function validatePeopleBladeGhostgetInvocation(result, request, policy) {
18426
18427
  const receipt = result.receipt;
18427
18428
  if (result.replayed || receipt.status !== "succeeded" || receipt.error !== null || receipt.planDigest !== null || receipt.risk !== "R1" || receipt.dispatchStarted || receipt.dispatch.planned !== 0 || receipt.dispatch.started !== 0 || receipt.dispatch.verified !== 0)
18428
- throw new Error("Wrench invocation crossed PeopleBlade's read-only execution boundary");
18429
+ throw new Error("Ghostget invocation crossed PeopleBlade's read-only execution boundary");
18429
18430
  if (receipt.adapter.id !== request.adapterId || receipt.adapter.version !== policy.adapterVersion || receipt.operation !== request.operationId || receipt.auth.id !== request.authId || receipt.auth.kind !== policy.authKind || receipt.transport !== policy.transport || receipt.finalOrigin !== policy.finalOrigin)
18430
- throw new Error("Wrench invocation route identity drifted");
18431
+ throw new Error("Ghostget invocation route identity drifted");
18431
18432
  if (receipt.transport === "local-cli") {
18432
18433
  const expected = policy.localCli;
18433
18434
  const actual = receipt.localCliContract;
18434
18435
  if (expected === undefined || actual.surface !== expected.surface || actual.action !== expected.action || actual.version !== expected.version || actual.tool.id !== expected.toolId || actual.tool.implementation !== expected.toolImplementation || actual.tool.versionScheme !== "semver" || actual.tool.version !== expected.toolVersion || actual.tool.releaseCommit !== expected.toolCommit || actual.tool.releaseManifestSha256 !== expected.toolReleaseManifestSha256)
18435
- throw new Error("Wrench local CLI contract identity drifted");
18436
+ throw new Error("Ghostget local CLI contract identity drifted");
18436
18437
  } else if (policy.localCli !== undefined) {
18437
- throw new Error("Wrench invocation did not use the required local CLI route");
18438
+ throw new Error("Ghostget invocation did not use the required local CLI route");
18438
18439
  }
18439
18440
  boundedRunId(receipt.runId);
18440
18441
  const expectedInput = sha256(canonicalJson(request.input));
18441
18442
  if (receipt.inputHash !== expectedInput || !DIGEST3.test(receipt.inputHash)) {
18442
- throw new Error("Wrench receipt does not bind the exact input");
18443
+ throw new Error("Ghostget receipt does not bind the exact input");
18443
18444
  }
18444
18445
  if (!DIGEST3.test(receipt.adapter.hash))
18445
- throw new Error("Wrench adapter identity is invalid");
18446
+ throw new Error("Ghostget adapter identity is invalid");
18446
18447
  if (policy.adapterSha256 !== undefined && receipt.adapter.hash !== policy.adapterSha256) {
18447
- throw new Error("Wrench adapter implementation drifted");
18448
+ throw new Error("Ghostget adapter implementation drifted");
18448
18449
  }
18449
18450
  const contract = contractSha256(receipt);
18450
18451
  if (contract !== policy.contractSha256 || !DIGEST3.test(policy.contractSha256)) {
18451
- throw new Error("Wrench operation contract identity drifted");
18452
+ throw new Error("Ghostget operation contract identity drifted");
18452
18453
  }
18453
- const startedAt = canonicalTimestamp(receipt.startedAt, "Wrench start");
18454
- const finishedAt = canonicalTimestamp(receipt.finishedAt, "Wrench finish");
18454
+ const startedAt = canonicalTimestamp(receipt.startedAt, "Ghostget start");
18455
+ const finishedAt = canonicalTimestamp(receipt.finishedAt, "Ghostget finish");
18455
18456
  if (finishedAt < startedAt)
18456
- throw new Error("Wrench receipt timing is invalid");
18457
+ throw new Error("Ghostget receipt timing is invalid");
18457
18458
  return {
18458
18459
  output: result.output,
18459
18460
  execution: {
@@ -18470,13 +18471,13 @@ function validatePeopleBladeWrenchInvocation(result, request, policy) {
18470
18471
  }
18471
18472
  };
18472
18473
  }
18473
- function callPeopleBladeWrench(request, invoke = invokeCapabilitySync) {
18474
+ function callPeopleBladeGhostget(request, invoke = invokeCapabilitySync) {
18474
18475
  return invoke(request);
18475
18476
  }
18476
18477
  function callPeopleBladeBeeperContactInteractions(request, exportInteractions = exportBeeperContactInteractionsSync) {
18477
18478
  return parseBeeperContactInteractionExportResult(exportInteractions(request));
18478
18479
  }
18479
- function ledgerPeopleBladeWrenchInvocation(database, input) {
18480
+ function ledgerPeopleBladeGhostgetInvocation(database, input) {
18480
18481
  const { receipt } = input.execution;
18481
18482
  return recordSourceExecutionReceipt(database, {
18482
18483
  provider: input.provider,
@@ -18542,21 +18543,21 @@ function canonicalTimestamp2(value, label) {
18542
18543
  function readBeeperContactInteractions(request, exportInteractions) {
18543
18544
  const result = callPeopleBladeBeeperContactInteractions(request, exportInteractions);
18544
18545
  if (result.receipt.auth.id !== request.authId || result.receipt.auth.kind !== "linked-device-store" || result.receipt.auth.provider !== "beeper" || result.receipt.operation !== "beeper.export-contact-interactions" || result.receipt.status !== "succeeded" || result.receipt.transport !== "linked-device")
18545
- throw new Error("Wrench Beeper interaction export route identity drifted");
18546
+ throw new Error("Ghostget Beeper interaction export route identity drifted");
18546
18547
  const expectedBounds = {
18547
18548
  limitChats: request.limitChats ?? null,
18548
18549
  limitMessages: request.limitMessages ?? null,
18549
18550
  maxParticipants: request.maxParticipants ?? null
18550
18551
  };
18551
18552
  if (canonicalJson(result.receipt.bounds) !== canonicalJson(expectedBounds)) {
18552
- throw new Error("Wrench Beeper interaction export did not bind the requested bounds");
18553
+ throw new Error("Ghostget Beeper interaction export did not bind the requested bounds");
18553
18554
  }
18554
18555
  if (result.receipt.output.summarySha256 !== result.output.integrity.summarySha256 || !DIGEST4.test(result.receipt.integrity.receiptSha256) || !DIGEST4.test(result.receipt.auth.identitySha256))
18555
- throw new Error("Wrench Beeper interaction export integrity drifted");
18556
+ throw new Error("Ghostget Beeper interaction export integrity drifted");
18556
18557
  canonicalTimestamp2(result.receipt.startedAt, "Beeper interaction export start");
18557
18558
  canonicalTimestamp2(result.receipt.finishedAt, "Beeper interaction export finish");
18558
18559
  if (result.receipt.finishedAt < result.receipt.startedAt) {
18559
- throw new Error("Wrench Beeper interaction export timing is invalid");
18560
+ throw new Error("Ghostget Beeper interaction export timing is invalid");
18560
18561
  }
18561
18562
  return result;
18562
18563
  }
@@ -18681,10 +18682,10 @@ function projectBeeperContactInteractions(summary2, coordinates) {
18681
18682
  }
18682
18683
 
18683
18684
  // src/local/providers/beeper-compatibility.ts
18684
- var BEEPER_WRENCH_COMPATIBILITY = Object.freeze({
18685
- wrench: Object.freeze({
18686
- version: "0.16.8",
18687
- commit: "b0cf2ecbc1113fcc8ef673a824be475c3d7bbb46"
18685
+ var BEEPER_GHOSTGET_COMPATIBILITY = Object.freeze({
18686
+ ghostget: Object.freeze({
18687
+ version: "0.17.3",
18688
+ commit: "67b53cc1917bb09a48b22042cc988c3afbc0aaf8"
18688
18689
  }),
18689
18690
  adapter: Object.freeze({
18690
18691
  id: "beeper-local",
@@ -18721,6 +18722,38 @@ var BEEPER_WRENCH_COMPATIBILITY = Object.freeze({
18721
18722
  commit: "b9c1714410139c2139b597338cd002d785653e85"
18722
18723
  })
18723
18724
  });
18725
+ var PREVIOUS_GHOSTGET_0171_BEEPER_SOURCE_BINDING_METADATA = Object.freeze({
18726
+ transport: "local-cli",
18727
+ wrenchVersion: "0.17.1",
18728
+ wrenchCommit: "b74ae2ac594bcf07c3def71dc4bb2e5a98c826dd",
18729
+ adapterId: "beeper-local",
18730
+ adapterVersion: "2.4.0",
18731
+ adapterSha256: "2714af7e821b799c1d0b57106e8e193cb9787e5a6da37e1269f4aae0710a4ddc",
18732
+ cliId: "beeper-cli",
18733
+ cliVersion: "0.6.2",
18734
+ cliCommit: "a416af06023449a87312dc11e54643fd9dc94b8c",
18735
+ contracts: Object.freeze({
18736
+ contactsList: "8048565547c2a09078528d0a35f7a0c3a2e8850b17b075dc572e8b59115fcb57",
18737
+ contactsSearch: "e57cdcc9012ed5fb8f956e16a2368e95adf0a6b8bb404f903e64df85061b1ca1",
18738
+ messagingSearch: "2fc54d139a54d19c31a82237e4b417994e12679db3da5fd71ec9265e3622b0bf"
18739
+ })
18740
+ });
18741
+ var PREVIOUS_WRENCH_0168_BEEPER_SOURCE_BINDING_METADATA = Object.freeze({
18742
+ transport: "local-cli",
18743
+ wrenchVersion: "0.16.8",
18744
+ wrenchCommit: "b0cf2ecbc1113fcc8ef673a824be475c3d7bbb46",
18745
+ adapterId: "beeper-local",
18746
+ adapterVersion: "2.4.0",
18747
+ adapterSha256: "2714af7e821b799c1d0b57106e8e193cb9787e5a6da37e1269f4aae0710a4ddc",
18748
+ cliId: "beeper-cli",
18749
+ cliVersion: "0.6.2",
18750
+ cliCommit: "a416af06023449a87312dc11e54643fd9dc94b8c",
18751
+ contracts: Object.freeze({
18752
+ contactsList: "8048565547c2a09078528d0a35f7a0c3a2e8850b17b075dc572e8b59115fcb57",
18753
+ contactsSearch: "e57cdcc9012ed5fb8f956e16a2368e95adf0a6b8bb404f903e64df85061b1ca1",
18754
+ messagingSearch: "2fc54d139a54d19c31a82237e4b417994e12679db3da5fd71ec9265e3622b0bf"
18755
+ })
18756
+ });
18724
18757
  var PEOPLEBLADE_010_WRENCH_0150_BEEPER_SOURCE_BINDING_METADATA = Object.freeze({
18725
18758
  transport: "local-cli",
18726
18759
  wrenchVersion: "0.15.0",
@@ -18818,15 +18851,15 @@ var BEEPER_INTERACTION_EXPORT_COMPATIBILITY = Object.freeze({
18818
18851
  sourceVersion: "1.1.0",
18819
18852
  transformId: "beeper-direct-contact-interactions",
18820
18853
  transformVersion: 1,
18821
- wrenchVersion: BEEPER_WRENCH_COMPATIBILITY.wrench.version,
18854
+ wrenchVersion: BEEPER_GHOSTGET_COMPATIBILITY.ghostget.version,
18822
18855
  platform: "darwin-arm64"
18823
18856
  });
18824
18857
  function beeperSourceBindingMetadata() {
18825
- const compatibility = BEEPER_WRENCH_COMPATIBILITY;
18858
+ const compatibility = BEEPER_GHOSTGET_COMPATIBILITY;
18826
18859
  return Object.freeze({
18827
18860
  transport: compatibility.adapter.transport,
18828
- wrenchVersion: compatibility.wrench.version,
18829
- wrenchCommit: compatibility.wrench.commit,
18861
+ wrenchVersion: compatibility.ghostget.version,
18862
+ wrenchCommit: compatibility.ghostget.commit,
18830
18863
  adapterId: compatibility.adapter.id,
18831
18864
  adapterVersion: compatibility.adapter.version,
18832
18865
  adapterSha256: compatibility.adapter.sha256,
@@ -18844,11 +18877,11 @@ function beeperSourceBindingMetadata() {
18844
18877
  // src/local/providers/beeper.ts
18845
18878
  var PROVIDER4 = "beeper";
18846
18879
  var MODE3 = "wrench-contacts-v1";
18847
- var ADAPTER_ID = BEEPER_WRENCH_COMPATIBILITY.adapter.id;
18848
- var ADAPTER_VERSION = BEEPER_WRENCH_COMPATIBILITY.adapter.version;
18849
- var ADAPTER_SHA256 = BEEPER_WRENCH_COMPATIBILITY.adapter.sha256;
18850
- var CONTRACT_SHA256 = BEEPER_WRENCH_COMPATIBILITY.operations["contacts.list"].sha256;
18851
- var FINAL_ORIGIN = BEEPER_WRENCH_COMPATIBILITY.adapter.origin;
18880
+ var ADAPTER_ID = BEEPER_GHOSTGET_COMPATIBILITY.adapter.id;
18881
+ var ADAPTER_VERSION = BEEPER_GHOSTGET_COMPATIBILITY.adapter.version;
18882
+ var ADAPTER_SHA256 = BEEPER_GHOSTGET_COMPATIBILITY.adapter.sha256;
18883
+ var CONTRACT_SHA256 = BEEPER_GHOSTGET_COMPATIBILITY.operations["contacts.list"].sha256;
18884
+ var FINAL_ORIGIN = BEEPER_GHOSTGET_COMPATIBILITY.adapter.origin;
18852
18885
  var MAX_ACCOUNTS = 128;
18853
18886
  var MAX_CONTACTS2 = 200;
18854
18887
  var SUBJECT = /^beeper:local:[a-f0-9]{64}$/u;
@@ -19011,22 +19044,22 @@ function parseContact(value, label) {
19011
19044
  }
19012
19045
  function parseBeeperContactPage(value, input, authId) {
19013
19046
  const request = { adapterId: ADAPTER_ID, operationId: "contacts.list", authId, input };
19014
- const validated = validatePeopleBladeWrenchInvocation(value, request, {
19047
+ const validated = validatePeopleBladeGhostgetInvocation(value, request, {
19015
19048
  adapterVersion: ADAPTER_VERSION,
19016
19049
  adapterSha256: ADAPTER_SHA256,
19017
19050
  authKind: "linked-device-store",
19018
- transport: BEEPER_WRENCH_COMPATIBILITY.adapter.transport,
19051
+ transport: BEEPER_GHOSTGET_COMPATIBILITY.adapter.transport,
19019
19052
  contractSha256: CONTRACT_SHA256,
19020
19053
  finalOrigin: FINAL_ORIGIN,
19021
19054
  localCli: {
19022
- surface: BEEPER_WRENCH_COMPATIBILITY.adapter.surface,
19055
+ surface: BEEPER_GHOSTGET_COMPATIBILITY.adapter.surface,
19023
19056
  action: "contacts.list",
19024
- version: BEEPER_WRENCH_COMPATIBILITY.operations["contacts.list"].version,
19025
- toolId: BEEPER_WRENCH_COMPATIBILITY.cli.id,
19026
- toolImplementation: BEEPER_WRENCH_COMPATIBILITY.cli.implementation,
19027
- toolVersion: BEEPER_WRENCH_COMPATIBILITY.cli.version,
19028
- toolCommit: BEEPER_WRENCH_COMPATIBILITY.cli.commit,
19029
- toolReleaseManifestSha256: BEEPER_WRENCH_COMPATIBILITY.cli.releaseManifestSha256
19057
+ version: BEEPER_GHOSTGET_COMPATIBILITY.operations["contacts.list"].version,
19058
+ toolId: BEEPER_GHOSTGET_COMPATIBILITY.cli.id,
19059
+ toolImplementation: BEEPER_GHOSTGET_COMPATIBILITY.cli.implementation,
19060
+ toolVersion: BEEPER_GHOSTGET_COMPATIBILITY.cli.version,
19061
+ toolCommit: BEEPER_GHOSTGET_COMPATIBILITY.cli.commit,
19062
+ toolReleaseManifestSha256: BEEPER_GHOSTGET_COMPATIBILITY.cli.releaseManifestSha256
19030
19063
  }
19031
19064
  });
19032
19065
  const execution = validated.execution;
@@ -19044,7 +19077,7 @@ function parseBeeperContactPage(value, input, authId) {
19044
19077
  "continuation"
19045
19078
  ], "Beeper contact output");
19046
19079
  if (output.provider !== "beeper" || output.operation !== "contacts.list" || output.projection !== "bounded-local-desktop-api" || output.query !== null) {
19047
- throw new Error("Wrench Beeper output changed projection semantics");
19080
+ throw new Error("Ghostget Beeper output changed projection semantics");
19048
19081
  }
19049
19082
  const accountSubject = text2(output.accountSubject, "Beeper account subject", 128);
19050
19083
  if (!SUBJECT.test(accountSubject))
@@ -19198,7 +19231,7 @@ function sameExecution(left, right) {
19198
19231
  return left.authId === right.authId && left.authSha256 === right.authSha256 && left.adapterSha256 === right.adapterSha256 && left.contractSha256 === right.contractSha256;
19199
19232
  }
19200
19233
  function ledgerBeeperContactRead(database, account, page) {
19201
- ledgerPeopleBladeWrenchInvocation(database, {
19234
+ ledgerPeopleBladeGhostgetInvocation(database, {
19202
19235
  provider: PROVIDER4,
19203
19236
  accountKey: account,
19204
19237
  capability: "contacts",
@@ -19273,8 +19306,14 @@ function classifyReviewedBeeperPredecessor(value, currentMetadata) {
19273
19306
  if (encoded === canonicalJson(PREVIOUS_WRENCH_0167_BEEPER_SOURCE_BINDING_METADATA)) {
19274
19307
  return "wrench-0.16.7-beeper-2.4";
19275
19308
  }
19276
- if (encoded === currentMetadata)
19309
+ if (encoded === canonicalJson(PREVIOUS_WRENCH_0168_BEEPER_SOURCE_BINDING_METADATA)) {
19277
19310
  return "wrench-0.16.8-beeper-2.4";
19311
+ }
19312
+ if (encoded === canonicalJson(PREVIOUS_GHOSTGET_0171_BEEPER_SOURCE_BINDING_METADATA)) {
19313
+ return "ghostget-0.17.1-beeper-2.4";
19314
+ }
19315
+ if (encoded === currentMetadata)
19316
+ return "ghostget-0.17.3-beeper-2.4";
19278
19317
  return null;
19279
19318
  }
19280
19319
  function assertStoredRealmInventory(database, sourceBindingId, accounts, storedSha256) {
@@ -19322,7 +19361,7 @@ function rebindBeeperSource(database, options = {}) {
19322
19361
  if (!AUTH_ID.test(authId))
19323
19362
  throw new Error("Beeper auth ID must be lowercase kebab text.");
19324
19363
  const input = { limit: 1 };
19325
- const invocation = callPeopleBladeWrench({
19364
+ const invocation = callPeopleBladeGhostget({
19326
19365
  adapterId: ADAPTER_ID,
19327
19366
  operationId: "contacts.list",
19328
19367
  authId,
@@ -19353,7 +19392,7 @@ function rebindBeeperSource(database, options = {}) {
19353
19392
  if (predecessor === null) {
19354
19393
  throw new Error("Beeper rebind source coordinates are not a reviewed predecessor.");
19355
19394
  }
19356
- const metadataOnly = sameIdentity && (predecessor === "peopleblade-0.1.0-wrench-0.15-beeper-2.0" || predecessor === "wrench-0.16.7-beeper-2.4");
19395
+ const metadataOnly = sameIdentity && (predecessor === "peopleblade-0.1.0-wrench-0.15-beeper-2.0" || predecessor === "wrench-0.16.7-beeper-2.4" || predecessor === "wrench-0.16.8-beeper-2.4" || predecessor === "ghostget-0.17.1-beeper-2.4");
19357
19396
  if (sameIdentity && !metadataOnly) {
19358
19397
  throw new Error("Beeper metadata-only rebind requires an exact reviewed same-identity predecessor.");
19359
19398
  }
@@ -19381,11 +19420,11 @@ function rebindBeeperSource(database, options = {}) {
19381
19420
  subjectSha256: next.subjectSha256,
19382
19421
  authSha256: next.authSha256,
19383
19422
  metadataSha256: sha256(currentMetadata),
19384
- wrenchVersion: BEEPER_WRENCH_COMPATIBILITY.wrench.version,
19385
- adapterVersion: BEEPER_WRENCH_COMPATIBILITY.adapter.version,
19386
- adapterSha256: BEEPER_WRENCH_COMPATIBILITY.adapter.sha256,
19387
- transport: BEEPER_WRENCH_COMPATIBILITY.adapter.transport,
19388
- contractSha256: BEEPER_WRENCH_COMPATIBILITY.operations["contacts.list"].sha256
19423
+ wrenchVersion: BEEPER_GHOSTGET_COMPATIBILITY.ghostget.version,
19424
+ adapterVersion: BEEPER_GHOSTGET_COMPATIBILITY.adapter.version,
19425
+ adapterSha256: BEEPER_GHOSTGET_COMPATIBILITY.adapter.sha256,
19426
+ transport: BEEPER_GHOSTGET_COMPATIBILITY.adapter.transport,
19427
+ contractSha256: BEEPER_GHOSTGET_COMPATIBILITY.operations["contacts.list"].sha256
19389
19428
  },
19390
19429
  inventory: {
19391
19430
  accounts: inventory.accounts.length,
@@ -19441,7 +19480,7 @@ function syncBeeperContacts(database, options = {}) {
19441
19480
  const limit = options.contactLimit ?? DEFAULT_BEEPER_CONTACT_LIMIT;
19442
19481
  if (!Number.isSafeInteger(limit) || limit < 1 || limit > MAX_CONTACTS2)
19443
19482
  throw new Error("Beeper contact limit must be from 1 through 200.");
19444
- const invoke = (input) => callPeopleBladeWrench({
19483
+ const invoke = (input) => callPeopleBladeGhostget({
19445
19484
  adapterId: ADAPTER_ID,
19446
19485
  operationId: "contacts.list",
19447
19486
  authId,
@@ -19705,12 +19744,12 @@ function beeperStats(database) {
19705
19744
  var PROVIDER5 = "beeper";
19706
19745
  var MODE4 = "wrench-targeted-search-v1";
19707
19746
  var ACCEPTANCE_MODE = "search-candidate-acceptance-v1";
19708
- var ADAPTER_ID2 = BEEPER_WRENCH_COMPATIBILITY.adapter.id;
19709
- var ADAPTER_VERSION2 = BEEPER_WRENCH_COMPATIBILITY.adapter.version;
19710
- var ADAPTER_SHA2562 = BEEPER_WRENCH_COMPATIBILITY.adapter.sha256;
19711
- var CONTACTS_SEARCH_CONTRACT_SHA256 = BEEPER_WRENCH_COMPATIBILITY.operations["contacts.search"].sha256;
19712
- var MESSAGING_SEARCH_CONTRACT_SHA256 = BEEPER_WRENCH_COMPATIBILITY.operations["messaging.search"].sha256;
19713
- var FINAL_ORIGIN2 = BEEPER_WRENCH_COMPATIBILITY.adapter.origin;
19747
+ var ADAPTER_ID2 = BEEPER_GHOSTGET_COMPATIBILITY.adapter.id;
19748
+ var ADAPTER_VERSION2 = BEEPER_GHOSTGET_COMPATIBILITY.adapter.version;
19749
+ var ADAPTER_SHA2562 = BEEPER_GHOSTGET_COMPATIBILITY.adapter.sha256;
19750
+ var CONTACTS_SEARCH_CONTRACT_SHA256 = BEEPER_GHOSTGET_COMPATIBILITY.operations["contacts.search"].sha256;
19751
+ var MESSAGING_SEARCH_CONTRACT_SHA256 = BEEPER_GHOSTGET_COMPATIBILITY.operations["messaging.search"].sha256;
19752
+ var FINAL_ORIGIN2 = BEEPER_GHOSTGET_COMPATIBILITY.adapter.origin;
19714
19753
  var MAX_QUERIES = 50;
19715
19754
  var MAX_RESULTS = 20;
19716
19755
  var SHA2562 = /^[a-f0-9]{64}$/u;
@@ -19854,7 +19893,7 @@ function parseConversation(value, label) {
19854
19893
  }
19855
19894
  function parseSearchPage(value, operation, input, authId) {
19856
19895
  const expectedContract = operation === "contacts.search" ? CONTACTS_SEARCH_CONTRACT_SHA256 : MESSAGING_SEARCH_CONTRACT_SHA256;
19857
- const validated = validatePeopleBladeWrenchInvocation(value, {
19896
+ const validated = validatePeopleBladeGhostgetInvocation(value, {
19858
19897
  adapterId: ADAPTER_ID2,
19859
19898
  operationId: operation,
19860
19899
  authId,
@@ -19863,18 +19902,18 @@ function parseSearchPage(value, operation, input, authId) {
19863
19902
  adapterVersion: ADAPTER_VERSION2,
19864
19903
  adapterSha256: ADAPTER_SHA2562,
19865
19904
  authKind: "linked-device-store",
19866
- transport: BEEPER_WRENCH_COMPATIBILITY.adapter.transport,
19905
+ transport: BEEPER_GHOSTGET_COMPATIBILITY.adapter.transport,
19867
19906
  contractSha256: expectedContract,
19868
19907
  finalOrigin: FINAL_ORIGIN2,
19869
19908
  localCli: {
19870
- surface: BEEPER_WRENCH_COMPATIBILITY.adapter.surface,
19909
+ surface: BEEPER_GHOSTGET_COMPATIBILITY.adapter.surface,
19871
19910
  action: operation,
19872
- version: BEEPER_WRENCH_COMPATIBILITY.operations[operation].version,
19873
- toolId: BEEPER_WRENCH_COMPATIBILITY.cli.id,
19874
- toolImplementation: BEEPER_WRENCH_COMPATIBILITY.cli.implementation,
19875
- toolVersion: BEEPER_WRENCH_COMPATIBILITY.cli.version,
19876
- toolCommit: BEEPER_WRENCH_COMPATIBILITY.cli.commit,
19877
- toolReleaseManifestSha256: BEEPER_WRENCH_COMPATIBILITY.cli.releaseManifestSha256
19911
+ version: BEEPER_GHOSTGET_COMPATIBILITY.operations[operation].version,
19912
+ toolId: BEEPER_GHOSTGET_COMPATIBILITY.cli.id,
19913
+ toolImplementation: BEEPER_GHOSTGET_COMPATIBILITY.cli.implementation,
19914
+ toolVersion: BEEPER_GHOSTGET_COMPATIBILITY.cli.version,
19915
+ toolCommit: BEEPER_GHOSTGET_COMPATIBILITY.cli.commit,
19916
+ toolReleaseManifestSha256: BEEPER_GHOSTGET_COMPATIBILITY.cli.releaseManifestSha256
19878
19917
  }
19879
19918
  });
19880
19919
  const execution = validated.execution;
@@ -19892,7 +19931,7 @@ function parseSearchPage(value, operation, input, authId) {
19892
19931
  "completeness"
19893
19932
  ], "Beeper search output");
19894
19933
  if (output.provider !== "beeper" || output.operation !== operation || output.projection !== "bounded-local-desktop-search" || output.searchSemantics !== "provider-fuzzy-candidates")
19895
- throw new Error("Wrench Beeper search changed projection semantics");
19934
+ throw new Error("Ghostget Beeper search changed projection semantics");
19896
19935
  const accountSubject = text3(output.accountSubject, "Beeper account subject", 128);
19897
19936
  if (!/^beeper:local:[a-f0-9]{64}$/u.test(accountSubject))
19898
19937
  throw new Error("Beeper account subject is invalid");
@@ -20084,7 +20123,7 @@ function stageCandidates(database, snapshot, candidates, query, service) {
20084
20123
  function ledgerSearchExecution(database, account, operation, execution) {
20085
20124
  if (execution.receipt.operation !== operation)
20086
20125
  throw new Error("Beeper search execution operation drifted");
20087
- return !ledgerPeopleBladeWrenchInvocation(database, {
20126
+ return !ledgerPeopleBladeGhostgetInvocation(database, {
20088
20127
  provider: PROVIDER5,
20089
20128
  accountKey: account,
20090
20129
  capability: "search_people",
@@ -20114,7 +20153,7 @@ function backfillBeeperSearch(database, options) {
20114
20153
  }
20115
20154
  return normalized;
20116
20155
  }));
20117
- const invoke = (operation, input) => callPeopleBladeWrench({ adapterId: ADAPTER_ID2, operationId: operation, authId, input }, options.invoke);
20156
+ const invoke = (operation, input) => callPeopleBladeGhostget({ adapterId: ADAPTER_ID2, operationId: operation, authId, input }, options.invoke);
20118
20157
  const inventoryInput = { limit: 1 };
20119
20158
  const inventory = parseBeeperContactPage(invoke("contacts.list", inventoryInput), inventoryInput, authId);
20120
20159
  assertSourceBindingCurrent(database, PROVIDER5, {
@@ -20124,7 +20163,7 @@ function backfillBeeperSearch(database, options) {
20124
20163
  metadata: beeperSourceBindingMetadata()
20125
20164
  });
20126
20165
  let executionReceiptsRecorded = 0;
20127
- if (!ledgerPeopleBladeWrenchInvocation(database, {
20166
+ if (!ledgerPeopleBladeGhostgetInvocation(database, {
20128
20167
  provider: PROVIDER5,
20129
20168
  accountKey: `beeper:binding:${sha256(inventory.accountSubject)}`,
20130
20169
  capability: "contacts",
@@ -20753,7 +20792,7 @@ function parseContact3(value, label, spec) {
20753
20792
  };
20754
20793
  }
20755
20794
  function parsePage(value, input, auth, spec) {
20756
- const validated = validatePeopleBladeWrenchInvocation(value, {
20795
+ const validated = validatePeopleBladeGhostgetInvocation(value, {
20757
20796
  adapterId: "gmail",
20758
20797
  operationId: "contacts.list",
20759
20798
  authId: auth,
@@ -20766,20 +20805,20 @@ function parsePage(value, input, auth, spec) {
20766
20805
  finalOrigin: null
20767
20806
  });
20768
20807
  const execution = validated.execution;
20769
- const output = record5(validated.output, "Wrench output");
20770
- exact3(output, ["provider", "operation", "accountSubject", "contactCollection", "statsIncluded", "contacts", "nextCursor", "totalItems", "statsScanLimit", "statsScope"], "Wrench output");
20808
+ const output = record5(validated.output, "Ghostget output");
20809
+ exact3(output, ["provider", "operation", "accountSubject", "contactCollection", "statsIncluded", "contacts", "nextCursor", "totalItems", "statsScanLimit", "statsScope"], "Ghostget output");
20771
20810
  if (output.provider !== "gmail" || output.operation !== "contacts.list" || output.contactCollection !== spec.id || output.statsIncluded !== false || output.statsScanLimit !== null || output.statsScope !== "not-requested") {
20772
- throw new Error("Wrench Gmail contact projection drifted");
20811
+ throw new Error("Ghostget Gmail contact projection drifted");
20773
20812
  }
20774
- const accountSubject = text4(output.accountSubject, "Wrench account subject", 254).toLowerCase();
20813
+ const accountSubject = text4(output.accountSubject, "Ghostget account subject", 254).toLowerCase();
20775
20814
  if (!ACCOUNT.test(accountSubject) || accountSubject !== output.accountSubject)
20776
- throw new Error("Wrench Gmail account subject is invalid");
20815
+ throw new Error("Ghostget Gmail account subject is invalid");
20777
20816
  const limit = integer5(input.limit, "Google page limit", 1, 100);
20778
- const contacts = array2(output.contacts, "Wrench contacts", limit).map((entry, index) => parseContact3(entry, `contacts[${index}]`, spec));
20817
+ const contacts = array2(output.contacts, "Ghostget contacts", limit).map((entry, index) => parseContact3(entry, `contacts[${index}]`, spec));
20779
20818
  if (new Set(contacts.map((contact) => contact.resourceName)).size !== contacts.length)
20780
- throw new Error("Wrench contact page contains duplicate resources");
20781
- const nextCursor = optionalText2(output.nextCursor, "Wrench next cursor", 4096);
20782
- const totalItems = output.totalItems === null ? null : integer5(output.totalItems, "Wrench total items", 0, MAX_CONTACTS3);
20819
+ throw new Error("Ghostget contact page contains duplicate resources");
20820
+ const nextCursor = optionalText2(output.nextCursor, "Ghostget next cursor", 4096);
20821
+ const totalItems = output.totalItems === null ? null : integer5(output.totalItems, "Ghostget total items", 0, MAX_CONTACTS3);
20783
20822
  return { collection: spec.id, input, accountSubject, contacts, nextCursor, totalItems, execution };
20784
20823
  }
20785
20824
  function authId(value) {
@@ -20788,11 +20827,11 @@ function authId(value) {
20788
20827
  throw new Error("Google auth ID is invalid");
20789
20828
  return parsed;
20790
20829
  }
20791
- function wrenchGoogleContactsSnapshot(options = {}, collection = "contacts") {
20830
+ function ghostgetGoogleContactsSnapshot(options = {}, collection = "contacts") {
20792
20831
  const spec = collectionSpec(collection);
20793
20832
  const auth = authId(options.authId ?? DEFAULT_GOOGLE_AUTH);
20794
20833
  const pageSize = options.pageSize === undefined ? DEFAULT_GOOGLE_PAGE_SIZE : integer5(options.pageSize, "Google page size", 1, 100);
20795
- const call = (input) => callPeopleBladeWrench({
20834
+ const call = (input) => callPeopleBladeGhostget({
20796
20835
  adapterId: "gmail",
20797
20836
  operationId: "contacts.list",
20798
20837
  authId: auth,
@@ -20815,7 +20854,7 @@ function wrenchGoogleContactsSnapshot(options = {}, collection = "contacts") {
20815
20854
  const page = parsePage(call(input), input, auth, spec);
20816
20855
  const priorExecution = pages.at(-1)?.execution;
20817
20856
  if (priorExecution !== undefined && Date.parse(page.execution.startedAt) < Date.parse(priorExecution.finishedAt)) {
20818
- throw new Error("Wrench Google page timing moved backwards during pagination");
20857
+ throw new Error("Ghostget Google page timing moved backwards during pagination");
20819
20858
  }
20820
20859
  if (account !== null && page.accountSubject !== account)
20821
20860
  throw new Error("Google account changed during pagination");
@@ -20844,25 +20883,25 @@ function wrenchGoogleContactsSnapshot(options = {}, collection = "contacts") {
20844
20883
  throw new Error("Google contact total is incomplete or exceeds its bound");
20845
20884
  const executions = pages.map((page) => page.execution);
20846
20885
  if (new Set(executions.map((item) => item.runId)).size !== executions.length)
20847
- throw new Error("Wrench reused a Google run ID");
20886
+ throw new Error("Ghostget reused a Google run ID");
20848
20887
  const first = executions[0];
20849
20888
  for (const item of executions)
20850
20889
  if (item.authId !== first.authId || item.authSha256 !== first.authSha256 || item.adapterVersion !== first.adapterVersion || item.adapterSha256 !== first.adapterSha256 || item.contractSha256 !== first.contractSha256) {
20851
- throw new Error("Wrench Google execution identity changed during pagination");
20890
+ throw new Error("Ghostget Google execution identity changed during pagination");
20852
20891
  }
20853
20892
  return { schemaVersion: 1, provider: "google-contacts", collection: spec.id, accountSubject: account, authId: auth, pages };
20854
20893
  }
20855
- function wrenchGoogleContactsSnapshots(options = {}) {
20856
- const snapshots = COLLECTIONS.map((spec) => wrenchGoogleContactsSnapshot(options, spec.id));
20894
+ function ghostgetGoogleContactsSnapshots(options = {}) {
20895
+ const snapshots = COLLECTIONS.map((spec) => ghostgetGoogleContactsSnapshot(options, spec.id));
20857
20896
  const first = snapshots[0];
20858
20897
  const executions = snapshots.flatMap((snapshot) => snapshot.pages.map((page) => page.execution));
20859
20898
  if (new Set(executions.map((execution) => execution.runId)).size !== executions.length) {
20860
- throw new Error("Wrench reused a Google run ID across contact collections");
20899
+ throw new Error("Ghostget reused a Google run ID across contact collections");
20861
20900
  }
20862
20901
  for (const snapshot of snapshots) {
20863
20902
  const execution = snapshot.pages[0].execution;
20864
20903
  if (snapshot.accountSubject !== first.accountSubject || snapshot.authId !== first.authId || execution.authSha256 !== first.pages[0].execution.authSha256 || execution.adapterVersion !== first.pages[0].execution.adapterVersion || execution.adapterSha256 !== first.pages[0].execution.adapterSha256 || execution.contractSha256 !== first.pages[0].execution.contractSha256) {
20865
- throw new Error("Wrench Google execution identity changed across contact collections");
20904
+ throw new Error("Ghostget Google execution identity changed across contact collections");
20866
20905
  }
20867
20906
  }
20868
20907
  return snapshots;
@@ -21188,10 +21227,10 @@ function importGoogleContactsSnapshots(database, snapshots) {
21188
21227
  }
21189
21228
  }
21190
21229
  function syncGoogleContacts(database, options = {}) {
21191
- const snapshots = wrenchGoogleContactsSnapshots(options);
21230
+ const snapshots = ghostgetGoogleContactsSnapshots(options);
21192
21231
  for (const snapshot of snapshots)
21193
21232
  for (const page of snapshot.pages) {
21194
- ledgerPeopleBladeWrenchInvocation(database, {
21233
+ ledgerPeopleBladeGhostgetInvocation(database, {
21195
21234
  provider: PROVIDER6,
21196
21235
  accountKey: snapshot.accountSubject,
21197
21236
  capability: "contacts",
@@ -24570,6 +24609,9 @@ function linkedInAccountKey(value) {
24570
24609
  }
24571
24610
  return key;
24572
24611
  }
24612
+ function canonicalLinkedInProfileUrl(value, label) {
24613
+ return profileUrl(value, label);
24614
+ }
24573
24615
  function ownerProfile(messages, supplied) {
24574
24616
  const explicit = supplied === undefined ? null : profileUrl(supplied, "LinkedIn archive owner profile URL");
24575
24617
  if (supplied !== undefined && explicit === null)
@@ -24974,6 +25016,342 @@ function linkedInStatsAll(database) {
24974
25016
  WHERE account.provider='linkedin' ORDER BY account.account_key`, MODE7).map((row) => ({ ...row, remote_set_complete: false }));
24975
25017
  }
24976
25018
 
25019
+ // src/local/providers/linkedin-contact-info.ts
25020
+ var LINKEDIN_CONTACT_INFO_ADAPTER_ID = "linkedin-web";
25021
+ var LINKEDIN_CONTACT_INFO_OPERATION_ID = "contacts.read";
25022
+ var LINKEDIN_CONTACT_INFO_ADAPTER_VERSION = "1.23.0";
25023
+ var LINKEDIN_CONTACT_INFO_CONTRACT_SHA256 = "8f80c234ca2b7706a49a5000012a11da78a36d38f3023c21854a240e16a13f43";
25024
+ var DEFAULT_LINKEDIN_AUTH = "linkedin-main";
25025
+ var PROVIDER11 = "linkedin";
25026
+ var MODE8 = "ghostget-contact-info";
25027
+ var RECORD_KIND = "contact-info";
25028
+ var OBSERVATION_BASIS2 = "linkedin-contact-info";
25029
+ var OBSERVATION_PRIORITY2 = 720;
25030
+ var MAX_PHONES = 8;
25031
+ var MAX_WEBSITES = 8;
25032
+ var EMAIL5 = /^(?=[\x21-\x7E]+$)[^@\s]+@[^@\s]+\.[^@\s]+$/u;
25033
+ var PHONE = /^\+?[0-9][0-9 .\-()]{6,30}[0-9]$/u;
25034
+ var VIEWER_SUBJECT = /^urn:li:fsd_profile:[0-9]{1,32}$/u;
25035
+ var PROFILE_URN = /^urn:li:fsd_profile:[A-Za-z0-9_-]{1,256}$/u;
25036
+ var VANITY = /^[A-Za-z0-9%._-]{1,1024}$/u;
25037
+ var DATE = /^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$/u;
25038
+ var BIRTHDAY = /^(?:[0-9]{4}-)?(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$/u;
25039
+ var AUTH_ID3 = /^[a-z0-9][a-z0-9._:-]{0,255}$/u;
25040
+ function getRow9(database, sql, ...bindings) {
25041
+ return database.query(sql).get(...bindings);
25042
+ }
25043
+ function allRows7(database, sql, ...bindings) {
25044
+ return database.query(sql).all(...bindings);
25045
+ }
25046
+ function run8(database, sql, ...bindings) {
25047
+ return database.run(sql, bindings);
25048
+ }
25049
+ function insertedId9(value) {
25050
+ return Number(value.lastInsertRowid);
25051
+ }
25052
+ function record6(value, label) {
25053
+ if (value === null || typeof value !== "object" || Array.isArray(value))
25054
+ throw new Error(`${label} must be an object`);
25055
+ return value;
25056
+ }
25057
+ function exact4(value, keys, label) {
25058
+ const actual = Object.keys(value).sort();
25059
+ const expected = [...keys].sort();
25060
+ if (actual.length !== expected.length || actual.some((key, index) => key !== expected[index])) {
25061
+ throw new Error(`${label} changed its reviewed shape`);
25062
+ }
25063
+ }
25064
+ function text6(value, label, maximum) {
25065
+ if (typeof value !== "string")
25066
+ throw new Error(`${label} must be a string`);
25067
+ const normalized = value.normalize("NFC");
25068
+ if (normalized.length < 1 || Buffer.byteLength(normalized, "utf8") > maximum || /[\u0000-\u001F\u007F-\u009F]/u.test(normalized))
25069
+ throw new Error(`${label} is invalid`);
25070
+ return normalized;
25071
+ }
25072
+ function optionalText3(value, label, maximum) {
25073
+ return value === null ? null : text6(value, label, maximum);
25074
+ }
25075
+ function timestamp6(value, label) {
25076
+ const parsed = text6(value, label, 64);
25077
+ const milliseconds2 = Date.parse(parsed);
25078
+ if (!Number.isFinite(milliseconds2) || new Date(milliseconds2).toISOString() !== parsed) {
25079
+ throw new Error(`${label} must be a canonical UTC timestamp`);
25080
+ }
25081
+ return parsed;
25082
+ }
25083
+ function boundedList(value, label, maximum) {
25084
+ if (!Array.isArray(value) || value.length > maximum)
25085
+ throw new Error(`${label} exceeded its reviewed bound`);
25086
+ const items = value.map((item, index) => text6(item, `${label}[${index}]`, 2048));
25087
+ if (new Set(items).size !== items.length)
25088
+ throw new Error(`${label} contains duplicates`);
25089
+ return items;
25090
+ }
25091
+ function website(value, label) {
25092
+ let parsed;
25093
+ try {
25094
+ parsed = new URL(value);
25095
+ } catch (error) {
25096
+ throw new Error(`${label} is not an absolute URL`, { cause: error });
25097
+ }
25098
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:" || parsed.username !== "" || parsed.password !== "")
25099
+ throw new Error(`${label} must be a plain web URL`);
25100
+ return parsed.href;
25101
+ }
25102
+ function normalizedWebsite(value) {
25103
+ const parsed = new URL(value);
25104
+ parsed.hash = "";
25105
+ const path = parsed.pathname.length > 1 && parsed.pathname.endsWith("/") ? parsed.pathname.slice(0, -1) : parsed.pathname;
25106
+ return `${parsed.protocol}//${parsed.host.toLowerCase()}${path}${parsed.search}`;
25107
+ }
25108
+ function normalizedEmail3(value, label) {
25109
+ if (!EMAIL5.test(value) || Buffer.byteLength(value, "utf8") > 320)
25110
+ throw new Error(`${label} is not an email address`);
25111
+ return value.toLowerCase();
25112
+ }
25113
+ function parseFields(value, label) {
25114
+ const parsed = record6(value, label);
25115
+ exact4(parsed, ["email", "profileUrl", "connectedSince", "phones", "websites", "birthday"], label);
25116
+ const email2 = optionalText3(parsed.email, `${label}.email`, 320);
25117
+ if (email2 !== null)
25118
+ normalizedEmail3(email2, `${label}.email`);
25119
+ const profileUrl2 = optionalText3(parsed.profileUrl, `${label}.profileUrl`, 4096);
25120
+ if (profileUrl2 !== null && canonicalLinkedInProfileUrl(profileUrl2, `${label}.profileUrl`) === null) {
25121
+ throw new Error(`${label}.profileUrl is invalid`);
25122
+ }
25123
+ const connectedSince = optionalText3(parsed.connectedSince, `${label}.connectedSince`, 10);
25124
+ if (connectedSince !== null && !DATE.test(connectedSince))
25125
+ throw new Error(`${label}.connectedSince is invalid`);
25126
+ const phones = boundedList(parsed.phones, `${label}.phones`, MAX_PHONES);
25127
+ for (const [index, phone] of phones.entries()) {
25128
+ if (!PHONE.test(phone))
25129
+ throw new Error(`${label}.phones[${index}] is invalid`);
25130
+ }
25131
+ const websites = boundedList(parsed.websites, `${label}.websites`, MAX_WEBSITES).map((item, index) => website(item, `${label}.websites[${index}]`));
25132
+ const birthday2 = optionalText3(parsed.birthday, `${label}.birthday`, 10);
25133
+ if (birthday2 !== null && !BIRTHDAY.test(birthday2))
25134
+ throw new Error(`${label}.birthday is invalid`);
25135
+ return Object.freeze({ email: email2, profileUrl: profileUrl2, connectedSince, phones, websites, birthday: birthday2 });
25136
+ }
25137
+ function projectLinkedInContactInfo(value, expectedProfileUrl) {
25138
+ const output = record6(value, "Ghostget LinkedIn contact output");
25139
+ exact4(output, ["schemaVersion", "provider", "profile", "viewer", "observedAt", "completeness", "contact"], "contact output");
25140
+ if (output.schemaVersion !== 1 || output.provider !== PROVIDER11)
25141
+ throw new Error("Ghostget LinkedIn contact semantics drifted");
25142
+ const profile = record6(output.profile, "contact output.profile");
25143
+ exact4(profile, ["vanity", "profileUrn", "url", "relationship"], "contact output.profile");
25144
+ const vanity = text6(profile.vanity, "contact output.profile.vanity", 1024);
25145
+ if (!VANITY.test(vanity))
25146
+ throw new Error("Ghostget LinkedIn profile vanity is invalid");
25147
+ const profileUrn = text6(profile.profileUrn, "contact output.profile.profileUrn", 300);
25148
+ if (!PROFILE_URN.test(profileUrn))
25149
+ throw new Error("Ghostget LinkedIn profile URN is invalid");
25150
+ const url = canonicalLinkedInProfileUrl(text6(profile.url, "contact output.profile.url", 4096), "contact output.profile.url");
25151
+ if (url === null || url !== expectedProfileUrl) {
25152
+ throw new Error("Ghostget LinkedIn contact output does not bind the requested profile");
25153
+ }
25154
+ if (profile.relationship !== "first-degree")
25155
+ throw new Error("Ghostget LinkedIn contact output is not a first-degree read");
25156
+ const viewer = record6(output.viewer, "contact output.viewer");
25157
+ exact4(viewer, ["subject"], "contact output.viewer");
25158
+ const viewerSubject = text6(viewer.subject, "contact output.viewer.subject", 64);
25159
+ if (!VIEWER_SUBJECT.test(viewerSubject))
25160
+ throw new Error("Ghostget LinkedIn viewer subject is invalid");
25161
+ const observedAt = timestamp6(output.observedAt, "contact output.observedAt");
25162
+ if (output.completeness !== "complete" && output.completeness !== "partial") {
25163
+ throw new Error("Ghostget LinkedIn contact completeness is invalid");
25164
+ }
25165
+ const contact = parseFields(output.contact, "contact output.contact");
25166
+ const hasAny = contact.email !== null || contact.connectedSince !== null || contact.phones.length > 0 || contact.websites.length > 0 || contact.birthday !== null;
25167
+ if (hasAny !== (output.completeness === "complete")) {
25168
+ throw new Error("Ghostget LinkedIn contact completeness disagrees with its fields");
25169
+ }
25170
+ return Object.freeze({
25171
+ profileUrl: url,
25172
+ vanity,
25173
+ profileUrn,
25174
+ relationship: "first-degree",
25175
+ viewerSubject,
25176
+ observedAt,
25177
+ completeness: output.completeness,
25178
+ contact
25179
+ });
25180
+ }
25181
+ function authId2(value) {
25182
+ const parsed = (value ?? DEFAULT_LINKEDIN_AUTH).trim();
25183
+ if (!AUTH_ID3.test(parsed))
25184
+ throw new Error("Ghostget auth ID is invalid");
25185
+ return parsed;
25186
+ }
25187
+ function envelope(value, input, auth) {
25188
+ return validatePeopleBladeGhostgetInvocation(value, {
25189
+ adapterId: LINKEDIN_CONTACT_INFO_ADAPTER_ID,
25190
+ operationId: LINKEDIN_CONTACT_INFO_OPERATION_ID,
25191
+ authId: auth,
25192
+ input
25193
+ }, {
25194
+ adapterVersion: LINKEDIN_CONTACT_INFO_ADAPTER_VERSION,
25195
+ authKind: "browser-profile",
25196
+ transport: "web-session-api",
25197
+ contractSha256: LINKEDIN_CONTACT_INFO_CONTRACT_SHA256,
25198
+ finalOrigin: "https://www.linkedin.com"
25199
+ });
25200
+ }
25201
+ function storedResultFromJson(value) {
25202
+ const parsed = record6(JSON.parse(value), "stored LinkedIn contact-info result");
25203
+ exact4(parsed, [
25204
+ "account_key",
25205
+ "person_id",
25206
+ "provider_resource_id",
25207
+ "profile_url",
25208
+ "vanity",
25209
+ "observed_at",
25210
+ "completeness",
25211
+ "connected_since",
25212
+ "email_recorded",
25213
+ "phones_recorded",
25214
+ "phones_unresolved",
25215
+ "websites_recorded",
25216
+ "birthday_recorded"
25217
+ ], "stored LinkedIn contact-info result");
25218
+ return parsed;
25219
+ }
25220
+ function metadata3(value) {
25221
+ return record6(JSON.parse(value), "LinkedIn resource metadata");
25222
+ }
25223
+ function readLinkedInContactInfo(database, options) {
25224
+ const account = linkedInAccountKey(options.accountKey);
25225
+ const auth = authId2(options.authId);
25226
+ if (!Number.isSafeInteger(options.personId) || options.personId < 1)
25227
+ throw new Error("person ID is invalid");
25228
+ const resources = allRows7(database, `SELECT id,person_id,profile_url,resource_id,metadata_json FROM provider_resources
25229
+ WHERE provider=? AND account_key=? AND resource_type='profile' AND active=1 AND person_id=?
25230
+ ORDER BY id`, PROVIDER11, account, options.personId);
25231
+ if (resources.length === 0) {
25232
+ throw new Error("This person has no active LinkedIn profile in that account; import the official LinkedIn export first");
25233
+ }
25234
+ if (resources.length > 1) {
25235
+ throw new Error("This person has more than one active LinkedIn profile in that account; review its identity decisions first");
25236
+ }
25237
+ const resource = resources[0];
25238
+ const profileUrl2 = canonicalLinkedInProfileUrl(resource.profile_url ?? resource.resource_id, "stored LinkedIn profile URL");
25239
+ if (profileUrl2 === null)
25240
+ throw new Error("stored LinkedIn profile resource lacks an exact profile URL");
25241
+ const owner = getRow9(database, "SELECT owner_key FROM archive_accounts WHERE provider=? AND account_key=?", PROVIDER11, account);
25242
+ if (owner !== null && owner.owner_key === profileUrl2) {
25243
+ throw new Error("Contact info is read for connections, not the account owner's own profile");
25244
+ }
25245
+ const input = Object.freeze({ profile_url: profileUrl2 });
25246
+ const invocation = callPeopleBladeGhostget({
25247
+ adapterId: LINKEDIN_CONTACT_INFO_ADAPTER_ID,
25248
+ operationId: LINKEDIN_CONTACT_INFO_OPERATION_ID,
25249
+ authId: auth,
25250
+ input
25251
+ }, options.invoke);
25252
+ const parsed = envelope(invocation, input, auth);
25253
+ const projection2 = projectLinkedInContactInfo(parsed.output, profileUrl2);
25254
+ const sourceSha256 = sha256(canonicalJson(projection2));
25255
+ const execution = parsed.execution;
25256
+ const personId = resource.person_id;
25257
+ const resourceId = resource.id;
25258
+ const resolvedPhones = projection2.contact.phones.map((phone) => ({ phone, normalized: resolvePhoneIdentity(phone, null) }));
25259
+ const stored = {
25260
+ account_key: account,
25261
+ person_id: personId,
25262
+ provider_resource_id: resourceId,
25263
+ profile_url: profileUrl2,
25264
+ vanity: projection2.vanity,
25265
+ observed_at: projection2.observedAt,
25266
+ completeness: projection2.completeness,
25267
+ connected_since: projection2.contact.connectedSince,
25268
+ email_recorded: projection2.contact.email !== null,
25269
+ phones_recorded: resolvedPhones.filter((entry) => entry.normalized !== null).length,
25270
+ phones_unresolved: resolvedPhones.filter((entry) => entry.normalized === null).length,
25271
+ websites_recorded: projection2.contact.websites.length,
25272
+ birthday_recorded: projection2.contact.birthday !== null
25273
+ };
25274
+ database.exec("BEGIN IMMEDIATE");
25275
+ try {
25276
+ const cached = getRow9(database, "SELECT id,result_json FROM source_runs WHERE provider=? AND account_key=? AND mode=? AND source_sha256=?", PROVIDER11, account, MODE8, sourceSha256);
25277
+ if (cached !== null) {
25278
+ database.exec("COMMIT");
25279
+ return { ...storedResultFromJson(cached.result_json), run_id: cached.id, replayed: true };
25280
+ }
25281
+ const runId = insertedId9(run8(database, `INSERT INTO source_runs(
25282
+ provider,account_key,mode,source_sha256,source_locator_sha256,completeness,result_json,started_at,completed_at
25283
+ ) VALUES (?,?,?,?,?,?,?,?,?)`, PROVIDER11, account, MODE8, sourceSha256, sha256(profileUrl2), projection2.completeness, canonicalJson(stored), execution.startedAt, execution.finishedAt));
25284
+ const methodLabel = `${OBSERVATION_BASIS2}:${sha256(profileUrl2).slice(0, 16)}`;
25285
+ const methodMetadata = canonicalJson({ observedIn: OBSERVATION_BASIS2, observedAt: projection2.observedAt });
25286
+ run8(database, "UPDATE contact_methods SET active=0 WHERE provider_resource_id=? AND label=?", resourceId, methodLabel);
25287
+ if (projection2.contact.email !== null) {
25288
+ run8(database, `INSERT INTO contact_methods(
25289
+ person_id,kind,value,normalized_value,label,confidence,first_seen_run_id,last_seen_run_id,
25290
+ metadata_json,provider_resource_id,active,identity_eligible
25291
+ ) VALUES (?,'email',?,?,?,'exact',?,?,?,?,1,1)
25292
+ ON CONFLICT(person_id,kind,normalized_value,label) DO UPDATE SET
25293
+ value=excluded.value,last_seen_run_id=excluded.last_seen_run_id,metadata_json=excluded.metadata_json,
25294
+ provider_resource_id=excluded.provider_resource_id,active=1,identity_eligible=1`, personId, projection2.contact.email, normalizedEmail3(projection2.contact.email, "contact email"), methodLabel, runId, runId, methodMetadata, resourceId);
25295
+ }
25296
+ for (const { phone, normalized } of resolvedPhones) {
25297
+ if (normalized === null)
25298
+ continue;
25299
+ run8(database, `INSERT INTO contact_methods(
25300
+ person_id,kind,value,normalized_value,label,confidence,first_seen_run_id,last_seen_run_id,
25301
+ metadata_json,provider_resource_id,active,identity_eligible
25302
+ ) VALUES (?,'phone',?,?,?,'exact',?,?,?,?,1,1)
25303
+ ON CONFLICT(person_id,kind,normalized_value,label) DO UPDATE SET
25304
+ value=excluded.value,last_seen_run_id=excluded.last_seen_run_id,metadata_json=excluded.metadata_json,
25305
+ provider_resource_id=excluded.provider_resource_id,active=1,identity_eligible=1`, personId, phone, normalized, methodLabel, runId, runId, methodMetadata, resourceId);
25306
+ }
25307
+ for (const site of projection2.contact.websites) {
25308
+ run8(database, `INSERT INTO contact_methods(
25309
+ person_id,kind,value,normalized_value,label,confidence,first_seen_run_id,last_seen_run_id,
25310
+ metadata_json,provider_resource_id,active,identity_eligible
25311
+ ) VALUES (?,'url',?,?,?,'exact',?,?,?,?,1,0)
25312
+ ON CONFLICT(person_id,kind,normalized_value,label) DO UPDATE SET
25313
+ value=excluded.value,last_seen_run_id=excluded.last_seen_run_id,metadata_json=excluded.metadata_json,
25314
+ provider_resource_id=excluded.provider_resource_id,active=1,identity_eligible=0`, personId, site, normalizedWebsite(site), methodLabel, runId, runId, methodMetadata, resourceId);
25315
+ }
25316
+ run8(database, "UPDATE person_field_observations SET active=0 WHERE provider_resource_id=? AND basis=?", resourceId, OBSERVATION_BASIS2);
25317
+ if (projection2.contact.birthday !== null) {
25318
+ run8(database, `INSERT INTO person_field_observations(
25319
+ provider_resource_id,field,value,basis,priority,active,first_seen_run_id,last_seen_run_id,metadata_json
25320
+ ) VALUES (?,'birthday',?,?,?,1,?,?,'{}')
25321
+ ON CONFLICT(provider_resource_id,field,value,basis) DO UPDATE SET
25322
+ priority=excluded.priority,active=1,last_seen_run_id=excluded.last_seen_run_id`, resourceId, projection2.contact.birthday, OBSERVATION_BASIS2, OBSERVATION_PRIORITY2, runId, runId);
25323
+ run8(database, "UPDATE people SET birthday=coalesce(birthday,?) WHERE id=?", projection2.contact.birthday, personId);
25324
+ }
25325
+ const resourceMetadata = {
25326
+ ...metadata3(resource.metadata_json),
25327
+ linkedInContactInfo: {
25328
+ observedAt: projection2.observedAt,
25329
+ completeness: projection2.completeness,
25330
+ connectedSince: projection2.contact.connectedSince,
25331
+ viewerSubject: projection2.viewerSubject,
25332
+ runId
25333
+ }
25334
+ };
25335
+ run8(database, "UPDATE provider_resources SET last_seen_run_id=?,metadata_json=? WHERE id=?", runId, canonicalJson(resourceMetadata), resourceId);
25336
+ run8(database, `INSERT INTO source_records(
25337
+ run_id,ordinal,record_kind,record_sha256,person_id,provider_resource_id,resolution,projection_json,error_text
25338
+ ) VALUES (?,1,?,?,?,?,'matched',?,NULL)`, runId, RECORD_KIND, sourceSha256, personId, resourceId, canonicalJson(projection2));
25339
+ ledgerPeopleBladeGhostgetInvocation(database, {
25340
+ provider: PROVIDER11,
25341
+ accountKey: account,
25342
+ capability: "contact_info",
25343
+ execution,
25344
+ costBasis: "local-browser-read",
25345
+ metadata: { profileUrlSha256: sha256(profileUrl2), completeness: projection2.completeness }
25346
+ });
25347
+ database.exec("COMMIT");
25348
+ return { ...stored, run_id: runId, replayed: false };
25349
+ } catch (error) {
25350
+ database.exec("ROLLBACK");
25351
+ throw error;
25352
+ }
25353
+ }
25354
+
24977
25355
  // src/local/providers/whatsapp.ts
24978
25356
  import { createHash as createHash9 } from "crypto";
24979
25357
  var CONTACTS_CONTRACT_SHA2562 = "0bd3c994f16608d5886f1192dd58d41736e4bd01add66a5a3e029efca8b14a38";
@@ -24994,18 +25372,18 @@ var DEVICE_LID_JID = /^([0-9]{5,32}):[0-9]{1,5}@lid$/u;
24994
25372
  var GROUP_JID = /^[0-9]{5,32}(?:-[0-9]{5,20})?@g\.us$/u;
24995
25373
  var OTHER_JID = /^(?:0@s\.whatsapp\.net|[0-9]{5,32}@newsletter|(?:status|[0-9]{5,32})@broadcast)$/u;
24996
25374
  var MESSAGE_ID = /^[A-Za-z0-9._~:-]{1,256}$/u;
24997
- var PROVIDER11 = "whatsapp";
25375
+ var PROVIDER12 = "whatsapp";
24998
25376
  var STREAM2 = "messages";
24999
- function getRow9(database, sql, ...values) {
25377
+ function getRow10(database, sql, ...values) {
25000
25378
  return database.query(sql).get(...values);
25001
25379
  }
25002
- function run8(database, sql, ...values) {
25380
+ function run9(database, sql, ...values) {
25003
25381
  return database.run(sql, values);
25004
25382
  }
25005
- function insertedId9(value) {
25383
+ function insertedId10(value) {
25006
25384
  return Number(value.lastInsertRowid);
25007
25385
  }
25008
- function record6(value, label) {
25386
+ function record7(value, label) {
25009
25387
  if (typeof value !== "object" || value === null || Array.isArray(value) || Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {
25010
25388
  throw new Error(`${label} must be a plain object`);
25011
25389
  }
@@ -25017,14 +25395,14 @@ function record6(value, label) {
25017
25395
  throw new Error(`${label} has symbol keys`);
25018
25396
  return value;
25019
25397
  }
25020
- function exact4(value, keys, label) {
25398
+ function exact5(value, keys, label) {
25021
25399
  const actual = Object.keys(value).sort();
25022
25400
  const expected = [...keys].sort();
25023
25401
  if (actual.length !== expected.length || actual.some((key, index) => key !== expected[index])) {
25024
25402
  throw new Error(`${label} contains unsupported or missing fields`);
25025
25403
  }
25026
25404
  }
25027
- function text6(value, label, maximum = 4096, empty = false) {
25405
+ function text7(value, label, maximum = 4096, empty = false) {
25028
25406
  if (typeof value !== "string" || !empty && value.length === 0 || Buffer.byteLength(value, "utf8") > maximum || /[\u0000\r]/u.test(value)) {
25029
25407
  throw new Error(`${label} must be bounded text`);
25030
25408
  }
@@ -25041,7 +25419,7 @@ function bool3(value, label) {
25041
25419
  return value;
25042
25420
  }
25043
25421
  function digest5(value, label) {
25044
- const parsed = text6(value, label, 64);
25422
+ const parsed = text7(value, label, 64);
25045
25423
  if (!SHA2563.test(parsed))
25046
25424
  throw new Error(`${label} is invalid`);
25047
25425
  return parsed;
@@ -25059,11 +25437,11 @@ function stableJson6(value) {
25059
25437
  }
25060
25438
  if (Array.isArray(value))
25061
25439
  return `[${value.map(stableJson6).join(",")}]`;
25062
- const parsed = record6(value, "canonical JSON");
25440
+ const parsed = record7(value, "canonical JSON");
25063
25441
  return `{${Object.keys(parsed).sort().map((key) => `${JSON.stringify(key)}:${stableJson6(parsed[key])}`).join(",")}}`;
25064
25442
  }
25065
- function timestamp6(value, label) {
25066
- const parsed = text6(value, label, 40);
25443
+ function timestamp7(value, label) {
25444
+ const parsed = text7(value, label, 40);
25067
25445
  if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?Z$/u.test(parsed))
25068
25446
  throw new Error(`${label} is invalid`);
25069
25447
  const milliseconds2 = Date.parse(parsed);
@@ -25072,25 +25450,25 @@ function timestamp6(value, label) {
25072
25450
  return new Date(milliseconds2).toISOString();
25073
25451
  }
25074
25452
  function decimal(value, label) {
25075
- const parsed = text6(value, label, 19);
25453
+ const parsed = text7(value, label, 19);
25076
25454
  if (!DECIMAL.test(parsed) || BigInt(parsed) > BigInt("9223372036854775807"))
25077
25455
  throw new Error(`${label} is invalid`);
25078
25456
  return parsed;
25079
25457
  }
25080
- function authId2(value) {
25081
- const parsed = text6(value, "WhatsApp auth ID", 48);
25458
+ function authId3(value) {
25459
+ const parsed = text7(value, "WhatsApp auth ID", 48);
25082
25460
  if (!/^[a-z][a-z0-9-]{0,47}$/u.test(parsed))
25083
25461
  throw new Error("WhatsApp auth ID is invalid");
25084
25462
  return parsed;
25085
25463
  }
25086
25464
  function subject(value) {
25087
- const parsed = text6(value, "WhatsApp account subject", 64);
25465
+ const parsed = text7(value, "WhatsApp account subject", 64);
25088
25466
  if (!SUBJECT2.test(parsed))
25089
25467
  throw new Error("WhatsApp account subject is invalid");
25090
25468
  return parsed;
25091
25469
  }
25092
25470
  function canonicalJid(value, label, device = false) {
25093
- const parsed = text6(value, label, 96);
25471
+ const parsed = text7(value, label, 96);
25094
25472
  const user = USER_JID.exec(parsed) ?? (device ? DEVICE_USER_JID.exec(parsed) : null);
25095
25473
  if (user?.[1] !== undefined)
25096
25474
  return { jid: `${user[1]}@s.whatsapp.net`, kind: "user" };
@@ -25112,8 +25490,8 @@ function directJid(value, label) {
25112
25490
  function ownerJid(accountSubject) {
25113
25491
  return accountSubject.startsWith("whatsapp:pn:") ? `${accountSubject.slice(12)}@s.whatsapp.net` : `${accountSubject.slice(13)}@lid`;
25114
25492
  }
25115
- function envelope(value, input, auth) {
25116
- const parsed = validatePeopleBladeWrenchInvocation(value, {
25493
+ function envelope2(value, input, auth) {
25494
+ const parsed = validatePeopleBladeGhostgetInvocation(value, {
25117
25495
  adapterId: "whatsapp-web",
25118
25496
  operationId: "contacts.list",
25119
25497
  authId: auth,
@@ -25125,25 +25503,25 @@ function envelope(value, input, auth) {
25125
25503
  contractSha256: CONTACTS_CONTRACT_SHA2562,
25126
25504
  finalOrigin: "https://web.whatsapp.com"
25127
25505
  });
25128
- return { output: record6(parsed.output, "Wrench output"), execution: parsed.execution };
25506
+ return { output: record7(parsed.output, "Ghostget output"), execution: parsed.execution };
25129
25507
  }
25130
25508
  var CONTACT_KEYS = ["providerId", "jidKind", "phone", "redactedPhone", "firstName", "fullName", "pushName", "businessName", "displayName", "displayNameBasis", "alias", "tags", "updatedAt", "localProjectionStatsComplete", "sentCount", "sentCountComplete", "sentCountLowerBound", "sentCountTruncated", "receivedCount", "receivedCountComplete", "receivedCountLowerBound", "receivedCountTruncated", "lastSentAt", "lastSentAtComplete", "lastSentAtBasis", "sentStatsIncompleteReasons", "lastReceivedAt", "lastReceivedAtComplete", "lastReceivedAtBasis", "receivedStatsIncompleteReasons"];
25131
25509
  function parseContact4(value, label) {
25132
- const parsed = record6(value, label);
25133
- exact4(parsed, CONTACT_KEYS, label);
25510
+ const parsed = record7(value, label);
25511
+ exact5(parsed, CONTACT_KEYS, label);
25134
25512
  const identity = directJid(parsed.providerId, `${label}.providerId`);
25135
25513
  if (parsed.jidKind !== identity.kind)
25136
25514
  throw new Error(`${label}.jidKind drifted`);
25137
- const phone = parsed.phone === null ? null : text6(parsed.phone, `${label}.phone`, 20);
25515
+ const phone = parsed.phone === null ? null : text7(parsed.phone, `${label}.phone`, 20);
25138
25516
  if (phone !== (USER_JID.exec(identity.jid)?.[1] ?? null))
25139
25517
  throw new Error(`${label}.phone drifted`);
25140
- const displayName2 = parsed.displayName === null ? null : text6(parsed.displayName, `${label}.displayName`, 512);
25518
+ const displayName2 = parsed.displayName === null ? null : text7(parsed.displayName, `${label}.displayName`, 512);
25141
25519
  const bases = ["full-name", "push-name", "business-name", "first-name", "redacted-phone", "phone", "unavailable"];
25142
25520
  if (!bases.includes(parsed.displayNameBasis))
25143
25521
  throw new Error(`${label}.displayNameBasis is invalid`);
25144
25522
  for (const key of ["redactedPhone", "firstName", "fullName", "pushName", "businessName"])
25145
25523
  if (parsed[key] !== null)
25146
- text6(parsed[key], `${label}.${key}`, 512);
25524
+ text7(parsed[key], `${label}.${key}`, 512);
25147
25525
  if (parsed.alias !== null || parsed.updatedAt !== null || !Array.isArray(parsed.tags) || parsed.tags.length !== 0 || parsed.localProjectionStatsComplete !== false || parsed.sentCount !== null || parsed.sentCountComplete !== false || parsed.sentCountLowerBound !== false || parsed.sentCountTruncated !== false || parsed.receivedCount !== null || parsed.receivedCountComplete !== false || parsed.receivedCountLowerBound !== false || parsed.receivedCountTruncated !== false || parsed.lastSentAt !== null || parsed.lastSentAtComplete !== false || parsed.lastSentAtBasis !== "unavailable" || parsed.lastReceivedAt !== null || parsed.lastReceivedAtComplete !== false || parsed.lastReceivedAtBasis !== "unavailable" || stableJson6(parsed.sentStatsIncompleteReasons) !== stableJson6(["whatsapp-message-store-account-owner-unavailable"]) || stableJson6(parsed.receivedStatsIncompleteReasons) !== stableJson6(["whatsapp-message-store-account-owner-unavailable"])) {
25148
25526
  throw new Error(`${label} changed bounded contact semantics`);
25149
25527
  }
@@ -25156,11 +25534,11 @@ function parseContact4(value, label) {
25156
25534
  };
25157
25535
  }
25158
25536
  function parseContactPage(value, input, auth) {
25159
- const parsed = envelope(value, input, auth);
25537
+ const parsed = envelope2(value, input, auth);
25160
25538
  const output = parsed.output;
25161
- exact4(output, ["provider", "operation", "accountSubject", "projection", "contacts", "nextCursor", "localContactTablePageComplete", "remoteContactSetComplete", "contactSetIncompleteReasons", "statsScope", "statsCompleteness"], "contact output");
25539
+ exact5(output, ["provider", "operation", "accountSubject", "projection", "contacts", "nextCursor", "localContactTablePageComplete", "remoteContactSetComplete", "contactSetIncompleteReasons", "statsScope", "statsCompleteness"], "contact output");
25162
25540
  if (output.provider !== "whatsapp" || output.operation !== "contacts.list" || output.projection !== "quiescent-account-bound-session-store" || output.remoteContactSetComplete !== false || output.statsScope !== "unavailable" || output.statsCompleteness !== "unavailable" || stableJson6(output.contactSetIncompleteReasons) !== stableJson6(["linked-device-contact-sync-coverage-unknown"]) || input.collection !== "contacts") {
25163
- throw new Error("Wrench contact semantics drifted");
25541
+ throw new Error("Ghostget contact semantics drifted");
25164
25542
  }
25165
25543
  const limit = integer6(input.limit, "contact limit", 1, 100);
25166
25544
  if (!Array.isArray(output.contacts) || output.contacts.length > limit)
@@ -25183,10 +25561,10 @@ function parseContactPage(value, input, auth) {
25183
25561
  return { input, accountSubject, contacts, nextCursor, localPageComplete: complete, safeOutputSha256, execution: parsed.execution };
25184
25562
  }
25185
25563
  function generation(value) {
25186
- const parsed = record6(value, "projection generation");
25187
- exact4(parsed, ["messageStoreIdentity", "schemaFingerprint"], "projection generation");
25188
- const identity = record6(parsed.messageStoreIdentity, "message-store identity");
25189
- exact4(identity, ["dev", "ino"], "message-store identity");
25564
+ const parsed = record7(value, "projection generation");
25565
+ exact5(parsed, ["messageStoreIdentity", "schemaFingerprint"], "projection generation");
25566
+ const identity = record7(parsed.messageStoreIdentity, "message-store identity");
25567
+ exact5(identity, ["dev", "ino"], "message-store identity");
25190
25568
  const dev = decimal(identity.dev, "message-store dev");
25191
25569
  const ino = decimal(identity.ino, "message-store ino");
25192
25570
  if (ino === "0" || parsed.schemaFingerprint !== PROJECTION_SCHEMA_FINGERPRINT)
@@ -25194,8 +25572,8 @@ function generation(value) {
25194
25572
  return { messageStoreIdentity: { dev, ino }, schemaFingerprint: PROJECTION_SCHEMA_FINGERPRINT };
25195
25573
  }
25196
25574
  function checkpoint(value, label) {
25197
- const parsed = record6(value, label);
25198
- exact4(parsed, ["cursor", "anchor"], label);
25575
+ const parsed = record7(value, label);
25576
+ exact5(parsed, ["cursor", "anchor"], label);
25199
25577
  const cursor = decimal(parsed.cursor, `${label}.cursor`);
25200
25578
  const anchor = parsed.anchor === null ? null : digest5(parsed.anchor, `${label}.anchor`);
25201
25579
  if (cursor === "0" !== (anchor === null))
@@ -25203,14 +25581,14 @@ function checkpoint(value, label) {
25203
25581
  return { cursor, anchor };
25204
25582
  }
25205
25583
  function parseInteraction(value, label) {
25206
- const parsed = record6(value, label);
25207
- exact4(parsed, ["rowid", "chatJid", "messageId", "senderJid", "timestamp", "fromMe", "chatKind"], label);
25584
+ const parsed = record7(value, label);
25585
+ exact5(parsed, ["rowid", "chatJid", "messageId", "senderJid", "timestamp", "fromMe", "chatKind"], label);
25208
25586
  const rowid = decimal(parsed.rowid, `${label}.rowid`);
25209
25587
  if (rowid === "0")
25210
25588
  throw new Error(`${label}.rowid is invalid`);
25211
25589
  const chat = canonicalJid(parsed.chatJid, `${label}.chatJid`);
25212
25590
  const sender = parsed.senderJid === null ? null : canonicalJid(parsed.senderJid, `${label}.senderJid`, true).jid;
25213
- const messageId = text6(parsed.messageId, `${label}.messageId`, 256);
25591
+ const messageId = text7(parsed.messageId, `${label}.messageId`, 256);
25214
25592
  if (!MESSAGE_ID.test(messageId))
25215
25593
  throw new Error(`${label}.messageId is invalid`);
25216
25594
  const kinds = ["dm", "group", "broadcast", "newsletter", "unknown"];
@@ -25224,7 +25602,7 @@ function parseInteraction(value, label) {
25224
25602
  chatJid: chat.jid,
25225
25603
  messageId,
25226
25604
  senderJid: sender,
25227
- timestamp: timestamp6(parsed.timestamp, `${label}.timestamp`),
25605
+ timestamp: timestamp7(parsed.timestamp, `${label}.timestamp`),
25228
25606
  fromMe: bool3(parsed.fromMe, `${label}.fromMe`),
25229
25607
  chatKind: parsed.chatKind
25230
25608
  };
@@ -25233,9 +25611,9 @@ function interactionAnchor(item) {
25233
25611
  return createHash9("sha256").update(item.rowid).update("\x00").update(item.chatJid).update("\x00").update(item.messageId).digest("hex");
25234
25612
  }
25235
25613
  function parseInteractionPage(value, input, auth) {
25236
- const parsed = envelope(value, input, auth);
25614
+ const parsed = envelope2(value, input, auth);
25237
25615
  const output = parsed.output;
25238
- exact4(output, ["provider", "operation", "accountSubject", "contactCollection", "projection", "projectionGeneration", "interactions", "nextCursor", "localInsertPageComplete", "checkpoint", "remoteHistoryComplete", "incompleteReasons"], "interaction output");
25616
+ exact5(output, ["provider", "operation", "accountSubject", "contactCollection", "projection", "projectionGeneration", "interactions", "nextCursor", "localInsertPageComplete", "checkpoint", "remoteHistoryComplete", "incompleteReasons"], "interaction output");
25239
25617
  if (output.provider !== "whatsapp" || output.operation !== "contacts.list" || output.contactCollection !== "interactions" || output.projection !== "quiescent-account-bound-local-message-inserts" || output.remoteHistoryComplete !== false || stableJson6(output.incompleteReasons) !== stableJson6(["linked-device-history-coverage-unknown", "rowid-cursor-discovers-inserts-only"]) || input.collection !== "interactions") {
25240
25618
  throw new Error("interaction projection semantics drifted");
25241
25619
  }
@@ -25271,8 +25649,8 @@ function parseInteractionPage(value, input, auth) {
25271
25649
  execution: parsed.execution
25272
25650
  };
25273
25651
  }
25274
- function wrenchWhatsAppSnapshot(options = {}) {
25275
- const auth = authId2(options.authId ?? DEFAULT_WHATSAPP_AUTH);
25652
+ function ghostgetWhatsAppSnapshot(options = {}) {
25653
+ const auth = authId3(options.authId ?? DEFAULT_WHATSAPP_AUTH);
25276
25654
  const contactPageSize = options.contactPageSize === undefined ? DEFAULT_WHATSAPP_CONTACT_PAGE_SIZE : integer6(options.contactPageSize, "contact page size", 1, 100);
25277
25655
  const interactionPageSize = options.interactionPageSize === undefined ? DEFAULT_WHATSAPP_INTERACTION_PAGE_SIZE : integer6(options.interactionPageSize, "interaction page size", 1, 1000);
25278
25656
  const supplied = options.checkpoint;
@@ -25281,7 +25659,7 @@ function wrenchWhatsAppSnapshot(options = {}) {
25281
25659
  const startGeneration = supplied?.generation === undefined ? undefined : generation(supplied.generation);
25282
25660
  if (startCursor === "0" !== (startAnchor === null))
25283
25661
  throw new Error("checkpoint is inconsistent");
25284
- const call = (_operation, input) => callPeopleBladeWrench({
25662
+ const call = (_operation, input) => callPeopleBladeGhostget({
25285
25663
  adapterId: "whatsapp-web",
25286
25664
  operationId: "contacts.list",
25287
25665
  authId: auth,
@@ -25333,11 +25711,11 @@ function wrenchWhatsAppSnapshot(options = {}) {
25333
25711
  throw new Error("WhatsApp interaction pagination exceeded its bound");
25334
25712
  const executions = [...contactPages, ...interactionPages].map((page) => page.execution);
25335
25713
  if (new Set(executions.map((item) => item.runId)).size !== executions.length)
25336
- throw new Error("Wrench reused a WhatsApp run ID");
25714
+ throw new Error("Ghostget reused a WhatsApp run ID");
25337
25715
  const first = executions[0];
25338
25716
  for (const item of executions)
25339
25717
  if (item.authId !== first.authId || item.authSha256 !== first.authSha256 || item.adapterVersion !== first.adapterVersion || item.adapterSha256 !== first.adapterSha256 || item.contractSha256 !== first.contractSha256)
25340
- throw new Error("Wrench execution identity changed during sync");
25718
+ throw new Error("Ghostget execution identity changed during sync");
25341
25719
  return {
25342
25720
  schemaVersion: 2,
25343
25721
  provider: "whatsapp",
@@ -25358,47 +25736,47 @@ function generationSha256(value) {
25358
25736
  return sha2569(stableJson6(value));
25359
25737
  }
25360
25738
  function ensureResource2(database, account, sourceRealmId, jid, name, basis, runId) {
25361
- const existing = getRow9(database, `SELECT id,person_id,source_realm_id FROM provider_resources
25362
- WHERE provider=? AND account_key=? AND resource_type='jid' AND resource_id=?`, PROVIDER11, account, jid);
25739
+ const existing = getRow10(database, `SELECT id,person_id,source_realm_id FROM provider_resources
25740
+ WHERE provider=? AND account_key=? AND resource_type='jid' AND resource_id=?`, PROVIDER12, account, jid);
25363
25741
  if (existing !== null) {
25364
25742
  if (existing.source_realm_id !== null && existing.source_realm_id !== sourceRealmId) {
25365
25743
  throw new Error("WhatsApp contact resource crossed its bound account realm");
25366
25744
  }
25367
- run8(database, `UPDATE provider_resources SET source_realm_id=?,display_name=coalesce(?,display_name),active=1,last_seen_run_id=?,
25745
+ run9(database, `UPDATE provider_resources SET source_realm_id=?,display_name=coalesce(?,display_name),active=1,last_seen_run_id=?,
25368
25746
  metadata_json=? WHERE id=?`, sourceRealmId, name, runId, stableJson6({ jidKind: USER_JID.test(jid) ? "user" : "lid", displayNameBasis: basis }), existing.id);
25369
25747
  if (name !== null)
25370
- run8(database, "UPDATE people SET display_name=coalesce(display_name,?) WHERE id=?", name, existing.person_id);
25748
+ run9(database, "UPDATE people SET display_name=coalesce(display_name,?) WHERE id=?", name, existing.person_id);
25371
25749
  return { personId: existing.person_id, resourceId: existing.id, imported: false };
25372
25750
  }
25373
- const personId = insertedId9(run8(database, "INSERT INTO people(stable_key,display_name,metadata_json) VALUES (?,?,?)", `whatsapp:${sha2569(`${account}\x00${jid}`)}`, name, stableJson6({ createdBy: "exact-whatsapp-jid" })));
25751
+ const personId = insertedId10(run9(database, "INSERT INTO people(stable_key,display_name,metadata_json) VALUES (?,?,?)", `whatsapp:${sha2569(`${account}\x00${jid}`)}`, name, stableJson6({ createdBy: "exact-whatsapp-jid" })));
25374
25752
  const phone = phoneForJid(jid);
25375
25753
  if (phone !== null)
25376
- run8(database, `INSERT INTO contact_methods(
25754
+ run9(database, `INSERT INTO contact_methods(
25377
25755
  person_id,kind,value,normalized_value,label,confidence,first_seen_run_id,last_seen_run_id,metadata_json
25378
25756
  ) VALUES (?,'phone',?,?,'whatsapp','exact',?,?,?)`, personId, phone, phone, runId, runId, stableJson6({ derivedFromJid: true }));
25379
- const resourceId = insertedId9(run8(database, `INSERT INTO provider_resources(
25757
+ const resourceId = insertedId10(run9(database, `INSERT INTO provider_resources(
25380
25758
  provider,account_key,source_realm_id,resource_type,resource_id,person_id,display_name,active,
25381
25759
  first_seen_run_id,last_seen_run_id,metadata_json
25382
- ) VALUES (?,?,?,'jid',?,?,?,1,?,?,?)`, PROVIDER11, account, sourceRealmId, jid, personId, name, runId, runId, stableJson6({ jidKind: USER_JID.test(jid) ? "user" : "lid", displayNameBasis: basis })));
25760
+ ) VALUES (?,?,?,'jid',?,?,?,1,?,?,?)`, PROVIDER12, account, sourceRealmId, jid, personId, name, runId, runId, stableJson6({ jidKind: USER_JID.test(jid) ? "user" : "lid", displayNameBasis: basis })));
25383
25761
  return { personId, resourceId, imported: true };
25384
25762
  }
25385
25763
  function parseStoredGeneration(value) {
25386
- const parsed = record6(JSON.parse(value), "stored WhatsApp checkpoint metadata");
25387
- exact4(parsed, ["generation", "coverage"], "stored WhatsApp checkpoint metadata");
25764
+ const parsed = record7(JSON.parse(value), "stored WhatsApp checkpoint metadata");
25765
+ exact5(parsed, ["generation", "coverage"], "stored WhatsApp checkpoint metadata");
25388
25766
  if (parsed.coverage !== "local-insert-rowid-scan")
25389
25767
  throw new Error("stored WhatsApp coverage drifted");
25390
25768
  return generation(parsed.generation);
25391
25769
  }
25392
25770
  function databaseCheckpoint(database, auth) {
25393
- const row = getRow9(database, `SELECT checkpoint.cursor,checkpoint.cursor_anchor_sha256,checkpoint.metadata_json
25771
+ const row = getRow10(database, `SELECT checkpoint.cursor,checkpoint.cursor_anchor_sha256,checkpoint.metadata_json
25394
25772
  FROM provider_accounts account JOIN provider_checkpoints checkpoint
25395
25773
  ON checkpoint.provider=account.provider AND checkpoint.account_key=account.account_key
25396
- WHERE account.provider=? AND account.auth_id=? AND checkpoint.stream_key=?`, PROVIDER11, auth, STREAM2);
25774
+ WHERE account.provider=? AND account.auth_id=? AND checkpoint.stream_key=?`, PROVIDER12, auth, STREAM2);
25397
25775
  return row === null ? { cursor: "0", anchor: null } : { cursor: row.cursor, anchor: row.cursor_anchor_sha256, generation: parseStoredGeneration(row.metadata_json) };
25398
25776
  }
25399
25777
  function refreshMetrics2(database, account, runId) {
25400
- run8(database, "DELETE FROM interaction_metrics WHERE provider=? AND account_key=?", PROVIDER11, account);
25401
- run8(database, `INSERT INTO interaction_metrics(
25778
+ run9(database, "DELETE FROM interaction_metrics WHERE provider=? AND account_key=?", PROVIDER12, account);
25779
+ run9(database, `INSERT INTO interaction_metrics(
25402
25780
  provider,account_key,person_id,sent_count,received_count,interaction_count,conversation_count,
25403
25781
  first_interaction_at,last_interaction_at,reciprocal,completeness,last_seen_run_id,metadata_json
25404
25782
  ) SELECT ?,?,person_id,sum(direction='outgoing'),sum(direction='incoming'),count(*),
@@ -25406,11 +25784,11 @@ function refreshMetrics2(database, account, runId) {
25406
25784
  CASE WHEN sum(direction='outgoing')>0 AND sum(direction='incoming')>0 THEN 1 ELSE 0 END,
25407
25785
  'lower-bound',?,'{"coverage":"local-insert-rowid-scan"}'
25408
25786
  FROM interaction_events WHERE provider=? AND account_key=? AND resolution='matched' AND person_id IS NOT NULL
25409
- GROUP BY person_id`, PROVIDER11, account, runId, PROVIDER11, account);
25787
+ GROUP BY person_id`, PROVIDER12, account, runId, PROVIDER12, account);
25410
25788
  }
25411
25789
  function resultFromJson2(value) {
25412
- const parsed = record6(JSON.parse(value), "stored WhatsApp result");
25413
- exact4(parsed, ["account_subject", "contacts_seen", "contacts_imported", "contacts_matched", "contacts_skipped_self", "messages_seen", "messages_inserted", "matched_messages", "skipped_messages", "checkpoint_cursor", "local_insert_scan_complete", "remote_history_complete", "counts_complete", "counts_lower_bound"], "stored WhatsApp result");
25790
+ const parsed = record7(JSON.parse(value), "stored WhatsApp result");
25791
+ exact5(parsed, ["account_subject", "contacts_seen", "contacts_imported", "contacts_matched", "contacts_skipped_self", "messages_seen", "messages_inserted", "matched_messages", "skipped_messages", "checkpoint_cursor", "local_insert_scan_complete", "remote_history_complete", "counts_complete", "counts_lower_bound"], "stored WhatsApp result");
25414
25792
  const numeric = ["contacts_seen", "contacts_imported", "contacts_matched", "contacts_skipped_self", "messages_seen", "messages_inserted", "matched_messages", "skipped_messages"];
25415
25793
  for (const key of numeric)
25416
25794
  integer6(parsed[key], `stored WhatsApp result.${key}`, 0, Number.MAX_SAFE_INTEGER);
@@ -25461,26 +25839,26 @@ function importWhatsAppSnapshot(database, snapshot) {
25461
25839
  }));
25462
25840
  database.exec("BEGIN IMMEDIATE");
25463
25841
  try {
25464
- const byAuth = getRow9(database, "SELECT account_key,auth_sha256 FROM provider_accounts WHERE provider=? AND auth_id=?", PROVIDER11, snapshot.authId);
25465
- const byAccount = getRow9(database, "SELECT auth_id,auth_sha256 FROM provider_accounts WHERE provider=? AND account_key=?", PROVIDER11, account);
25842
+ const byAuth = getRow10(database, "SELECT account_key,auth_sha256 FROM provider_accounts WHERE provider=? AND auth_id=?", PROVIDER12, snapshot.authId);
25843
+ const byAccount = getRow10(database, "SELECT auth_id,auth_sha256 FROM provider_accounts WHERE provider=? AND account_key=?", PROVIDER12, account);
25466
25844
  if (byAuth !== null && (byAuth.account_key !== account || byAuth.auth_sha256 !== firstExecution.authSha256) || byAccount !== null && (byAccount.auth_id !== snapshot.authId || byAccount.auth_sha256 !== firstExecution.authSha256)) {
25467
25845
  throw new Error("WhatsApp durable auth-to-account binding drifted");
25468
25846
  }
25469
25847
  if (byAuth === null)
25470
- run8(database, `INSERT INTO provider_accounts(provider,auth_id,account_key,auth_sha256,first_seen_at,last_seen_at)
25471
- VALUES (?,?,?,?,?,?)`, PROVIDER11, snapshot.authId, account, firstExecution.authSha256, firstExecution.startedAt, lastExecution.finishedAt);
25848
+ run9(database, `INSERT INTO provider_accounts(provider,auth_id,account_key,auth_sha256,first_seen_at,last_seen_at)
25849
+ VALUES (?,?,?,?,?,?)`, PROVIDER12, snapshot.authId, account, firstExecution.authSha256, firstExecution.startedAt, lastExecution.finishedAt);
25472
25850
  else
25473
- run8(database, "UPDATE provider_accounts SET last_seen_at=? WHERE provider=? AND auth_id=?", lastExecution.finishedAt, PROVIDER11, snapshot.authId);
25851
+ run9(database, "UPDATE provider_accounts SET last_seen_at=? WHERE provider=? AND auth_id=?", lastExecution.finishedAt, PROVIDER12, snapshot.authId);
25474
25852
  const sourceRealmId = bindProviderAccountRealm(database, {
25475
- provider: PROVIDER11,
25853
+ provider: PROVIDER12,
25476
25854
  authId: snapshot.authId,
25477
25855
  accountKey: account,
25478
25856
  authSha256: firstExecution.authSha256,
25479
25857
  firstSeenAt: firstExecution.startedAt,
25480
25858
  lastSeenAt: lastExecution.finishedAt
25481
25859
  }).id;
25482
- const storedCheckpoint = getRow9(database, `SELECT cursor,cursor_anchor_sha256,generation_sha256,metadata_json
25483
- FROM provider_checkpoints WHERE provider=? AND account_key=? AND stream_key=?`, PROVIDER11, account, STREAM2);
25860
+ const storedCheckpoint = getRow10(database, `SELECT cursor,cursor_anchor_sha256,generation_sha256,metadata_json
25861
+ FROM provider_checkpoints WHERE provider=? AND account_key=? AND stream_key=?`, PROVIDER12, account, STREAM2);
25484
25862
  if (storedCheckpoint === null) {
25485
25863
  if (snapshot.startCheckpoint.cursor !== "0" || snapshot.startCheckpoint.anchor !== null || snapshot.startCheckpoint.generation !== undefined)
25486
25864
  throw new Error("WhatsApp initial scan must start at zero");
@@ -25490,8 +25868,8 @@ function importWhatsAppSnapshot(database, snapshot) {
25490
25868
  throw new Error("WhatsApp durable checkpoint or message-store generation drifted");
25491
25869
  }
25492
25870
  }
25493
- const existingRun = getRow9(database, `SELECT result_json FROM source_runs
25494
- WHERE provider=? AND account_key=? AND mode='linked-device-sync' AND source_sha256=?`, PROVIDER11, account, sourceDigest);
25871
+ const existingRun = getRow10(database, `SELECT result_json FROM source_runs
25872
+ WHERE provider=? AND account_key=? AND mode='linked-device-sync' AND source_sha256=?`, PROVIDER12, account, sourceDigest);
25495
25873
  if (existingRun !== null) {
25496
25874
  database.exec("COMMIT");
25497
25875
  return resultFromJson2(existingRun.result_json);
@@ -25508,8 +25886,8 @@ function importWhatsAppSnapshot(database, snapshot) {
25508
25886
  expectedContactsSkippedSelf += 1;
25509
25887
  continue;
25510
25888
  }
25511
- const exists = getRow9(database, `SELECT 1 FROM provider_resources
25512
- WHERE provider=? AND account_key=? AND resource_type='jid' AND resource_id=?`, PROVIDER11, account, contact.providerId) !== null;
25889
+ const exists = getRow10(database, `SELECT 1 FROM provider_resources
25890
+ WHERE provider=? AND account_key=? AND resource_type='jid' AND resource_id=?`, PROVIDER12, account, contact.providerId) !== null;
25513
25891
  if (exists)
25514
25892
  expectedContactsMatched += 1;
25515
25893
  else
@@ -25542,11 +25920,11 @@ function importWhatsAppSnapshot(database, snapshot) {
25542
25920
  counts_complete: false,
25543
25921
  counts_lower_bound: true
25544
25922
  };
25545
- const runInsert = run8(database, `INSERT INTO source_runs(
25923
+ const runInsert = run9(database, `INSERT INTO source_runs(
25546
25924
  provider,account_key,mode,source_sha256,source_locator_sha256,completeness,
25547
25925
  result_json,started_at,completed_at
25548
- ) VALUES (?,?,'linked-device-sync',?,?,'lower-bound',?,?,?)`, PROVIDER11, account, sourceDigest, sha2569(snapshot.authId), stableJson6(expectedResult), firstExecution.startedAt, lastExecution.finishedAt);
25549
- const runId = insertedId9(runInsert);
25926
+ ) VALUES (?,?,'linked-device-sync',?,?,'lower-bound',?,?,?)`, PROVIDER12, account, sourceDigest, sha2569(snapshot.authId), stableJson6(expectedResult), firstExecution.startedAt, lastExecution.finishedAt);
25927
+ const runId = insertedId10(runInsert);
25550
25928
  let ordinal = 0;
25551
25929
  let contactsSeen = 0;
25552
25930
  let contactsImported = 0;
@@ -25559,7 +25937,7 @@ function importWhatsAppSnapshot(database, snapshot) {
25559
25937
  if (contact.providerId === owner) {
25560
25938
  contactsSkippedSelf += 1;
25561
25939
  const item2 = stableJson6({ type: "contact", ...contact, resolution: "skipped-self" });
25562
- run8(database, `INSERT INTO source_records(run_id,ordinal,record_kind,record_sha256,resolution,projection_json,error_text)
25940
+ run9(database, `INSERT INTO source_records(run_id,ordinal,record_kind,record_sha256,resolution,projection_json,error_text)
25563
25941
  VALUES (?,?,'contact',?,'skipped',?,'owner-self-contact')`, runId, ordinal, sha2569(item2), item2);
25564
25942
  continue;
25565
25943
  }
@@ -25569,7 +25947,7 @@ function importWhatsAppSnapshot(database, snapshot) {
25569
25947
  else
25570
25948
  contactsMatched += 1;
25571
25949
  const item = stableJson6({ type: "contact", ...contact });
25572
- run8(database, `INSERT INTO source_records(
25950
+ run9(database, `INSERT INTO source_records(
25573
25951
  run_id,ordinal,record_kind,record_sha256,person_id,provider_resource_id,resolution,projection_json
25574
25952
  ) VALUES (?,?,'contact',?,?,?,?,?)`, runId, ordinal, sha2569(item), identity.personId, identity.resourceId, identity.imported ? "imported" : "matched", item);
25575
25953
  }
@@ -25613,13 +25991,13 @@ function importWhatsAppSnapshot(database, snapshot) {
25613
25991
  reason
25614
25992
  };
25615
25993
  const evidenceJson = stableJson6(evidence);
25616
- run8(database, `INSERT INTO source_records(
25994
+ run9(database, `INSERT INTO source_records(
25617
25995
  run_id,ordinal,record_kind,record_sha256,person_id,provider_resource_id,resolution,projection_json,error_text
25618
25996
  ) VALUES (?,?,'message',?,?,?,?,?,?)`, runId, ordinal, sha2569(evidenceJson), personId, resourceId, resolution, evidenceJson, resolution === "matched" ? null : reason);
25619
- run8(database, `INSERT INTO interaction_events(
25997
+ run9(database, `INSERT INTO interaction_events(
25620
25998
  provider,account_key,external_id,person_id,occurred_at,direction,conversation_sha256,
25621
25999
  event_kind,resolution,run_id,metadata_json
25622
- ) VALUES (?,?,?,?,?,?,?,'message',?,?,?)`, PROVIDER11, account, `row:${message.rowid}`, personId, message.timestamp, direction, conversationHash, resolution, runId, stableJson6({ conversationKind, reason, messageIdSha256: sha2569(message.messageId) }));
26000
+ ) VALUES (?,?,?,?,?,?,?,'message',?,?,?)`, PROVIDER12, account, `row:${message.rowid}`, personId, message.timestamp, direction, conversationHash, resolution, runId, stableJson6({ conversationKind, reason, messageIdSha256: sha2569(message.messageId) }));
25623
26001
  messagesInserted += 1;
25624
26002
  }
25625
26003
  refreshMetrics2(database, account, runId);
@@ -25641,8 +26019,8 @@ function importWhatsAppSnapshot(database, snapshot) {
25641
26019
  };
25642
26020
  if (stableJson6(result) !== stableJson6(expectedResult))
25643
26021
  throw new Error("WhatsApp applied counts drifted from the reviewed snapshot");
25644
- const metadata3 = stableJson6({ generation: scanGeneration, coverage: "local-insert-rowid-scan" });
25645
- run8(database, `INSERT INTO provider_checkpoints(
26022
+ const metadata4 = stableJson6({ generation: scanGeneration, coverage: "local-insert-rowid-scan" });
26023
+ run9(database, `INSERT INTO provider_checkpoints(
25646
26024
  provider,account_key,source_realm_id,stream_key,source_locator_sha256,schema_sha256,generation_sha256,
25647
26025
  cursor,cursor_anchor_sha256,last_run_id,metadata_json
25648
26026
  ) VALUES (?,?,?,?,?,?,?,?,?,?,?)
@@ -25650,7 +26028,7 @@ function importWhatsAppSnapshot(database, snapshot) {
25650
26028
  source_realm_id=excluded.source_realm_id,source_locator_sha256=excluded.source_locator_sha256,schema_sha256=excluded.schema_sha256,
25651
26029
  generation_sha256=excluded.generation_sha256,cursor=excluded.cursor,
25652
26030
  cursor_anchor_sha256=excluded.cursor_anchor_sha256,last_run_id=excluded.last_run_id,
25653
- metadata_json=excluded.metadata_json,updated_at=CURRENT_TIMESTAMP`, PROVIDER11, account, sourceRealmId, STREAM2, sha2569(snapshot.authId), CONTACTS_CONTRACT_SHA2562, generationSha256(scanGeneration), end2.cursor, end2.anchor, runId, metadata3);
26031
+ metadata_json=excluded.metadata_json,updated_at=CURRENT_TIMESTAMP`, PROVIDER12, account, sourceRealmId, STREAM2, sha2569(snapshot.authId), CONTACTS_CONTRACT_SHA2562, generationSha256(scanGeneration), end2.cursor, end2.anchor, runId, metadata4);
25654
26032
  database.exec("COMMIT");
25655
26033
  return result;
25656
26034
  } catch (error) {
@@ -25659,13 +26037,13 @@ function importWhatsAppSnapshot(database, snapshot) {
25659
26037
  }
25660
26038
  }
25661
26039
  function syncWhatsAppRelationships(database, options = {}) {
25662
- const auth = authId2(options.authId ?? DEFAULT_WHATSAPP_AUTH);
26040
+ const auth = authId3(options.authId ?? DEFAULT_WHATSAPP_AUTH);
25663
26041
  if (options.checkpoint !== undefined)
25664
26042
  throw new Error("sync checkpoint is database-owned");
25665
- const snapshot = wrenchWhatsAppSnapshot({ ...options, authId: auth, checkpoint: databaseCheckpoint(database, auth) });
26043
+ const snapshot = ghostgetWhatsAppSnapshot({ ...options, authId: auth, checkpoint: databaseCheckpoint(database, auth) });
25666
26044
  for (const page of [...snapshot.contactPages, ...snapshot.interactionPages]) {
25667
- ledgerPeopleBladeWrenchInvocation(database, {
25668
- provider: PROVIDER11,
26045
+ ledgerPeopleBladeGhostgetInvocation(database, {
26046
+ provider: PROVIDER12,
25669
26047
  accountKey: snapshot.accountSubject,
25670
26048
  capability: "contact_interactions",
25671
26049
  execution: page.execution,
@@ -25679,7 +26057,7 @@ function syncWhatsAppRelationships(database, options = {}) {
25679
26057
  }
25680
26058
 
25681
26059
  // src/cli/version.ts
25682
- var peoplebladeVersion = "0.2.1";
26060
+ var peoplebladeVersion = "0.3.0";
25683
26061
 
25684
26062
  // src/cli/main.ts
25685
26063
  var usage = `PeopleBlade \u2014 local-first contact intelligence
@@ -25719,20 +26097,23 @@ Core:
25719
26097
 
25720
26098
  Sources (append --auto-accept to run identity auto-accept after a successful import):
25721
26099
  contacts sync [--directory PATH] Sync macOS Contacts from the local AddressBook database
25722
- beeper sync [--auth ID] Sync connected Beeper accounts sequentially through Wrench
26100
+ beeper sync [--auth ID] Sync connected Beeper accounts sequentially through Ghostget
25723
26101
  [--with-relationships] Add body-free lower-bound direct interaction counts
25724
26102
  beeper search --query TEXT Import bounded fuzzy candidates for explicit identity review
25725
26103
  [--query TEXT ...] [--service NAME ...]
25726
26104
  beeper rebind --confirm Explicitly transition a verified existing Beeper source binding
25727
26105
  beeper stats Show aggregate Beeper realm and completeness statistics
25728
- google sync [--auth ID] Sync saved and Other Google Contacts through Wrench
26106
+ google sync [--auth ID] Sync saved and Other Google Contacts through Ghostget
25729
26107
  google stats Show aggregate Google contact statistics by collection
25730
26108
  imessage sync [--database PATH] Sync content-free iMessage metadata incrementally
25731
26109
  x import ZIP Import exact IDs from an official X data archive
25732
26110
  x stats Show aggregate X archive statistics
25733
- x mutuals sync Sync X mutuals through Wrench (requires reviewed Wrench capability)
25734
- whatsapp sync [--auth ID] Sync WhatsApp through Wrench's linked-device projection
26111
+ x mutuals sync Sync X mutuals through Ghostget (requires reviewed Ghostget capability)
26112
+ whatsapp sync [--auth ID] Sync WhatsApp through Ghostget's linked-device projection
25735
26113
  linkedin import ZIP Import an official LinkedIn data-export ZIP
26114
+ linkedin contact-info --person-id ID
26115
+ Read one first-degree connection's Contact info through Ghostget
26116
+ [--account KEY] [--auth ID]
25736
26117
  linkedin stats Show aggregate LinkedIn import statistics
25737
26118
  instagram import ZIP Import an official Instagram JSON archive
25738
26119
  instagram stats Show aggregate Instagram import statistics
@@ -26462,17 +26843,17 @@ ${verification}`) });
26462
26843
  }
26463
26844
  if (command === "beeper" && subcommand === "sync") {
26464
26845
  const options = [...rest];
26465
- const authId3 = valueAfter(options, "--auth");
26846
+ const authId4 = valueAfter(options, "--auth");
26466
26847
  const contactLimit = positive(valueAfter(options, "--contact-limit"), "--contact-limit", 200, 200);
26467
26848
  const withRelationships = options.includes("--with-relationships");
26468
26849
  if (withRelationships)
26469
26850
  options.splice(options.indexOf("--with-relationships"), 1);
26470
26851
  if (options.length)
26471
26852
  fail3(`Unknown argument: ${options[0]}`);
26472
- const effectiveAuthId = authId3 ?? DEFAULT_BEEPER_AUTH;
26853
+ const effectiveAuthId = authId4 ?? DEFAULT_BEEPER_AUTH;
26473
26854
  if (withRelationships)
26474
- console.error("Beeper relationships \xB7 deriving a body-free interaction summary through Wrench");
26475
- console.error("Beeper contacts \xB7 discovering connected accounts through Wrench");
26855
+ console.error("Beeper relationships \xB7 deriving a body-free interaction summary through Ghostget");
26856
+ console.error("Beeper contacts \xB7 discovering connected accounts through Ghostget");
26476
26857
  printImport(syncBeeperContacts(database, {
26477
26858
  authId: effectiveAuthId,
26478
26859
  contactLimit,
@@ -26491,23 +26872,23 @@ ${verification}`) });
26491
26872
  }
26492
26873
  if (command === "beeper" && subcommand === "rebind") {
26493
26874
  const options = [...rest];
26494
- const authId3 = valueAfter(options, "--auth");
26875
+ const authId4 = valueAfter(options, "--auth");
26495
26876
  const confirm = options.includes("--confirm");
26496
26877
  if (confirm)
26497
26878
  options.splice(options.indexOf("--confirm"), 1);
26498
26879
  if (options.length)
26499
26880
  fail3(`Unknown argument: ${options[0]}`);
26500
26881
  if (!confirm)
26501
- fail3("beeper rebind requires --confirm after reviewing the current Wrench binding, release, and connected-account inventory.");
26882
+ fail3("beeper rebind requires --confirm after reviewing the current Ghostget binding, release, and connected-account inventory.");
26502
26883
  console.error("Beeper binding \xB7 verifying the complete connected-account inventory before an append-only transition");
26503
- print(rebindBeeperSource(database, { ...authId3 === undefined ? {} : { authId: authId3 } }), asJson);
26884
+ print(rebindBeeperSource(database, { ...authId4 === undefined ? {} : { authId: authId4 } }), asJson);
26504
26885
  return;
26505
26886
  }
26506
26887
  if (command === "beeper" && subcommand === "search") {
26507
26888
  const options = [...rest];
26508
26889
  const queries = valuesAfter(options, "--query");
26509
26890
  const services = valuesAfter(options, "--service");
26510
- const authId3 = valueAfter(options, "--auth");
26891
+ const authId4 = valueAfter(options, "--auth");
26511
26892
  const limit = positive(valueAfter(options, "--limit"), "--limit", 20, 20);
26512
26893
  if (queries.length === 0)
26513
26894
  fail3("beeper search requires one or more --query values.");
@@ -26516,18 +26897,18 @@ ${verification}`) });
26516
26897
  print(backfillBeeperSearch(database, {
26517
26898
  queries,
26518
26899
  ...services.length === 0 ? {} : { services },
26519
- ...authId3 === undefined ? {} : { authId: authId3 },
26900
+ ...authId4 === undefined ? {} : { authId: authId4 },
26520
26901
  limit
26521
26902
  }), asJson);
26522
26903
  return;
26523
26904
  }
26524
26905
  if (command === "google" && subcommand === "sync") {
26525
26906
  const options = [...rest];
26526
- const authId3 = valueAfter(options, "--auth");
26907
+ const authId4 = valueAfter(options, "--auth");
26527
26908
  const pageSize = positive(valueAfter(options, "--page-size"), "--page-size", 100, 100);
26528
26909
  if (options.length)
26529
26910
  fail3(`Unknown argument: ${options[0]}`);
26530
- printImport(syncGoogleContacts(database, { ...authId3 === undefined ? {} : { authId: authId3 }, pageSize }), asJson);
26911
+ printImport(syncGoogleContacts(database, { ...authId4 === undefined ? {} : { authId: authId4 }, pageSize }), asJson);
26531
26912
  return;
26532
26913
  }
26533
26914
  if (command === "google" && subcommand === "stats") {
@@ -26552,13 +26933,13 @@ ${verification}`) });
26552
26933
  }
26553
26934
  if (command === "whatsapp" && subcommand === "sync") {
26554
26935
  const options = [...rest];
26555
- const authId3 = valueAfter(options, "--auth");
26936
+ const authId4 = valueAfter(options, "--auth");
26556
26937
  const contactPageSize = positive(valueAfter(options, "--contact-page-size"), "--contact-page-size", 100, 100);
26557
26938
  const interactionPageSize = positive(valueAfter(options, "--interaction-page-size"), "--interaction-page-size", 1000, 1000);
26558
26939
  if (options.length)
26559
26940
  fail3(`Unknown argument: ${options[0]}`);
26560
26941
  printImport(syncWhatsAppRelationships(database, {
26561
- ...authId3 === undefined ? {} : { authId: authId3 },
26942
+ ...authId4 === undefined ? {} : { authId: authId4 },
26562
26943
  contactPageSize,
26563
26944
  interactionPageSize
26564
26945
  }), asJson);
@@ -26579,6 +26960,25 @@ ${verification}`) });
26579
26960
  }), asJson);
26580
26961
  return;
26581
26962
  }
26963
+ if (command === "linkedin" && subcommand === "contact-info") {
26964
+ const options = [...rest];
26965
+ const personText = valueAfter(options, "--person-id");
26966
+ if (personText === undefined)
26967
+ fail3("linkedin contact-info requires --person-id ID.");
26968
+ const personId = Number(personText);
26969
+ if (!Number.isSafeInteger(personId) || personId < 1)
26970
+ fail3("--person-id must be a positive integer.");
26971
+ const accountKey5 = valueAfter(options, "--account");
26972
+ const authId4 = valueAfter(options, "--auth");
26973
+ if (options.length)
26974
+ fail3(`Unknown argument: ${options[0]}`);
26975
+ print(readLinkedInContactInfo(database, {
26976
+ personId,
26977
+ ...accountKey5 === undefined ? {} : { accountKey: accountKey5 },
26978
+ ...authId4 === undefined ? {} : { authId: authId4 }
26979
+ }), asJson);
26980
+ return;
26981
+ }
26582
26982
  if (command === "linkedin" && subcommand === "stats") {
26583
26983
  if (rest.length)
26584
26984
  fail3(`Unknown argument: ${rest[0]}`);
@@ -26625,7 +27025,7 @@ ${verification}`) });
26625
27025
  return;
26626
27026
  }
26627
27027
  if (command === "x" && subcommand === "mutuals" && rest[0] === "sync")
26628
- fail3("X mutual sync is not enabled until Wrench ships a reviewed, bounded x-web mutuals capability. No official X API is required.");
27028
+ fail3("X mutual sync is not enabled until Ghostget ships a reviewed, bounded x-web mutuals capability. No official X API is required.");
26629
27029
  fail3(`Unknown command.
26630
27030
 
26631
27031
  ${usage}`);