mcp-scraper 0.79.1 → 0.79.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/CHANGELOG.md +25 -1
  2. package/README.md +1 -1
  3. package/dist/{analytics-repository-VEUDEPWI.js → analytics-repository-YOY5KMOD.js} +3 -3
  4. package/dist/bin/api-server.js +4 -4
  5. package/dist/bin/mcp-scraper-cli.js +1 -1
  6. package/dist/bin/mcp-scraper-core.js +7 -7
  7. package/dist/bin/mcp-scraper-install.js +2 -2
  8. package/dist/bin/mcp-stdio-server.js +7 -7
  9. package/dist/bin/paa-harvest.js +3 -3
  10. package/dist/{chunk-LB2GNACG.js → chunk-3423R23T.js} +3 -3
  11. package/dist/{chunk-NGLZ6UJR.js → chunk-5UAFBKJR.js} +1 -1
  12. package/dist/{chunk-B6L73AO4.js → chunk-6HAV7LCE.js} +3 -1
  13. package/dist/{chunk-NH3EUCZL.js → chunk-7UZAVM4J.js} +138 -11
  14. package/dist/{chunk-Q5L2OCOQ.js → chunk-C5Z4OFKW.js} +1 -1
  15. package/dist/{chunk-KAGHJQFO.js → chunk-EQGTEHLZ.js} +1 -1
  16. package/dist/{chunk-BTQ23KCT.js → chunk-F5GQJWZU.js} +1 -1
  17. package/dist/{chunk-DUWZQSSJ.js → chunk-HEUMDX4I.js} +1 -1
  18. package/dist/{chunk-OIGM6VKQ.js → chunk-IHYG52ZW.js} +1 -1
  19. package/dist/{chunk-OUBH6XMY.js → chunk-K3Z5AQYE.js} +1 -1
  20. package/dist/{chunk-UFJJGXVO.js → chunk-KNGTQD6U.js} +396 -67
  21. package/dist/{chunk-R4YRH5PG.js → chunk-MVB25X55.js} +1 -1
  22. package/dist/{chunk-47ZCUBM5.js → chunk-NVUKO5NN.js} +12 -1
  23. package/dist/{chunk-QVW5S6BD.js → chunk-TCYZ7HMU.js} +3 -3
  24. package/dist/{chunk-SL7YVA4S.js → chunk-YBR32LOD.js} +1 -1
  25. package/dist/{chunk-OU4FV2RP.js → chunk-YXNDOQXN.js} +49 -0
  26. package/dist/{db-TA567JLA.js → db-Z34LPZNR.js} +5 -1
  27. package/dist/{extract-bundle-I2GNC25L.js → extract-bundle-S3ZGNFML.js} +3 -3
  28. package/dist/{gmail-service-GGQVJUC3.js → gmail-service-YFS2OV4S.js} +4 -4
  29. package/dist/index.cjs +394 -65
  30. package/dist/index.d.cts +35 -0
  31. package/dist/index.d.ts +35 -0
  32. package/dist/index.js +3 -3
  33. package/dist/{lead-list-enrichment-repository-5LEWW4X7.js → lead-list-enrichment-repository-36RPVV6N.js} +2 -2
  34. package/dist/{location-data-repository-AHKDXTEQ.js → location-data-repository-WPRG62GE.js} +2 -2
  35. package/dist/{server-MNSYIX42.js → server-MDWFOUTS.js} +73 -28
  36. package/dist/{site-extract-repository-KF736IR6.js → site-extract-repository-WAJMIDPJ.js} +2 -2
  37. package/dist/{worker-VU6JCCLG.js → worker-3LUFQWWJ.js} +5 -5
  38. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,21 @@ All notable changes to MCP Scraper are documented here. The format is based on [
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.79.3] - 2026-08-29
8
+
9
+ ### Fixed
10
+
11
+ - Persisted per-control PAA dispatch and 0.7/1.0/1.4-second confirmation telemetry in durable checkpoints, exposed recent interaction and attempt correlation through MCP status, attached Bright Data session IDs immediately after browser launch, and finalized dangling attempt rows during lease recovery without blocking customer settlement.
12
+ - Prevented inline style, script, and hidden DOM text inside Google answer containers from falsely confirming that PAA answer material loaded.
13
+ - Routed canonical `/assistant` page loads to the web app and the redacted private Assistant readiness endpoint to the main API function, preventing production 404s after the 0.79.1 launch.
14
+
15
+ ## [0.79.2] - 2026-08-28
16
+
17
+ ### Fixed
18
+
19
+ - Rejected Google loading and error placeholders as PAA answers, retried interrupted controls without misreporting frontier exhaustion, preserved complete answer/source material from retained DOM, and resolved surviving Google `/goto` evidence after a late browser disconnect without visiting publisher pages.
20
+ - Advanced requested question counts through bounded newest-frontier click batches with 0.7–1.4 second observation windows, reducing a verified 35-question complete harvest from 347 seconds to 83 seconds while retaining actual multi-question click growth.
21
+
7
22
  ## [0.79.1] - 2026-08-28
