opendevbrowser 0.0.21 → 0.0.23

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 (54) hide show
  1. package/README.md +13 -3
  2. package/dist/{chunk-4KVXCXV3.js → chunk-2MG7BRPF.js} +521 -84
  3. package/dist/{chunk-4KVXCXV3.js.map → chunk-2MG7BRPF.js.map} +1 -1
  4. package/dist/chunk-3ILXPKSJ.js +86 -0
  5. package/dist/chunk-3ILXPKSJ.js.map +1 -0
  6. package/dist/{chunk-ZE2E7ZGH.js → chunk-K2TEHJCV.js} +240 -33
  7. package/dist/chunk-K2TEHJCV.js.map +1 -0
  8. package/dist/chunk-QVWOPIZJ.js +612 -0
  9. package/dist/chunk-QVWOPIZJ.js.map +1 -0
  10. package/dist/{chunk-3VA6XR25.js → chunk-STGGGVYT.js} +23 -100
  11. package/dist/chunk-STGGGVYT.js.map +1 -0
  12. package/dist/cli/commands/macro-resolve.d.ts.map +1 -1
  13. package/dist/cli/commands/uninstall.d.ts +1 -0
  14. package/dist/cli/commands/uninstall.d.ts.map +1 -1
  15. package/dist/cli/daemon-commands.d.ts.map +1 -1
  16. package/dist/cli/help.d.ts.map +1 -1
  17. package/dist/cli/index.js +298 -618
  18. package/dist/cli/index.js.map +1 -1
  19. package/dist/cli/installers/postinstall-skill-sync.d.ts +15 -0
  20. package/dist/cli/installers/postinstall-skill-sync.d.ts.map +1 -0
  21. package/dist/cli/installers/postinstall-skill-sync.js +48 -0
  22. package/dist/cli/installers/postinstall-skill-sync.js.map +1 -0
  23. package/dist/cli/installers/skills.d.ts +9 -14
  24. package/dist/cli/installers/skills.d.ts.map +1 -1
  25. package/dist/cli/skill-lifecycle.d.ts +26 -0
  26. package/dist/cli/skill-lifecycle.d.ts.map +1 -0
  27. package/dist/cli/update-skill-modes.d.ts +3 -0
  28. package/dist/cli/update-skill-modes.d.ts.map +1 -0
  29. package/dist/cli/utils/workflow-message.d.ts +1 -0
  30. package/dist/cli/utils/workflow-message.d.ts.map +1 -1
  31. package/dist/index.js +25 -9
  32. package/dist/index.js.map +1 -1
  33. package/dist/opendevbrowser.js +25 -9
  34. package/dist/opendevbrowser.js.map +1 -1
  35. package/dist/providers/social/platform.d.ts.map +1 -1
  36. package/dist/providers/social/search-quality.d.ts.map +1 -1
  37. package/dist/providers/social/youtube.d.ts.map +1 -1
  38. package/dist/providers/workflow-handoff.d.ts +27 -3
  39. package/dist/providers/workflow-handoff.d.ts.map +1 -1
  40. package/dist/providers/workflows.d.ts +1 -0
  41. package/dist/providers/workflows.d.ts.map +1 -1
  42. package/dist/{providers-ZIVHHH4F.js → providers-6YVHKTOJ.js} +2 -2
  43. package/dist/public-surface/generated-manifest.d.ts +162 -4
  44. package/dist/public-surface/generated-manifest.d.ts.map +1 -1
  45. package/dist/public-surface/source.d.ts +12 -6
  46. package/dist/public-surface/source.d.ts.map +1 -1
  47. package/dist/skills/skill-loader.js +2 -1
  48. package/dist/tools/macro_resolve.d.ts.map +1 -1
  49. package/extension/manifest.json +1 -1
  50. package/package.json +6 -4
  51. package/scripts/postinstall-sync-skills.mjs +33 -0
  52. package/dist/chunk-3VA6XR25.js.map +0 -1
  53. package/dist/chunk-ZE2E7ZGH.js.map +0 -1
  54. /package/dist/{providers-ZIVHHH4F.js.map → providers-6YVHKTOJ.js.map} +0 -0