8
23
 
9
24
  ### Fixed
@@ -1478,7 +1493,16 @@ All notable changes to MCP Scraper are documented here. The format is based on [
1478
1493
  - Write actions remain unavailable until the account owner explicitly enables them.
1479
1494
  - Provider-specific connection data is normalized into one agent-facing contract.
1480
1495
 
1481
- [Unreleased]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.73.5...HEAD
1496
+ [Unreleased]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.79.2...HEAD
1497
+ [0.79.2]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.79.1...v0.79.2
1498
+ [0.79.1]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.79.0...v0.79.1
1499
+ [0.79.0]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.78.0...v0.79.0
1500
+ [0.78.0]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.77.0...v0.78.0
1501
+ [0.77.0]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.76.0...v0.77.0
1502
+ [0.76.0]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.75.1...v0.76.0
1503
+ [0.75.1]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.75.0...v0.75.1
1504
+ [0.75.0]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.74.0...v0.75.0
1505
+ [0.74.0]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.73.5...v0.74.0
1482
1506
  [0.73.5]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.73.4...v0.73.5
1483
1507
  [0.73.4]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.73.3...v0.73.4
1484
1508
  [0.73.3]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.73.2...v0.73.3
package/README.md CHANGED
@@ -173,7 +173,7 @@ Build the branded one-click bundle:
173
173
  npm run build:mcpb
174
174
  ```
175
175
 
176
- The generated bundle is written to `build/mcpb/mcp-scraper-<version>.mcpb` and copied to `public/downloads/` for the hosted download. The current public bundle is `https://mcpscraper.dev/downloads/mcp-scraper.mcpb` (`0.79.1`, SHA-256 `25c661ca24ac033667250ddb6866e1009a5ffa55789e4791475e20e2cd4103da`). Install it by opening or dragging it into Claude Desktop. Claude displays the `MCP Scraper` install card, icon, API-key configuration field, and manually curated current-release message from the bundle manifest.
176
+ The generated bundle is written to `build/mcpb/mcp-scraper-<version>.mcpb` and copied to `public/downloads/` for the hosted download. The current public bundle is `https://mcpscraper.dev/downloads/mcp-scraper.mcpb` (`0.79.3`, SHA-256 `aa51d15b20740d5fa98d92ce919b4d37ff8f02a949c0186c90e403fd356dad14`). Install it by opening or dragging it into Claude Desktop. Claude displays the `MCP Scraper` install card, icon, API-key configuration field, and manually curated current-release message from the bundle manifest.
177
177
 
178
178
  The MCPB install exposes every tool — web-intelligence plus all `browser_*` tools — through the one `mcp-scraper` server.
179
179
 
@@ -85,9 +85,9 @@ import {
85
85
  updateAnalyticsPixel,
86
86
  upsertAnalyticsAdSpend,
87
87
  upsertAnalyticsHostGroup
88
- } from "./chunk-DUWZQSSJ.js";
89
- import "./chunk-Q5L2OCOQ.js";
90
- import "./chunk-OU4FV2RP.js";
88
+ } from "./chunk-HEUMDX4I.js";
89
+ import "./chunk-C5Z4OFKW.js";
90
+ import "./chunk-YXNDOQXN.js";
91
91
  export {
92
92
  ANALYTICS_CONTENT_SORTS,
93
93
  AnalyticsRepositoryError,
@@ -17,16 +17,16 @@ loadDotEnv();
17
17
  async function main() {
18
18
  const [{ serve }, { app, personalAssistantProductionStartup }, { startWorker }, { migrate }] = await Promise.all([
19
19
  import("@hono/node-server"),
20
- import("../server-MNSYIX42.js"),
21
- import("../worker-VU6JCCLG.js"),
22
- import("../db-TA567JLA.js")
20
+ import("../server-MDWFOUTS.js"),
21
+ import("../worker-3LUFQWWJ.js"),
22
+ import("../db-Z34LPZNR.js")
23
23
  ]);
24
24
  const PORT = parseInt(process.env.PORT ?? "3001");
25
25
  try {
26
26
  await personalAssistantProductionStartup;
27
27
  await migrate();
28
28
  if (process.env.ANALYTICS_DATABASE_URL) {
29
- const { migrateAnalytics } = await import("../analytics-repository-VEUDEPWI.js");
29
+ const { migrateAnalytics } = await import("../analytics-repository-YOY5KMOD.js");
30
30
  await migrateAnalytics();
31
31
  }
32
32
  startWorker();
@@ -13,7 +13,7 @@ import "../chunk-VXLU74YZ.js";
13
13
  import "../chunk-GGZEC22A.js";
14
14
  import {
15
15
  PACKAGE_VERSION
16
- } from "../chunk-OIGM6VKQ.js";
16
+ } from "../chunk-IHYG52ZW.js";
17
17
 
18
18
  // src/cli/human-cli.ts
19
19
  import { Command } from "commander";
@@ -1,20 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runMcpScraperStdio
4
- } from "../chunk-QVW5S6BD.js";
5
- import "../chunk-NH3EUCZL.js";
4
+ } from "../chunk-TCYZ7HMU.js";
5
+ import "../chunk-7UZAVM4J.js";
6
6
  import "../chunk-PGJQDMC2.js";