@@ -0,0 +1,86 @@
1
+ // src/utils/package-assets.ts
2
+ import * as fs from "fs";
3
+ import * as path from "path";
4
+ import { fileURLToPath } from "url";
5
+ var PACKAGE_NAME = "opendevbrowser";
6
+ var SKILLS_DIR_NAME = "skills";
7
+ var cachedPackageRoot = null;
8
+ function findPackageRoot(startDir) {
9
+ let current = startDir;
10
+ while (true) {
11
+ const pkgPath = path.join(current, "package.json");
12
+ if (fs.existsSync(pkgPath)) {
13
+ try {
14
+ const parsed = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
15
+ if (parsed.name === PACKAGE_NAME) {
16
+ return current;
17
+ }
18
+ } catch {
19
+ }
20
+ }
21
+ const parent = path.dirname(current);
22
+ if (parent === current) {
23
+ break;
24
+ }
25
+ current = parent;
26
+ }
27
+ return null;
28
+ }
29
+ function getPackageRoot() {
30
+ if (cachedPackageRoot) {
31
+ return cachedPackageRoot;
32
+ }
33
+ const moduleDir = path.dirname(fileURLToPath(import.meta.url));
34
+ const packageRoot = findPackageRoot(moduleDir);
35
+ if (!packageRoot) {
36
+ throw new Error(`Unable to locate ${PACKAGE_NAME} package root.`);
37
+ }
38
+ cachedPackageRoot = packageRoot;
39
+ return cachedPackageRoot;
40
+ }
41
+ function findBundledSkillsDir() {
42
+ try {
43
+ const skillsDir = path.join(getPackageRoot(), SKILLS_DIR_NAME);
44
+ return fs.existsSync(skillsDir) ? skillsDir : null;
45
+ } catch {
46
+ return null;
47
+ }
48
+ }
49
+ function getBundledSkillsDir() {
50
+ const skillsDir = findBundledSkillsDir();
51
+ if (!skillsDir) {
52
+ throw new Error(`Bundled skills directory not found in ${PACKAGE_NAME} package.`);
53
+ }
54
+ return skillsDir;
55
+ }
56
+
57
+ // src/skills/bundled-skill-directories.ts
58
+ var bundledSkillDirectories = [
59
+ { name: "opendevbrowser-best-practices" },
60
+ { name: "opendevbrowser-continuity-ledger" },
61
+ { name: "opendevbrowser-data-extraction" },
62
+ { name: "opendevbrowser-design-agent" },
63
+ { name: "opendevbrowser-form-testing" },
64
+ { name: "opendevbrowser-login-automation" },
65
+ { name: "opendevbrowser-product-presentation-asset" },
66
+ { name: "opendevbrowser-research" },
67
+ { name: "opendevbrowser-shopping" }
68
+ ];
69
+ var bundledSkillDirectoryByName = new Map(
70
+ bundledSkillDirectories.map((entry) => [entry.name, entry])
71
+ );
72
+ function listBundledSkillDirectories() {
73
+ return [...bundledSkillDirectories];
74
+ }
75
+ function isBundledSkillName(name) {
76
+ return bundledSkillDirectoryByName.has(name);
77
+ }
78
+
79
+ export {
80
+ getPackageRoot,
81
+ findBundledSkillsDir,
82
+ getBundledSkillsDir,
83
+ listBundledSkillDirectories,
84
+ isBundledSkillName
85
+ };
86
+ //# sourceMappingURL=chunk-3ILXPKSJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/package-assets.ts","../src/skills/bundled-skill-directories.ts"],"sourcesContent":["import * as fs from \"fs\";\nimport * as path from \"path\";\nimport { fileURLToPath } from \"url\";\n\nconst PACKAGE_NAME = \"opendevbrowser\";\nconst SKILLS_DIR_NAME = \"skills\";\n\nlet cachedPackageRoot: string | null = null;\n\nfunction findPackageRoot(startDir: string): string | null {\n let current = startDir;\n\n while (true) {\n const pkgPath = path.join(current, \"package.json\");\n if (fs.existsSync(pkgPath)) {\n try {\n const parsed = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\")) as { name?: string };\n if (parsed.name === PACKAGE_NAME) {\n return current;\n }\n } catch {\n void 0;\n }\n }\n\n const parent = path.dirname(current);\n if (parent === current) {\n break;\n }\n current = parent;\n }\n\n return null;\n}\n\nexport function getPackageRoot(): string {\n if (cachedPackageRoot) {\n return cachedPackageRoot;\n }\n const moduleDir = path.dirname(fileURLToPath(import.meta.url));\n const packageRoot = findPackageRoot(moduleDir);\n if (!packageRoot) {\n throw new Error(`Unable to locate ${PACKAGE_NAME} package root.`);\n }\n cachedPackageRoot = packageRoot;\n return cachedPackageRoot;\n}\n\nexport function findBundledSkillsDir(): string | null {\n try {\n const skillsDir = path.join(getPackageRoot(), SKILLS_DIR_NAME);\n return fs.existsSync(skillsDir) ? skillsDir : null;\n } catch {\n return null;\n }\n}\n\nexport function getBundledSkillsDir(): string {\n const skillsDir = findBundledSkillsDir();\n if (!skillsDir) {\n throw new Error(`Bundled skills directory not found in ${PACKAGE_NAME} package.`);\n }\n return skillsDir;\n}\n","export interface BundledSkillDirectory {\n name: string;\n}\n\nexport const bundledSkillDirectories: BundledSkillDirectory[] = [\n { name: \"opendevbrowser-best-practices\" },\n { name: \"opendevbrowser-continuity-ledger\" },\n { name: \"opendevbrowser-data-extraction\" },\n { name: \"opendevbrowser-design-agent\" },\n { name: \"opendevbrowser-form-testing\" },\n { name: \"opendevbrowser-login-automation\" },\n { name: \"opendevbrowser-product-presentation-asset\" },\n { name: \"opendevbrowser-research\" },\n { name: \"opendevbrowser-shopping\" }\n];\n\nconst bundledSkillDirectoryByName = new Map(\n bundledSkillDirectories.map((entry) => [entry.name, entry] as const)\n);\n\nexport function listBundledSkillDirectories(): BundledSkillDirectory[] {\n return [...bundledSkillDirectories];\n}\n\nexport function getBundledSkillDirectory(name: string): BundledSkillDirectory | null {\n return bundledSkillDirectoryByName.get(name) ?? null;\n}\n\nexport function isBundledSkillName(name: string): boolean {\n return bundledSkillDirectoryByName.has(name);\n}\n"],"mappings":";AAAA,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB,SAAS,qBAAqB;AAE9B,IAAM,eAAe;AACrB,IAAM,kBAAkB;AAExB,IAAI,oBAAmC;AAEvC,SAAS,gBAAgB,UAAiC;AACxD,MAAI,UAAU;AAEd,SAAO,MAAM;AACX,UAAM,UAAe,UAAK,SAAS,cAAc;AACjD,QAAO,cAAW,OAAO,GAAG;AAC1B,UAAI;AACF,cAAM,SAAS,KAAK,MAAS,gBAAa,SAAS,OAAO,CAAC;AAC3D,YAAI,OAAO,SAAS,cAAc;AAChC,iBAAO;AAAA,QACT;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,UAAM,SAAc,aAAQ,OAAO;AACnC,QAAI,WAAW,SAAS;AACtB;AAAA,IACF;AACA,cAAU;AAAA,EACZ;AAEA,SAAO;AACT;AAEO,SAAS,iBAAyB;AACvC,MAAI,mBAAmB;AACrB,WAAO;AAAA,EACT;AACA,QAAM,YAAiB,aAAQ,cAAc,YAAY,GAAG,CAAC;AAC7D,QAAM,cAAc,gBAAgB,SAAS;AAC7C,MAAI,CAAC,aAAa;AAChB,UAAM,IAAI,MAAM,oBAAoB,YAAY,gBAAgB;AAAA,EAClE;AACA,sBAAoB;AACpB,SAAO;AACT;AAEO,SAAS,uBAAsC;AACpD,MAAI;AACF,UAAM,YAAiB,UAAK,eAAe,GAAG,eAAe;AAC7D,WAAU,cAAW,SAAS,IAAI,YAAY;AAAA,EAChD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,sBAA8B;AAC5C,QAAM,YAAY,qBAAqB;AACvC,MAAI,CAAC,WAAW;AACd,UAAM,IAAI,MAAM,yCAAyC,YAAY,WAAW;AAAA,EAClF;AACA,SAAO;AACT;;;AC3DO,IAAM,0BAAmD;AAAA,EAC9D,EAAE,MAAM,gCAAgC;AAAA,EACxC,EAAE,MAAM,mCAAmC;AAAA,EAC3C,EAAE,MAAM,iCAAiC;AAAA,EACzC,EAAE,MAAM,8BAA8B;AAAA,EACtC,EAAE,MAAM,8BAA8B;AAAA,EACtC,EAAE,MAAM,kCAAkC;AAAA,EAC1C,EAAE,MAAM,4CAA4C;AAAA,EACpD,EAAE,MAAM,0BAA0B;AAAA,EAClC,EAAE,MAAM,0BAA0B;AACpC;AAEA,IAAM,8BAA8B,IAAI;AAAA,EACtC,wBAAwB,IAAI,CAAC,UAAU,CAAC,MAAM,MAAM,KAAK,CAAU;AACrE;AAEO,SAAS,8BAAuD;AACrE,SAAO,CAAC,GAAG,uBAAuB;AACpC;AAMO,SAAS,mBAAmB,MAAuB;AACxD,SAAO,4BAA4B,IAAI,IAAI;AAC7C;","names":[]}
@@ -5428,11 +5428,17 @@ var createCommunityProvider = (options = {}) => {
5428
5428
  };
5429
5429
 
5430
5430
  // src/providers/social/search-quality.ts
5431
- var TARGETED_PLATFORMS = /* @__PURE__ */ new Set(["x", "bluesky", "reddit"]);
5431
+ var TARGETED_PLATFORMS = /* @__PURE__ */ new Set(["x", "bluesky", "reddit", "facebook"]);
5432
5432
  var SOCIAL_JS_REQUIRED_RE = /\b(?:javascript (?:is not available|required|is disabled(?: in this browser)?)|you need to enable javascript|please enable javascript)\b/i;
5433
5433
  var BLUESKY_LOGGED_OUT_SEARCH_RE = /\bsearch is currently unavailable when logged out\b/i;
5434
5434
  var BLUESKY_EMPTY_SEARCH_SHELL_RE = /\b(?:follow 10 people to get started|find people to follow)\b/i;
5435
5435
  var REDDIT_VERIFICATION_WALL_RE = /\b(?:please wait for verification|verify (?:you(?:'re| are) human|that you(?:'re| are) human)|security check)\b/i;
5436
+ var FACEBOOK_SEARCH_RESULTS_HEADING_RE = /\bsearch results\b/i;
5437
+ var FACEBOOK_SEARCH_RESULT_MARKERS = [
5438
+ /\bshared with public\b/i,
5439
+ /\bopen reel in reels viewer\b/i,
5440
+ /\bcomment as\b/i
5441
+ ];
5436
5442
  var REDDIT_BLOCKED_EXPANSION_HOSTS = ["accounts.google.com", "ads.reddit.com"];
5437
5443
  var REDDIT_BLOCKED_FIRST_SEGMENTS = /* @__PURE__ */ new Set(["account", "ads", "notifications", "submit", "verification"]);