7
7
  import "../chunk-DNM65UCK.js";
8
8
  import "../chunk-T3MZISOF.js";
9
- import "../chunk-B6L73AO4.js";
9
+ import "../chunk-6HAV7LCE.js";
10
10
  import "../chunk-VFCUGTCF.js";
11
11
  import "../chunk-OM7HVEJ3.js";
12
- import "../chunk-NGLZ6UJR.js";
13
- import "../chunk-R4YRH5PG.js";
12
+ import "../chunk-5UAFBKJR.js";
13
+ import "../chunk-MVB25X55.js";
14
14
  import "../chunk-VXLU74YZ.js";
15
15
  import "../chunk-GGZEC22A.js";
16
- import "../chunk-OIGM6VKQ.js";
17
- import "../chunk-OU4FV2RP.js";
16
+ import "../chunk-IHYG52ZW.js";
17
+ import "../chunk-YXNDOQXN.js";
18
18
 
19
19
  // src/mcp/thorbit-restricted-tool-surface.ts
20
20
  var THORBIT_RESTRICTED_TOOL_NAMES = [
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  renderInstallTerminal
4
- } from "../chunk-R4YRH5PG.js";
4
+ } from "../chunk-MVB25X55.js";
5
5
  import {
6
6
  PACKAGE_VERSION
7
- } from "../chunk-OIGM6VKQ.js";
7
+ } from "../chunk-IHYG52ZW.js";
8
8
 
9
9
  // bin/mcp-scraper-install.ts
10
10
  var noColor = process.argv.includes("--no-color") || process.env.NO_COLOR !== void 0 || process.env.FORCE_COLOR === "0" || !process.stdout.isTTY;
@@ -1,20 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runMcpScraperStdio
4
- } from "../chunk-QVW5S6BD.js";
5
- import "../chunk-NH3EUCZL.js";
4
+ } from "../chunk-TCYZ7HMU.js";
5
+ import "../chunk-7UZAVM4J.js";
6
6
  import "../chunk-PGJQDMC2.js";
7
7
  import "../chunk-DNM65UCK.js";
8
8
  import "../chunk-T3MZISOF.js";
9
- import "../chunk-B6L73AO4.js";
9
+ import "../chunk-6HAV7LCE.js";
10
10
  import "../chunk-VFCUGTCF.js";
11
11
  import "../chunk-OM7HVEJ3.js";
12
- import "../chunk-NGLZ6UJR.js";
13
- import "../chunk-R4YRH5PG.js";
12
+ import "../chunk-5UAFBKJR.js";
13
+ import "../chunk-MVB25X55.js";
14
14
  import "../chunk-VXLU74YZ.js";
15
15
  import "../chunk-GGZEC22A.js";
16
- import "../chunk-OIGM6VKQ.js";
17
- import "../chunk-OU4FV2RP.js";
16
+ import "../chunk-IHYG52ZW.js";
17
+ import "../chunk-YXNDOQXN.js";
18
18
 
19
19
  // bin/mcp-stdio-server.ts
20
20
  runMcpScraperStdio();
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  harvest
4
- } from "../chunk-UFJJGXVO.js";
4
+ } from "../chunk-KNGTQD6U.js";
5
5
  import {
6
6
  browserServiceApiKey
7
7
  } from "../chunk-OM7HVEJ3.js";
8
- import "../chunk-NGLZ6UJR.js";
8
+ import "../chunk-5UAFBKJR.js";
9
9
  import "../chunk-OWF2JJKN.js";
10
- import "../chunk-OU4FV2RP.js";
10
+ import "../chunk-YXNDOQXN.js";
11
11
 
12
12
  // src/cli.ts
13
13
  import { Command } from "commander";