5438
5444
  var FIRST_PARTY_HELP_HOSTS = {
@@ -5486,6 +5492,27 @@ var isPrimaryRedditHost = (host) => {
5486
5492
  const normalized = host.toLowerCase();
5487
5493
  return normalized === "www.reddit.com" || normalized === "reddit.com" || normalized === "old.reddit.com";
5488
5494
  };
5495
+ var isPrimaryFacebookHost = (host) => {
5496
+ const normalized = host.toLowerCase();
5497
+ return normalized === "www.facebook.com" || normalized === "facebook.com" || normalized === "m.facebook.com";
5498
+ };
5499
+ var isFacebookSearchLikePath = (pathname) => pathname === "/watch/search" || pathname === "/watch/search/" || pathname.startsWith("/watch/explore/") || pathname.startsWith("/search/") || pathname.startsWith("/public/") || pathname.startsWith("/hashtag/");
5500
+ var isBlockedFacebookNonContentUrl = (parsed, options) => {
5501
+ if (!isPrimaryFacebookHost(parsed.hostname)) {
5502
+ return false;
5503
+ }
5504
+ const pathname = parsed.pathname.toLowerCase();
5505
+ if (pathname === "/" || pathname === "/login" || pathname === "/login/" || pathname === "/reg" || pathname === "/reg/" || pathname.startsWith("/recover/")) {
5506
+ return true;
5507
+ }
5508
+ if ((pathname === "/watch" || pathname === "/watch/") && !parsed.searchParams.get("v")) {
5509
+ return true;
5510
+ }
5511
+ if (isStaticMetadataPath(pathname)) {
5512
+ return true;
5513
+ }
5514
+ return options.includeSearchRoute && isFacebookSearchLikePath(pathname);
5515
+ };
5489
5516
  var isBlockedRedditNonContentUrl = (parsed, options) => {
5490
5517
  const host = parsed.hostname.toLowerCase();
5491
5518
  if (matchesHost(host, REDDIT_BLOCKED_EXPANSION_HOSTS)) {
@@ -5511,6 +5538,8 @@ var isRootShellUrl = (platform, parsed) => {
5511
5538
  return host === "bsky.app" && (pathname === "/" || pathname === "/login");
5512
5539
  case "reddit":
5513
5540
  return isBlockedRedditNonContentUrl(parsed, { includeSearchRoute: false });
5541
+ case "facebook":
5542
+ return isBlockedFacebookNonContentUrl(parsed, { includeSearchRoute: false });
5514
5543
  default:
5515
5544
  return false;
5516
5545
  }
@@ -5525,6 +5554,8 @@ var isBlockedExpansionPath = (platform, parsed) => {
5525
5554
  return host === "bsky.app" && (pathname === "/" || pathname === "/login" || pathname === "/search" || isStaticMetadataPath(pathname) || /^\/profile\/[^/]+\/feed\/[^/]+$/.test(pathname));
5526
5555
  case "reddit":
5527
5556
  return isBlockedRedditNonContentUrl(parsed, { includeSearchRoute: true });
5557
+ case "facebook":
5558
+ return isBlockedFacebookNonContentUrl(parsed, { includeSearchRoute: true });
5528
5559
  default:
5529
5560
  return false;
5530
5561
  }
@@ -5539,6 +5570,8 @@ var isFirstPartySearchRoute = (platform, parsed) => {
5539
5570
  return host === "bsky.app" && pathname === "/search";
5540
5571
  case "reddit":
5541
5572
  return isPrimaryRedditHost(host) && pathname === "/search";
5573
+ case "facebook":
5574
+ return isPrimaryFacebookHost(host) && isFacebookSearchLikePath(pathname);
5542
5575
  default:
5543
5576
  return false;
5544
5577
  }
@@ -5604,6 +5637,51 @@ var isUsableRedditSearchEvidenceUrl = (url) => {
5604
5637
  const parsed = parseUrl(url);
5605
5638
  return parsed !== null && isPrimaryRedditHost(parsed.hostname) && /^\/r\/[^/]+\/comments\/[^/]+(?:\/|$)/.test(parsed.pathname.toLowerCase());
5606
5639
  };
5640
+ var isUsableFacebookSearchEvidenceUrl = (url) => {
5641
+ const parsed = parseUrl(url);
5642
+ if (parsed === null || !isPrimaryFacebookHost(parsed.hostname)) {
5643
+ return false;
5644
+ }
5645
+ const pathname = parsed.pathname.toLowerCase();
5646
+ if ((pathname === "/watch" || pathname === "/watch/") && parsed.searchParams.get("v")) {
5647
+ return true;
5648
+ }
5649
+ return /^\/reel\/[^/]+\/?$/.test(pathname) || /^\/groups\/[^/]+\/posts\/[^/]+\/?$/.test(pathname) || /^\/[^/]+\/videos\/[^/]+\/?$/.test(pathname) || /^\/share\/v\/[^/]+\/?$/.test(pathname) || (pathname === "/permalink.php" || pathname === "/story.php") && parsed.searchParams.has("story_fbid") || pathname === "/photo/" && parsed.searchParams.has("fbid");
5650
+ };
5651
+ var isRetainableFacebookSearchSupportUrl = (url) => {
5652
+ const parsed = parseUrl(url);
5653
+ if (parsed === null || !isPrimaryFacebookHost(parsed.hostname)) {
5654
+ return false;
5655
+ }
5656
+ if (isBlockedFacebookNonContentUrl(parsed, { includeSearchRoute: true })) {
5657
+ return false;
5658
+ }
5659
+ if (isFirstPartySearchRoute("facebook", parsed)) {
5660
+ return false;
5661
+ }
5662
+ return !isUsableFacebookSearchEvidenceUrl(url);
5663
+ };
5664
+ var hasFacebookSearchResultSignals = (input) => {
5665
+ const parsed = parseUrl(input.url);
5666
+ if (parsed === null || !isFirstPartySearchRoute("facebook", parsed)) {
5667
+ return false;
5668
+ }
5669
+ const combined = `${normalizeText2(input.title)} ${normalizeText2(input.content)}`.trim();
5670
+ const hasSearchHeading = FACEBOOK_SEARCH_RESULTS_HEADING_RE.test(combined);
5671
+ const markerCount = FACEBOOK_SEARCH_RESULT_MARKERS.filter((pattern) => pattern.test(combined)).length;
5672
+ const evidence = collectSocialSearchLinkEvidence("facebook", parsed.toString(), Array.isArray(input.links) ? input.links : []);
5673
+ const supportLinkCount = evidence.usableLinks.filter(isRetainableFacebookSearchSupportUrl).length;
5674
+ if (markerCount >= 2) {
5675
+ return true;
5676
+ }
5677
+ if (!hasSearchHeading) {
5678
+ return false;
5679
+ }
5680
+ if (markerCount >= 1) {
5681
+ return true;
5682
+ }
5683
+ return supportLinkCount >= 2;
5684
+ };
5607
5685
  var isUsableSocialSearchContentUrl = (platform, url) => {
5608
5686
  switch (platform) {
5609
5687
  case "x":
@@ -5612,6 +5690,8 @@ var isUsableSocialSearchContentUrl = (platform, url) => {
5612
5690
  return isUsableBlueskySearchEvidenceUrl(url);
5613
5691
  case "reddit":
5614
5692
  return isUsableRedditSearchEvidenceUrl(url);
5693
+ case "facebook":
5694
+ return isUsableFacebookSearchEvidenceUrl(url);
5615
5695
  default:
5616
5696
  return false;
5617
5697
  }
@@ -5664,6 +5744,9 @@ var detectSocialSearchShell = (platform, input) => {
5664
5744
  browserRequired: true
5665
5745
  };
5666
5746
  }
5747
+ if (parsed && isFirstPartySearchRoute(platform, parsed) && platform === "facebook" && hasFacebookSearchResultSignals(input)) {
5748
+ return null;
5749
+ }
5667
5750
  if (parsed && isFirstPartySearchRoute(platform, parsed) && !hasUsableFirstPartySearchEvidence(platform, parsed, links)) {
5668
5751
  return {
5669
5752
  providerShell: "social_render_shell",
@@ -5811,6 +5894,9 @@ var pickCarryForwardSocialSearchAttributes = (attributes) => {
5811
5894
  }, {});
5812
5895
  return Object.keys(carried).length > 0 ? carried : void 0;
5813
5896
  };
5897
+ var hasBrowserFallbackMode = (attributes) => typeof attributes?.browser_fallback_mode === "string" && attributes.browser_fallback_mode.length > 0;
5898
+ var hasVisibleSearchContent = (row) => typeof row.title === "string" && row.title.trim().length > 0 || typeof row.content === "string" && row.content.trim().length > 0;
5899
+ var shouldKeepRecoveredFacebookSearchRow = (platform, row) => platform === "facebook" && hasBrowserFallbackMode(row.attributes) && hasVisibleSearchContent(row);
5814
5900
  var extractLinks3 = (platform, row, fallbackUrl) => {
5815
5901
  const attributeLinks = [
5816
5902
  ...coerceStringArray2(row.attributes?.links),
@@ -5929,7 +6015,8 @@ var createSocialPlatformProvider = (profile, options = {}) => {
5929
6015
  if (!isHttpUrl3(canonical) || seen.has(canonical)) continue;
5930
6016
  seen.add(canonical);
5931
6017
  const links = extractLinks3(profile.platform, row, canonical).slice(0, traversal.expansionPerRecord);
5932
- const keepRow = !isFirstPartySocialSearchRoute(profile.platform, canonical);
6018
+ const keepFirstPartySearchRow = shouldKeepRecoveredFacebookSearchRow(profile.platform, row) || profile.platform === "facebook" && links.length === 0;
6019
+ const keepRow = !isFirstPartySocialSearchRoute(profile.platform, canonical) || keepFirstPartySearchRow;
5933
6020
  const carryForwardAttributes = keepRow ? void 0 : pickCarryForwardSocialSearchAttributes(row.attributes);
5934
6021
  if (keepRow) {
5935
6022
  rows.push({
@@ -7684,23 +7771,28 @@ var createYouTubeProvider = (options = {}) => {
7684
7771
  supportsThreads: false
7685
7772
  }, options);
7686
7773
  };
7687
- var withDefaultYouTubeOptions = (options = {}) => ({
7688
- ...options,
7689
- recoveryHints: options.recoveryHints ?? (() => ({
7690
- preferredFallbackModes: ["managed_headed"],
7691
- challengeProne: true,
7692
- settleTimeoutMs: 5e3,
7693
- captureDelayMs: 500
7694
- })),
7695
- defaultTraversal: {
7696
- pageLimit: options.defaultTraversal?.pageLimit ?? 1,
7697
- hopLimit: options.defaultTraversal?.hopLimit ?? 0,
7698
- expansionPerRecord: options.defaultTraversal?.expansionPerRecord ?? 1,
7699
- maxRecords: options.defaultTraversal?.maxRecords ?? 8
7700
- },
7701
- search: buildSearch(options.search),
7702
- fetch: buildFetch(options)
7703
- });
7774
+ var withDefaultYouTubeOptions = (options = {}) => {
7775
+ const resolvedOptions = {
7776
+ ...options,
7777
+ recoveryHints: options.recoveryHints ?? (() => ({
7778
+ preferredFallbackModes: ["extension", "managed_headed"],
7779
+ challengeProne: true,
7780
+ settleTimeoutMs: 5e3,
7781
+ captureDelayMs: 500
7782
+ })),
7783
+ defaultTraversal: {
7784
+ pageLimit: options.defaultTraversal?.pageLimit ?? 1,
7785
+ hopLimit: options.defaultTraversal?.hopLimit ?? 0,
7786
+ expansionPerRecord: options.defaultTraversal?.expansionPerRecord ?? 1,
7787
+ maxRecords: options.defaultTraversal?.maxRecords ?? 8
7788
+ }
7789
+ };
7790
+ return {
7791
+ ...resolvedOptions,
7792
+ search: buildSearch(resolvedOptions.search),
7793
+ fetch: buildFetch(resolvedOptions)
7794
+ };
7795
+ };
7704
7796
 
7705
7797
  // src/providers/social/index.ts
7706
7798
  var createSocialProviders = (options = {}) => {
@@ -11252,27 +11344,76 @@ var createSuccessHandoff = (followthroughSummary, suggestedNextAction, suggested
11252
11344
  suggestedNextAction,
11253
11345
  suggestedSteps
11254
11346
  });
11255
- var buildResearchSuccessHandoff = () => {
11347
+ var cliExample = (command, args = "") => `npx opendevbrowser ${command}${args ? ` ${args}` : ""}`;
11348
+ var quoteCliValue = (value) => JSON.stringify(value);
11349
+ var buildResearchRerunCommand = (topic) => cliExample(
11350
+ "research run",
11351
+ `--topic ${quoteCliValue(topic)} --days 14 --source-selection auto --sources web,community --mode json --output-format json`
11352
+ );
11353
+ var buildShoppingRerunCommand = (input) => {
11354
+ const providers = input.providers?.length ? ` --providers ${input.providers.join(",")}` : " --providers shopping/bestbuy,shopping/ebay";
11355
+ const budget = typeof input.budget === "number" ? ` --budget ${input.budget}` : "";
11356
+ const region = input.region ? ` --region ${quoteCliValue(input.region)}` : "";
11357
+ const browserMode = ` --browser-mode ${input.browserMode ?? "managed"}`;
11358
+ const sort = input.sort ? ` --sort ${input.sort}` : "";
11359
+ return cliExample(
11360
+ "shopping run",
11361
+ `--query ${quoteCliValue(input.query)}${providers}${budget}${region}${browserMode}${sort} --mode json --output-format json`
11362
+ );
11363
+ };
11364
+ var buildProductVideoRerunCommand = (input = {}) => {
11365
+ const target = input.productUrl ? `--product-url ${quoteCliValue(input.productUrl)}` : `--product-name ${quoteCliValue(input.productName ?? "<product-name>")}`;
11366
+ const providerHint = input.providerHint ? ` --provider-hint ${input.providerHint}` : "";
11367
+ const screenshots = input.includeScreenshots ? " --include-screenshots" : "";
11368
+ const allImages = input.includeAllImages ? " --include-all-images" : "";
11369
+ const includeCopy = input.includeCopy ? " --include-copy" : "";
11370
+ return cliExample(
11371
+ "product-video run",
11372
+ `${target}${providerHint}${screenshots}${allImages}${includeCopy} --output-format json`
11373
+ );
11374
+ };
11375
+ var buildMacroResolveArgs = (input, options) => {
11376
+ const defaultProvider = input.defaultProvider ? ` --default-provider ${input.defaultProvider}` : "";
11377
+ const execute = options?.execute ? " --execute" : "";
11378
+ const challenge = options?.challengeAutomationMode ? ` --challenge-automation-mode ${options.challengeAutomationMode}` : "";
11379
+ const outputFormat = options?.includeOutputFormat === false ? "" : " --output-format json";
11380
+ return `--expression ${quoteCliValue(input.expression)}${defaultProvider}${execute}${challenge}${outputFormat}`;
11381
+ };
11382
+ var buildMacroPreviewCommand = (input) => cliExample("macro-resolve", buildMacroResolveArgs(input));
11383
+ var buildMacroExecuteCommand = (input, challengeAutomationMode) => cliExample("macro-resolve", buildMacroResolveArgs(input, {
11384
+ execute: true,
11385
+ challengeAutomationMode
11386
+ }));
11387
+ var buildResearchSuccessHandoff = (topic) => {
11388
+ const rerunCommand = buildResearchRerunCommand(topic);
11256
11389
  return createSuccessHandoff(
11257
11390
  "Review the ranked records and artifact bundle before turning the result into a publishable claim.",
11258
- "Open the returned artifact path, inspect the supporting records, and rerun with explicit --sources or a tighter timebox if you need stronger evidence.",
11391
+ `Open the returned artifact path, inspect the supporting records, and rerun ${rerunCommand} if you need a tighter evidence set.`,
11259
11392
  [
11260
11393
  { reason: "Check which records actually support the final claim." },
11261
- { reason: "Rerun with explicit sources or a narrower timebox if the evidence set is still too broad." }
11394
+ {
11395
+ reason: "Rerun with explicit sources and a narrower timebox if the evidence set is still too broad.",
11396
+ command: rerunCommand
11397
+ }
11262
11398
  ]
11263
11399
  );
11264
11400
  };
11265
- var buildShoppingSuccessHandoff = () => {
11401
+ var buildShoppingSuccessHandoff = (input) => {
11402
+ const rerunCommand = buildShoppingRerunCommand(input);
11266
11403
  return createSuccessHandoff(
11267
11404
  "Review the offer set and diagnostics before calling any result a strong deal.",
11268
- "Inspect the offers and meta.offerFilterDiagnostics, then rerun with explicit providers or budget and region adjustments if you need a tighter comparison.",
11405
+ `Inspect the offers and meta.offerFilterDiagnostics, then rerun ${rerunCommand} if you need a tighter comparison.`,
11269
11406
  [
11270
11407
  { reason: "Check which offers survived the workflow filters and why." },
11271
- { reason: "Rerun with explicit providers or updated budget and region inputs if the comparison is still noisy." }
11408
+ {
11409
+ reason: "Rerun with explicit providers or updated budget and region inputs if the comparison is still noisy.",
11410
+ command: rerunCommand
11411
+ }
11272
11412
  ]
11273
11413
  );
11274
11414
  };
11275
- var buildProductVideoSuccessHandoff = () => {
11415
+ var buildProductVideoSuccessHandoff = (input = {}) => {
11416
+ const rerunCommand = buildProductVideoRerunCommand(input);
11276
11417
  return createSuccessHandoff(
11277
11418
  "Review the generated asset pack to confirm whether it is visual-ready or metadata-first before briefing production.",
11278
11419
  `Open the returned pack path, inspect manifest.json plus copy and features, then run ${PRODUCT_VIDEO_BRIEF_HELPER_COMMAND} to generate production briefs and sourcing notes.`,
@@ -11282,10 +11423,50 @@ var buildProductVideoSuccessHandoff = () => {
11282
11423
  reason: "Run the product-presentation-asset brief helper on manifest.json to generate the production brief files.",
11283
11424
  command: PRODUCT_VIDEO_BRIEF_HELPER_COMMAND
11284
11425
  },
11426
+ {
11427
+ reason: "Rerun the asset workflow with adjusted provider or media flags when the current pack is too thin.",
11428
+ command: rerunCommand
11429
+ },
11285
11430
  { reason: "Source or capture visuals before final handoff if the pack is metadata-first." }
11286
11431
  ]
11287
11432
  );
11288
11433
  };
11434
+ var buildMacroResolveSuccessHandoff = (input) => {
11435
+ const previewCommand = buildMacroPreviewCommand(input);
11436
+ const executeCommand = buildMacroExecuteCommand(input);
11437
+ const browserRetryCommand = buildMacroExecuteCommand(input, "browser");
11438
+ if (!input.execute) {
11439
+ return createSuccessHandoff(
11440
+ "Review the resolved provider action and provenance before executing the macro.",
11441
+ `Run ${executeCommand} when the resolved action looks correct.`,
11442
+ [
11443
+ { reason: "Inspect resolution.action and resolution.provenance to confirm provider and query shaping." },
11444
+ { reason: "Execute the resolved macro once the plan looks correct.", command: executeCommand },
11445
+ { reason: "Add --default-provider only when you need to force a different provider lane.", command: previewCommand }
11446
+ ]
11447
+ );
11448
+ }
11449
+ if (input.blocked) {
11450
+ return createSuccessHandoff(
11451
+ "Review execution.meta.blocker and failures before retrying the macro.",
11452
+ `Run ${browserRetryCommand} after checking execution.meta.blocker and the current recovery path.`,
11453
+ [
11454
+ { reason: "Inspect execution.meta.blocker and execution.failures before retrying." },
11455
+ { reason: "Retry with browser-scoped challenge automation when the blocker requires live follow-up.", command: browserRetryCommand },
11456
+ { reason: "Preview the resolved action again if you need to switch providers before another execute attempt.", command: previewCommand }
11457
+ ]
11458
+ );
11459
+ }
11460
+ return createSuccessHandoff(
11461
+ "Review execution.records and trace metadata before widening the macro or changing providers.",
11462
+ `Inspect execution.records and execution.meta, then rerun ${previewCommand} if you need a narrower plan.`,
11463
+ [
11464
+ { reason: "Inspect execution.records and execution.meta to confirm the resolved action hit the expected lane." },
11465
+ { reason: "Preview the macro again before changing providers or expression scope.", command: previewCommand },
11466
+ { reason: "Re-execute with browser-scoped challenge automation when the target requires live browser recovery.", command: browserRetryCommand }
11467
+ ]
11468
+ );
11469
+ };
11289
11470
 
11290
11471
  // src/providers/shopping-postprocess.ts
11291
11472
  import { createHash as createHash4 } from "crypto";
@@ -13419,6 +13600,7 @@ var workflowTestUtils = {
13419
13600
  redactRawCapture: (record) => redactRawCapture(record),
13420
13601
  toProviderSource: (providerId) => toProviderSource2(providerId),
13421
13602
  resolveShoppingProviderIdForUrl: (url) => resolveShoppingProviderIdForUrl(url),
13603
+ normalizeProductVideoProviderHint: (productUrl, providerHint, fallbackProvider) => normalizeProductVideoProviderHint(productUrl, providerHint, fallbackProvider),
13422
13604
  hasTranscriptSuccess: (record) => hasTranscriptSuccess(record),
13423
13605
  sanitizeFeatureList: (values) => sanitizeFeatureList(values),
13424
13606
  parsePriceFromContent: (content) => parsePriceFromContent(content),
@@ -13519,6 +13701,15 @@ var resolveShoppingProviderIdForUrl = (url) => {
13519
13701
  return null;
13520
13702
  }
13521
13703
  };
13704
+ var normalizeProductVideoProviderHint = (productUrl, providerHint, fallbackProvider) => {
13705
+ if (fallbackProvider?.includes("/")) return fallbackProvider;
13706
+ if (providerHint?.includes("/")) return providerHint;
13707
+ const shoppingProviderId = resolveShoppingProviderIdForUrl(productUrl);
13708
+ if (shoppingProviderId) {
13709
+ return providerHint ? `shopping/${providerHint}` : fallbackProvider ?? shoppingProviderId;
13710
+ }
13711
+ return fallbackProvider ?? providerHint;
13712
+ };
13522
13713
  var IMAGE_ASSET_RE = /\.(?:png|jpg|jpeg|webp|gif)(?:[?#].*)?$/i;
13523
13714
  var isHttpAssetUrl = (value) => {
13524
13715
  try {
@@ -14423,7 +14614,7 @@ var runResearchWorkflow = async (runtime, input) => {
14423
14614
  failures: mergedFailures,
14424
14615
  alerts: buildWorkflowAlerts(runtime, mergedFailures)
14425
14616
  }, primaryConstraintFailures);
14426
- const handoff = buildResearchSuccessHandoff();
14617
+ const handoff = buildResearchSuccessHandoff(plan.compiled.topic);
14427
14618
  const responseMeta = withFollowthroughMeta(meta, handoff);
14428
14619
  const rendered = renderResearch({
14429
14620
  mode: workflowInput.mode,
@@ -14602,7 +14793,14 @@ var runShoppingWorkflow = async (runtime, input) => {
14602
14793
  if (typeof filterConstraintSummary === "string") {
14603
14794
  meta = withPrimaryConstraintSummaryOverride(meta, filterConstraintSummary);
14604
14795
  }
14605
- const handoff = buildShoppingSuccessHandoff();
14796
+ const handoff = buildShoppingSuccessHandoff({
14797
+ query: plan.compiled.query,
14798
+ providers: plan.compiled.providerIds,
14799
+ budget: plan.compiled.budget,
14800
+ region: workflowInput.region,
14801
+ browserMode: workflowInput.browserMode,
14802
+ sort: workflowInput.sort
14803
+ });
14606
14804
  const responseMeta = withFollowthroughMeta(meta, handoff);
14607
14805
  const rendered = renderShopping({
14608
14806
  mode: workflowInput.mode,
@@ -14966,6 +15164,7 @@ var runProductVideoWorkflow = async (runtime, input, options = {}) => {
14966
15164
  const refreshedMetadata = needsProductMetadataRefresh(primary, productUrl) ? await refreshProductMetadata(productUrl, remainingTimeoutMs()) : null;
14967
15165
  const primaryOffer = extractShoppingOffer(primary, /* @__PURE__ */ new Date());
14968
15166
  const preferredPrice = resolvePreferredProductPrice(primary, productUrl, refreshedMetadata?.price, primaryOffer);
15167
+ providerHint = normalizeProductVideoProviderHint(productUrl, providerHint, primary.provider);
14969
15168
  const resolvedBrand = resolveProductBrand(primary, productUrl, refreshedMetadata?.brand);
14970
15169
  const resolvedTitle = resolveProductTitle(primary, productUrl, resolvedBrand, refreshedMetadata?.title);
14971
15170
  const resolvedPrice = resolveProductPrice(primary, productUrl, refreshedMetadata?.price, primaryOffer);
@@ -15073,7 +15272,14 @@ var runProductVideoWorkflow = async (runtime, input, options = {}) => {
15073
15272
  const cookieDiagnostics = summarizeCookieDiagnostics(details.failures, details.records);
15074
15273
  const antiBotPressure = summarizeAntiBotPressure(details.failures);
15075
15274
  const primaryIssue = summarizePrimaryProviderIssue(details.failures);
15076
- const handoff = buildProductVideoSuccessHandoff();
15275
+ const handoff = buildProductVideoSuccessHandoff({
15276
+ productUrl,
15277
+ productName: workflowInput.product_name,
15278
+ providerHint,
15279
+ includeScreenshots: workflowInput.include_screenshots,
15280
+ includeAllImages: workflowInput.include_all_images,
15281
+ includeCopy: workflowInput.include_copy
15282
+ });
15077
15283
  const meta = withFollowthroughMeta({
15078
15284
  alerts: buildWorkflowAlerts(runtime, details.failures),
15079
15285
  failures: details.failures,
@@ -15118,11 +15324,11 @@ var WORKFLOW_KIND_BY_SUSPENDED_INTENT_KIND2 = {
15118
15324
  "workflow.inspiredesign": "inspiredesign",
15119
15325
  "workflow.product_video": "product_video"
15120
15326
  };
15121
- var EXTENSION_FIRST_SOCIAL_FALLBACK_PLATFORMS = /* @__PURE__ */ new Set(["x", "reddit", "bluesky", "linkedin"]);
15327
+ var EXTENSION_FIRST_SOCIAL_FALLBACK_PLATFORMS = /* @__PURE__ */ new Set(["x", "reddit", "bluesky", "facebook", "linkedin"]);
15122
15328
  var EXTENSION_MINIMAL_TRAVERSAL_SOCIAL_PLATFORMS = /* @__PURE__ */ new Set(["linkedin"]);
15123
15329
  var EXTENSION_FIRST_FALLBACK_MODES = ["extension", "managed_headed"];
15124
15330
  var SOCIAL_BROWSER_RECOVERY_REASON_CODES = /* @__PURE__ */ new Set(["challenge_detected"]);
15125
- var SEARCH_RENDER_RECOVERY_SOCIAL_PLATFORMS = /* @__PURE__ */ new Set(["x", "bluesky", "reddit"]);
15331
+ var SEARCH_RENDER_RECOVERY_SOCIAL_PLATFORMS = /* @__PURE__ */ new Set(["x", "bluesky", "reddit", "facebook"]);
15126
15332
  var withPrioritizedFallbackModes = (prioritized, existing) => [.../* @__PURE__ */ new Set([...prioritized, ...existing ?? []])];
15127
15333
  var buildSocialRecoveryHints = (platform, options) => {
15128
15334
  const existing = options?.recoveryHints?.();
@@ -15274,7 +15480,7 @@ var SOCIAL_SEARCH_ENDPOINTS = {
15274
15480
  x: (query, page) => `https://x.com/search?q=${encodeURIComponent(query)}&f=live&page=${page}`,
15275
15481
  reddit: (query, page) => `https://www.reddit.com/search/?q=${encodeURIComponent(query)}&sort=relevance&t=all&page=${page}`,
15276
15482
  bluesky: (query, page) => `https://bsky.app/search?q=${encodeURIComponent(query)}&page=${page}`,
15277
- facebook: (query, page) => `https://www.facebook.com/search/top?q=${encodeURIComponent(query)}&page=${page}`,
15483
+ facebook: (query, page) => `https://www.facebook.com/watch/search/?q=${encodeURIComponent(query)}&page=${page}`,
15278
15484
  linkedin: (query, page) => `https://www.linkedin.com/search/results/content/?keywords=${encodeURIComponent(query)}&page=${page}`,
15279
15485
  instagram: (query, page) => `https://www.instagram.com/explore/search/keyword/?q=${encodeURIComponent(query)}&page=${page}`,
15280
15486
  tiktok: (query, page) => `https://www.tiktok.com/search?q=${encodeURIComponent(query)}&page=${page}`,
@@ -17246,6 +17452,7 @@ export {
17246
17452
  renderResearch,
17247
17453
  renderShopping,
17248
17454
  renderInspiredesign,
17455
+ buildMacroResolveSuccessHandoff,
17249
17456
  workflowTestUtils,
17250
17457
  runResearchWorkflow,
17251
17458
  runShoppingWorkflow,
@@ -17256,4 +17463,4 @@ export {
17256
17463
  createProviderRuntime,
17257
17464
  createDefaultRuntime
17258
17465
  };
17259
- //# sourceMappingURL=chunk-ZE2E7ZGH.js.map
17466
+ //# sourceMappingURL=chunk-K2TEHJCV.js.map