@@ -5,7 +5,7 @@ import {
5
5
  recordServiceConnectionHealth,
6
6
  setServiceConnectionProviderIdentity,
7
7
  updateServiceConnectionTools
8
- } from "./chunk-Q5L2OCOQ.js";
8
+ } from "./chunk-C5Z4OFKW.js";
9
9
  import {
10
10
  createConnectedDataArtifact,
11
11
  createConnectedDataBinaryArtifact
@@ -23,13 +23,13 @@ import {
23
23
  import {
24
24
  recordVendorUsage,
25
25
  runWithCostContext
26
- } from "./chunk-NGLZ6UJR.js";
26
+ } from "./chunk-5UAFBKJR.js";
27
27
  import {
28
28
  debitMcIdempotent,
29
29
  getDb,
30
30
  getUserByEmail,
31
31
  reconcileBalanceMc
32
- } from "./chunk-OU4FV2RP.js";
32
+ } from "./chunk-YXNDOQXN.js";
33
33
 
34
34
  // src/api/gmail-service.ts
35
35
  import { createHash as createHash4, createHmac, timingSafeEqual } from "crypto";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getDb
3
- } from "./chunk-OU4FV2RP.js";
3
+ } from "./chunk-YXNDOQXN.js";
4
4
 
5
5
  // src/api/cost-context.ts
6
6
  import { AsyncLocalStorage } from "async_hooks";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  publicErrorMessage,
3
3
  sanitizeVendorName
4
- } from "./chunk-OU4FV2RP.js";
4
+ } from "./chunk-YXNDOQXN.js";
5
5
 
6
6
  // src/api/outbound-sanitize.ts
7
7
  var KEY_RENAMES = {
@@ -46,6 +46,7 @@ var INTERNAL_DIAGNOSTIC_KEYS = /* @__PURE__ */ new Set([
46
46
  // bypassing that projection through the generic diagnostics sanitizer.
47
47
  "browser_provider",
48
48
  "provider_session_id",
49
+ "provider_session_observed_at",
49
50
  "provider_lookup_status",
50
51
  "provider_status",
51
52
  "provider_error_code",
@@ -190,6 +191,7 @@ function projectAttemptProviderTelemetry(attempt) {
190
191
  return {
191
192
  browser_provider: allowlistedString(attempt.browser_provider, PUBLIC_BROWSER_PROVIDERS),
192
193
  provider_session_id: publicProviderSessionId(attempt.provider_session_id),
194
+ provider_session_observed_at: publicIsoTimestamp(attempt.provider_session_observed_at),
193
195
  provider_lookup_status: allowlistedString(attempt.provider_lookup_status, PUBLIC_PROVIDER_LOOKUP_STATUSES),
194
196
  provider_status: allowlistedString(attempt.provider_status, PUBLIC_PROVIDER_STATUSES),
195
197
  provider_error_code: publicProviderErrorCode(attempt.provider_error_code),
@@ -19,7 +19,7 @@ import {
19
19
  } from "./chunk-T3MZISOF.js";
20
20
  import {
21
21
  sanitizeOutboundDiagnostics
22
- } from "./chunk-B6L73AO4.js";
22
+ } from "./chunk-6HAV7LCE.js";
23
23
  import {
24
24
  MC_PER_CREDIT,
25
25
  PAA_BASE_CREDITS,
@@ -34,7 +34,7 @@ import {
34
34
  import {
35
35
  recordVendorUsage,
36
36
  vendorCostUsd
37
- } from "./chunk-NGLZ6UJR.js";
37
+ } from "./chunk-5UAFBKJR.js";
38
38
  import {
39
39
  buildSerpEmailQuery,
40
40
  classifyEmailScope,
@@ -45,14 +45,14 @@ import {
45
45
  } from "./chunk-VXLU74YZ.js";
46
46
  import {
47
47
  PACKAGE_VERSION
48
- } from "./chunk-OIGM6VKQ.js";
48
+ } from "./chunk-IHYG52ZW.js";
49
49
  import {
50
50
  PUBLIC_ERROR_CODES,
51
51
  buildPublicErrorEnvelope,
52
52
  normalizePublicErrorCode,
53
53
  publicErrorMessage,
54
54
  sanitizeVendorName
55
- } from "./chunk-OU4FV2RP.js";
55
+ } from "./chunk-YXNDOQXN.js";
56
56
 
57
57
  // src/harvest-timeout.ts
58
58
  var SCRAPE_FUNCTION_MAX_MS = 8e5;
@@ -1139,9 +1139,64 @@ function publicPaaLifecycle(value) {
1139
1139
  knownQuestions: finiteNonNegative(row.knownQuestions) ?? questionsFound,
1140
1140
  processedQuestions: finiteNonNegative(row.processedQuestions) ?? 0,
1141
1141
  failedInteractions: finiteNonNegative(row.failedInteractions) ?? 0,
1142
- noGrowthConfirmations: finiteNonNegative(row.noGrowthConfirmations) ?? 0
1142
+ noGrowthConfirmations: finiteNonNegative(row.noGrowthConfirmations) ?? 0,
1143
+ visibleControls: finiteNonNegative(row.visibleControls) ?? 0,
1144
+ eligibleControls: finiteNonNegative(row.eligibleControls) ?? 0,
1145
+ dispatchedInteractions: finiteNonNegative(row.dispatchedInteractions) ?? 0,
1146
+ confirmedInteractions: finiteNonNegative(row.confirmedInteractions) ?? 0,
1147
+ unconfirmedInteractions: finiteNonNegative(row.unconfirmedInteractions) ?? 0
1143
1148
  };
1144
1149
  }
1150
+ function publicPaaInteraction(value) {
1151
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
1152
+ const row = value;
1153
+ const id = nullableBoundedString(row.id, 200);
1154
+ const question = nullableBoundedString(row.question, 2e3);
1155
+ if (!id || !question) return null;
1156
+ const outcome = row.outcome === "confirmed" || row.outcome === "unconfirmed" || row.outcome === "dispatch_failed" ? row.outcome : "unconfirmed";
1157
+ const allowedSignals = /* @__PURE__ */ new Set(["expanded", "answer", "source", "question_growth"]);
1158
+ return {
1159
+ id,
1160
+ questionId: nullableBoundedString(row.questionId, 100) ?? "",
1161
+ question,
1162
+ batchNumber: finiteNonNegative(row.batchNumber) ?? 0,
1163
+ controlAttempt: finiteNonNegative(row.controlAttempt) ?? 0,
1164
+ observedAt: nullableBoundedString(row.observedAt, 100),
1165
+ dispatched: row.dispatched === true,
1166
+ outcome,
1167
+ confirmationSignals: Array.isArray(row.confirmationSignals) ? row.confirmationSignals.filter((signal) => typeof signal === "string" && allowedSignals.has(signal)) : [],
1168
+ confirmationCheckpointMs: finiteNonNegative(row.confirmationCheckpointMs),
1169
+ confirmedAtMs: finiteNonNegative(row.confirmedAtMs),
1170
+ dispatchDurationMs: finiteNonNegative(row.dispatchDurationMs) ?? 0,
1171
+ totalDurationMs: finiteNonNegative(row.totalDurationMs) ?? 0,
1172
+ beforeQuestionCount: finiteNonNegative(row.beforeQuestionCount) ?? 0,
1173
+ afterQuestionCount: finiteNonNegative(row.afterQuestionCount) ?? 0,
1174
+ newQuestionCount: finiteNonNegative(row.newQuestionCount) ?? 0,
1175
+ expandedBefore: row.expandedBefore === true,
1176
+ expandedAfter: row.expandedAfter === true,
1177
+ answerObserved: row.answerObserved === true,
1178
+ sourceCount: finiteNonNegative(row.sourceCount) ?? 0,
1179
+ errorCode: nullableBoundedString(row.errorCode, 100)
1180
+ };
1181
+ }
1182
+ function publicPaaInteractionSummary(value) {
1183
+ const row = structuredRecord(value);
1184
+ return Object.fromEntries([
1185
+ "observations",
1186
+ "dispatched",
1187
+ "confirmed",
1188
+ "unconfirmed",
1189
+ "dispatchFailures",
1190
+ "confirmedWithoutDispatchAck",
1191
+ "expandedSignals",
1192
+ "answerSignals",
1193
+ "sourceSignals",
1194
+ "questionGrowthBatches",
1195
+ "checkpoint700ms",
1196
+ "checkpoint1000ms",
1197
+ "checkpoint1400ms"
1198
+ ].map((key) => [key, finiteNonNegative(row[key]) ?? 0]));
1199
+ }
1145
1200
  function publicPaaSource(value) {
1146
1201
  if (!value || typeof value !== "object") return null;
1147
1202
  const source = value;
@@ -1318,6 +1373,11 @@ function durablePaaProgress(result, options) {
1318
1373
  row.source_cite ?? row.sourceCite ?? row.source_site ?? row.sourceSite ?? row.source_url ?? row.sourceUrl
1319
1374
  ) !== null).length;
1320
1375
  const lifecycle = publicPaaLifecycle(diagnostics.paaLifecycle ?? structuredRecord(result.progress).lifecycle);
1376
+ const rawProgress = structuredRecord(result.progress);
1377
+ const interactions = Array.isArray(rawProgress.interactions) ? rawProgress.interactions.flatMap((value) => {
1378
+ const interaction = publicPaaInteraction(value);
1379
+ return interaction ? [interaction] : [];
1380
+ }) : [];
1321
1381
  if (lifecycle) {
1322
1382
  lifecycle.automaticRetries = Math.max(
1323
1383
  finiteNonNegative(lifecycle.automaticRetries) ?? 0,
@@ -1331,7 +1391,9 @@ function durablePaaProgress(result, options) {
1331
1391
  sourcedQuestions: sourced,
1332
1392
  missingAnswers: finiteNonNegative(completeness.paaWithoutAnswer ?? completeness.missingAnswers) ?? Math.max(0, captured - answered),
1333
1393
  missingSources: finiteNonNegative(completeness.paaWithoutSource ?? completeness.missingSources) ?? Math.max(0, captured - sourced),
1334
- lifecycle
1394
+ lifecycle,
1395
+ interactionSummary: publicPaaInteractionSummary(rawProgress.interactionSummary),
1396
+ recentInteractions: interactions.slice(-20)
1335
1397
  };
1336
1398
  }
1337
1399
  function durablePaaResult(result) {
@@ -1356,11 +1418,14 @@ function durablePaaAttempts(value) {
1356
1418
  if (!entry || typeof entry !== "object" || Array.isArray(entry)) return [];
1357
1419
  const row = entry;
1358
1420
  return [{
1421
+ attemptId: nullableBoundedString(row.id ?? row.attemptId, 200) ?? "",
1359
1422
  attemptNumber: finiteNonNegative(row.attempt_number ?? row.attemptNumber) ?? index + 1,
1423
+ status: nullableBoundedString(row.status, 100),
1360
1424
  outcome: nullableBoundedString(row.outcome),
1361
1425
  questionCount: finiteNonNegative(row.question_count ?? row.questionCount),
1362
1426
  provider: nullableBoundedString(row.browser_provider ?? row.provider, 100),
1363
1427
  providerSessionId: nullableBoundedString(row.provider_session_id ?? row.providerSessionId, 200),
1428
+ providerSessionObservedAt: nullableBoundedString(row.provider_session_observed_at ?? row.providerSessionObservedAt, 100),
1364
1429
  providerLookupStatus: nullableBoundedString(row.provider_lookup_status ?? row.providerLookupStatus, 100),
1365
1430
  providerStatus: nullableBoundedString(row.provider_status ?? row.providerStatus, 100),
1366
1431
  providerErrorCode: nullableBoundedString(row.provider_error_code ?? row.providerErrorCode, 100),
@@ -1371,7 +1436,10 @@ function durablePaaAttempts(value) {
1371
1436
  providerBandwidthBytes: finiteNonNegative(row.provider_bandwidth_bytes ?? row.providerBandwidthBytes),
1372
1437
  providerCaptcha: typeof (row.provider_captcha ?? row.providerCaptcha) === "boolean" ? row.provider_captcha ?? row.providerCaptcha : null,
1373
1438
  providerCheckedAt: nullableBoundedString(row.provider_checked_at ?? row.providerCheckedAt, 100),
1374
- willRetry: typeof (row.will_retry ?? row.willRetry) === "boolean" ? row.will_retry ?? row.willRetry : null
1439
+ willRetry: typeof (row.will_retry ?? row.willRetry) === "boolean" ? row.will_retry ?? row.willRetry : null,
1440
+ durationMs: finiteNonNegative(row.duration_ms ?? row.durationMs),
1441
+ startedAt: nullableBoundedString(row.created_at ?? row.startedAt, 100),
1442
+ completedAt: nullableBoundedString(row.completed_at ?? row.completedAt, 100)
1375
1443
  }];
1376
1444
  });
1377
1445
  }
@@ -1401,6 +1469,8 @@ function formatHarvestPaaStart(raw) {
1401
1469
  const state = durablePaaState(parsed.data.status ?? parsed.data.state);
1402
1470
  const structuredContent = {
1403
1471
  jobId,
1472
+ operationId: jobId,
1473
+ taskId: jobId,
1404
1474
  status: durablePaaStatus(state),
1405
1475
  replayed: parsed.data.replayed === true,
1406
1476
  statusTool: "harvest_paa_status"
@@ -1429,6 +1499,8 @@ function formatHarvestPaaStatus(raw) {
1429
1499
  const billingState = billingSettled ? billedMc === 0 ? "refunded" : "settled" : state === "failed" || state === "cancelled" ? "refund_pending" : holdMc !== null ? "held" : "unknown";
1430
1500
  const structuredContent = {
1431
1501
  jobId,
1502
+ operationId: jobId,
1503
+ taskId: jobId,
1432
1504
  status: durablePaaStatus(state),
1433
1505
  replayed: parsed.data.replayed === true,
1434
1506
  progress,
@@ -8546,8 +8618,51 @@ var PaaLifecycleOutput = z6.object({
8546
8618
  knownQuestions: z6.number().int().min(0),
8547
8619
  processedQuestions: z6.number().int().min(0),
8548
8620
  failedInteractions: z6.number().int().min(0),
8549
- noGrowthConfirmations: z6.number().int().min(0)
8621
+ noGrowthConfirmations: z6.number().int().min(0),
8622
+ visibleControls: z6.number().int().min(0),
8623
+ eligibleControls: z6.number().int().min(0),
8624
+ dispatchedInteractions: z6.number().int().min(0),
8625
+ confirmedInteractions: z6.number().int().min(0),
8626
+ unconfirmedInteractions: z6.number().int().min(0)
8550
8627
  }).nullable();
8628
+ var PaaInteractionSummaryOutput = z6.object({
8629
+ observations: z6.number().int().min(0),
8630
+ dispatched: z6.number().int().min(0),
8631
+ confirmed: z6.number().int().min(0),
8632
+ unconfirmed: z6.number().int().min(0),
8633
+ dispatchFailures: z6.number().int().min(0),
8634
+ confirmedWithoutDispatchAck: z6.number().int().min(0),
8635
+ expandedSignals: z6.number().int().min(0),
8636
+ answerSignals: z6.number().int().min(0),
8637
+ sourceSignals: z6.number().int().min(0),
8638
+ questionGrowthBatches: z6.number().int().min(0),
8639
+ checkpoint700ms: z6.number().int().min(0),
8640
+ checkpoint1000ms: z6.number().int().min(0),
8641
+ checkpoint1400ms: z6.number().int().min(0)
8642
+ });
8643
+ var PaaInteractionOutput = z6.object({
8644
+ id: z6.string(),
8645
+ questionId: z6.string(),
8646
+ question: z6.string(),
8647
+ batchNumber: z6.number().int().min(0),
8648
+ controlAttempt: z6.number().int().min(0),
8649
+ observedAt: NullableString,
8650
+ dispatched: z6.boolean(),
8651
+ outcome: z6.enum(["confirmed", "unconfirmed", "dispatch_failed"]),
8652
+ confirmationSignals: z6.array(z6.enum(["expanded", "answer", "source", "question_growth"])),
8653
+ confirmationCheckpointMs: z6.union([z6.literal(700), z6.literal(1e3), z6.literal(1400)]).nullable(),
8654
+ confirmedAtMs: z6.number().int().min(0).nullable(),
8655
+ dispatchDurationMs: z6.number().int().min(0),
8656
+ totalDurationMs: z6.number().int().min(0),
8657
+ beforeQuestionCount: z6.number().int().min(0),
8658
+ afterQuestionCount: z6.number().int().min(0),
8659
+ newQuestionCount: z6.number().int().min(0),
8660
+ expandedBefore: z6.boolean(),
8661
+ expandedAfter: z6.boolean(),
8662
+ answerObserved: z6.boolean(),
8663
+ sourceCount: z6.number().int().min(0),
8664
+ errorCode: z6.enum(["click_failed", "click_ack_timeout", "control_missing", "confirmation_timeout"]).nullable()
8665
+ });
8551
8666
  var HarvestPaaOutputSchema = {
8552
8667
  query: z6.string(),
8553
8668
  location: NullableString,
@@ -8571,14 +8686,19 @@ var HarvestPaaDurableProgressOutput = z6.object({
8571
8686
  sourcedQuestions: z6.number().int().min(0),
8572
8687
  missingAnswers: z6.number().int().min(0),
8573
8688
  missingSources: z6.number().int().min(0),
8574
- lifecycle: PaaLifecycleOutput
8689
+ lifecycle: PaaLifecycleOutput,
8690
+ interactionSummary: PaaInteractionSummaryOutput,
8691
+ recentInteractions: z6.array(PaaInteractionOutput).max(20)
8575
8692
  });
8576
8693
  var HarvestPaaDurableAttemptOutput = z6.object({
8694
+ attemptId: z6.string(),
8577
8695
  attemptNumber: z6.number().int().min(1),
8696
+ status: NullableString,
8578
8697
  outcome: NullableString,
8579
8698
  questionCount: z6.number().int().min(0).nullable(),
8580
8699
  provider: NullableString,
8581
8700
  providerSessionId: NullableString,
8701
+ providerSessionObservedAt: NullableString,
8582
8702
  providerLookupStatus: NullableString,
8583
8703
  providerStatus: NullableString,
8584
8704
  providerErrorCode: NullableString,
@@ -8589,7 +8709,10 @@ var HarvestPaaDurableAttemptOutput = z6.object({
8589
8709
  providerBandwidthBytes: z6.number().int().min(0).nullable(),
8590
8710
  providerCaptcha: z6.boolean().nullable(),
8591
8711
  providerCheckedAt: NullableString,
8592
- willRetry: z6.boolean().nullable()
8712
+ willRetry: z6.boolean().nullable(),
8713
+ durationMs: z6.number().int().min(0).nullable(),
8714
+ startedAt: NullableString,
8715
+ completedAt: NullableString
8593
8716
  });
8594
8717
  var HarvestPaaDurableBillingOutput = z6.object({
8595
8718
  state: z6.enum(["held", "settled", "refund_pending", "refunded", "unknown"]),
@@ -8647,6 +8770,8 @@ var HarvestPaaDurableStateOutput = z6.discriminatedUnion("state", [
8647
8770
  ]);
8648
8771
  var HarvestPaaStartOutputSchema = {
8649
8772
  jobId: z6.string(),
8773
+ operationId: z6.string(),
8774
+ taskId: z6.string(),
8650
8775
  status: z6.object({
8651
8776
  state: z6.enum(["pending", "running"]),
8652
8777
  terminal: z6.literal(false),
@@ -8658,6 +8783,8 @@ var HarvestPaaStartOutputSchema = {
8658
8783
  };
8659
8784
  var HarvestPaaStatusOutputSchema = {
8660
8785
  jobId: z6.string(),
8786
+ operationId: z6.string(),
8787
+ taskId: z6.string(),
8661
8788
  status: HarvestPaaDurableStateOutput,
8662
8789
  replayed: z6.boolean(),
8663
8790
  progress: HarvestPaaDurableProgressOutput,
@@ -14436,7 +14563,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
14436
14563
  });
14437
14564
  server.registerTool("harvest_paa_status", {
14438
14565
  title: "Check Durable Google PAA Harvest",
14439
- description: "Poll an owner-scoped harvest_paa_start job. Returns state, saved progress, automatic-recovery count, target status, discovery status, material completeness, attempts, terminal rows, and billing. frontier_exhausted means every observed eligible PAA control was processed plus three healthy no-growth confirmations; interruption never means exhaustion. Polling never starts or bills another run.",
14566
+ description: "Poll an owner-scoped harvest_paa_start job. Returns the job/operation/task correlation ID, saved progress, automatic-recovery count, target and discovery status, material completeness, recent per-control interaction outcomes with 0.7/1.0/1.4-second confirmation telemetry, provider-session-correlated attempts, terminal rows, and billing. frontier_exhausted means every observed eligible PAA control was processed plus three healthy no-growth confirmations; interruption never means exhaustion. Polling never starts or bills another run.",
14440
14567
  inputSchema: HarvestPaaStatusInputSchema,
14441
14568
  outputSchema: recordOutputSchema("harvest_paa_status", HarvestPaaStatusOutputSchema),
14442
14569
  annotations: { ...liveWebToolAnnotations("Check Durable Google PAA Harvest"), idempotentHint: true, openWorldHint: false }
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getDb,
3
3
  getUserByEmail
4
- } from "./chunk-OU4FV2RP.js";
4
+ } from "./chunk-YXNDOQXN.js";
5
5
 
6
6
  // src/api/session.ts
7
7
  import { createHmac, timingSafeEqual } from "crypto";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getDb
3
- } from "./chunk-OU4FV2RP.js";
3
+ } from "./chunk-YXNDOQXN.js";
4
4
 
5
5
  // src/api/lead-list-enrichment-repository.ts
6
6
  import { createHash, randomUUID } from "crypto";
@@ -8,7 +8,7 @@ import {
8
8
  import {
9
9
  buildPublicErrorEnvelope,
10
10
  getDb
11
- } from "./chunk-OU4FV2RP.js";
11
+ } from "./chunk-YXNDOQXN.js";
12
12
 
13
13
  // src/lib/media-extractor.ts
14
14
  import { createWriteStream, mkdirSync, rmSync } from "fs";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getSessionSecret,
3
3
  serviceConnectionAdvertisesAction
4
- } from "./chunk-Q5L2OCOQ.js";
4
+ } from "./chunk-C5Z4OFKW.js";
5
5
 
6
6
  // src/api/analytics-repository.ts
7
7
  import { createHash as createHash2, createHmac as createHmac2, randomBytes as randomBytes2, randomUUID as randomUUID2 } from "crypto";
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var PACKAGE_VERSION = "0.79.1";
2
+ var PACKAGE_VERSION = "0.79.3";
3
3
 
4
4
  export {
5
5
  PACKAGE_VERSION
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-RJ7JVYKU.js";
4
4
  import {
5
5
  getDb
6
- } from "./chunk-OU4FV2RP.js";
6
+ } from "./chunk-YXNDOQXN.js";
7
7
 
8
8
  // src/api/location-data-repository.ts
9
9
  import { createHash, randomUUID } from "crypto";