@agent-native/core 0.49.9 → 0.49.11

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 (68) hide show
  1. package/dist/cli/pr-visual-recap-workflow.d.ts +1 -1
  2. package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
  3. package/dist/cli/pr-visual-recap-workflow.js +1 -1
  4. package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
  5. package/dist/cli/recap.d.ts +4 -1
  6. package/dist/cli/recap.d.ts.map +1 -1
  7. package/dist/cli/recap.js +97 -23
  8. package/dist/cli/recap.js.map +1 -1
  9. package/dist/cli/skills.d.ts +5 -5
  10. package/dist/cli/skills.d.ts.map +1 -1
  11. package/dist/cli/skills.js +219 -24
  12. package/dist/cli/skills.js.map +1 -1
  13. package/dist/client/blocks/library/annotation-rail.d.ts.map +1 -1
  14. package/dist/client/blocks/library/annotation-rail.js +16 -6
  15. package/dist/client/blocks/library/annotation-rail.js.map +1 -1
  16. package/dist/deploy/build.d.ts.map +1 -1
  17. package/dist/deploy/build.js +10 -2
  18. package/dist/deploy/build.js.map +1 -1
  19. package/dist/extensions/actions.js +1 -1
  20. package/dist/extensions/actions.js.map +1 -1
  21. package/dist/local-artifacts/index.d.ts +101 -0
  22. package/dist/local-artifacts/index.d.ts.map +1 -0
  23. package/dist/local-artifacts/index.js +507 -0
  24. package/dist/local-artifacts/index.js.map +1 -0
  25. package/dist/secrets/substitution.js +2 -2
  26. package/dist/secrets/substitution.js.map +1 -1
  27. package/dist/server/auth-marketing.d.ts +1 -0
  28. package/dist/server/auth-marketing.d.ts.map +1 -1
  29. package/dist/server/auth-marketing.js +5 -0
  30. package/dist/server/auth-marketing.js.map +1 -1
  31. package/dist/server/auth.d.ts.map +1 -1
  32. package/dist/server/auth.js +59 -37
  33. package/dist/server/auth.js.map +1 -1
  34. package/dist/server/entry-server.d.ts +27 -4
  35. package/dist/server/entry-server.d.ts.map +1 -1
  36. package/dist/server/entry-server.js +63 -43
  37. package/dist/server/entry-server.js.map +1 -1
  38. package/dist/server/onboarding-html.d.ts.map +1 -1
  39. package/dist/server/onboarding-html.js +3 -3
  40. package/dist/server/onboarding-html.js.map +1 -1
  41. package/dist/server/social-og-image.d.ts +2 -0
  42. package/dist/server/social-og-image.d.ts.map +1 -1
  43. package/dist/server/social-og-image.js +20 -7
  44. package/dist/server/social-og-image.js.map +1 -1
  45. package/dist/server/ssr-handler.d.ts.map +1 -1
  46. package/dist/server/ssr-handler.js +2 -2
  47. package/dist/server/ssr-handler.js.map +1 -1
  48. package/dist/shared/index.d.ts +1 -1
  49. package/dist/shared/index.d.ts.map +1 -1
  50. package/dist/shared/index.js +1 -1
  51. package/dist/shared/index.js.map +1 -1
  52. package/dist/shared/social-meta.d.ts +2 -0
  53. package/dist/shared/social-meta.d.ts.map +1 -1
  54. package/dist/shared/social-meta.js +5 -0
  55. package/dist/shared/social-meta.js.map +1 -1
  56. package/dist/templates/default/.agents/skills/storing-data/SKILL.md +3 -1
  57. package/dist/templates/default/app/entry.server.tsx +8 -2
  58. package/dist/templates/starter-shell-sync.spec.ts +4 -3
  59. package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +3 -2
  60. package/dist/templates/workspace-core/.agents/skills/storing-data/SKILL.md +3 -1
  61. package/docs/content/pr-visual-recap.md +4 -4
  62. package/docs/content/template-content.md +9 -0
  63. package/package.json +6 -1
  64. package/src/templates/default/.agents/skills/storing-data/SKILL.md +3 -1
  65. package/src/templates/default/app/entry.server.tsx +8 -2
  66. package/src/templates/starter-shell-sync.spec.ts +4 -3
  67. package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +3 -2
  68. package/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +3 -1
package/dist/cli/recap.js CHANGED
@@ -192,6 +192,7 @@ export function writePrVisualRecapReusableCallerWorkflow(baseDir, options = {})
192
192
  return { status: "written", path: rel, existed: false };
193
193
  }
194
194
  const DEFAULT_RECAP_APP_URL = "https://plan.agent-native.com";
195
+ const RECAP_MCP_CLIENT_HEADER = "agent-native-pr-visual-recap";
195
196
  export function normalizeRecapAgent(value) {
196
197
  const agent = (value || "claude").toLowerCase();
197
198
  if (agent === "codex")
@@ -1088,7 +1089,11 @@ export function buildRecapClaudeMcpConfig(appUrl, token) {
1088
1089
  plan: {
1089
1090
  type: "http",
1090
1091
  url,
1091
- headers: { Authorization: "Bearer " + token },
1092
+ headers: {
1093
+ Authorization: "Bearer " + token,
1094
+ "X-Agent-Native-MCP-Client": RECAP_MCP_CLIENT_HEADER,
1095
+ "X-Agent-Native-MCP-Full-Catalog": "1",
1096
+ },
1092
1097
  },
1093
1098
  },
1094
1099
  });
@@ -1105,7 +1110,8 @@ export function buildRecapCodexMcpConfig(appUrl) {
1105
1110
  "url = " +
1106
1111
  JSON.stringify(url) +
1107
1112
  "\n" +
1108
- 'bearer_token_env_var = "PLAN_RECAP_TOKEN"\n');
1113
+ 'bearer_token_env_var = "PLAN_RECAP_TOKEN"\n' +
1114
+ 'http_headers = { "X-Agent-Native-MCP-Client" = "agent-native-pr-visual-recap", "X-Agent-Native-MCP-Full-Catalog" = "1" }\n');
1109
1115
  }
1110
1116
  /**
1111
1117
  * `recap mcp-config` — write the plan MCP client config for the chosen backend,
@@ -1319,7 +1325,7 @@ export function buildRecapPrompt(input) {
1319
1325
  else {
1320
1326
  lines.push("## Publish (this is the only way to produce output)");
1321
1327
  lines.push(`The \`plan\` MCP server is configured for you. Call its tools by name (your host may expose them as \`get-plan-blocks\` / \`create-visual-recap\` or \`mcp__plan__get-plan-blocks\` / \`mcp__plan__create-visual-recap\` — same tools).`);
1322
- lines.push("This is a one-shot GitHub Actions run. Do not schedule wakeups, reminders, follow-ups, or retries in another turn; either publish the recap and write `recap-url.txt` in this process, or report the MCP/tool failure plainly.");
1328
+ lines.push("This is a one-shot GitHub Actions run. Do not wait, sleep, back off, schedule wakeups, reminders, follow-ups, or retries in another turn. Either publish the recap and write `recap-url.txt` in this process, or report the MCP/tool failure plainly.");
1323
1329
  lines.push("First call `get-plan-blocks`, then call `create-visual-recap`. If `create-visual-recap` is available but `get-plan-blocks` is not, the Plan MCP is connected but the block-registry tool is not visible to this runner. Report that the runner must expose `get-plan-blocks` through the workflow/tool allowlist or compact MCP catalog; do not describe that case as a disconnected Plan MCP.");
1324
1330
  lines.push(`1. Call the **create-visual-recap** tool on the \`plan\` MCP server with grounded MDX derived ONLY from the real diff, passing \`visibility: "org"\` so the recap is published org-scoped (never public) server-side${input.prevPlanId
1325
1331
  ? `, and also passing \`planId: "${input.prevPlanId}"\` so this REPLACES the existing recap plan`
@@ -1350,6 +1356,9 @@ export function buildRecapPrompt(input) {
1350
1356
  const MARKER = "<!-- pr-visual-recap -->";
1351
1357
  const RECAP_IMAGE_URL_PATH_PATTERN = /\/_agent-native\/recap-image\/[0-9a-f]{32,128}\.png$/;
1352
1358
  const RECAP_SCREENSHOT_QUERY_PARAM = "recapScreenshot";
1359
+ const RECAP_SCREENSHOT_THEME_QUERY_PARAM = "recapScreenshotTheme";
1360
+ const GITHUB_LIGHT_CANVAS_BACKGROUND = "#ffffff";
1361
+ const GITHUB_DARK_CANVAS_BACKGROUND = "#0d1117";
1353
1362
  function repoParts(repoFullName) {
1354
1363
  const [owner, repo] = repoFullName.split("/");
1355
1364
  if (!owner || !repo)
@@ -1437,6 +1446,14 @@ function originOf(url) {
1437
1446
  return "";
1438
1447
  }
1439
1448
  }
1449
+ function trustedRecapImageUrl(raw, base) {
1450
+ const value = (raw || "").trim();
1451
+ return value &&
1452
+ sameOrigin(value, base) &&
1453
+ RECAP_IMAGE_URL_PATH_PATTERN.test(value)
1454
+ ? value
1455
+ : "";
1456
+ }
1440
1457
  /** Build the sticky comment body from the workflow's environment. */
1441
1458
  export function buildCommentBody(env = process.env) {
1442
1459
  const lines = [MARKER];
@@ -1513,28 +1530,29 @@ export function buildCommentBody(env = process.env) {
1513
1530
  lines.push(diagnostic);
1514
1531
  }
1515
1532
  }
1516
- // Keep a link to the last-good recap so reviewers are not left in the dark.
1517
- if (prevPlanId && base) {
1518
- const prevSafeUrl = `${base}/recaps/${prevPlanId}`;
1519
- lines.push("", `Previous recap (from an earlier push): [Open recap](${prevSafeUrl})`);
1520
- }
1521
1533
  if (markerPlanId)
1522
1534
  lines.push("", `<!-- plan-id: ${markerPlanId} -->`);
1523
1535
  return lines.join("\n");
1524
1536
  }
1525
- // The image URL is produced by our own recap-image route, but validate it is
1537
+ // Image URLs are produced by our own recap-image route, but validate each is
1526
1538
  // same-origin and matches the canonical hex-token path before embedding it, so
1527
- // it likewise cannot inject markdown.
1528
- const imageUrlRaw = (env.RECAP_IMAGE_URL || "").trim();
1529
- const imageUrl = imageUrlRaw &&
1530
- sameOrigin(imageUrlRaw, base) &&
1531
- RECAP_IMAGE_URL_PATH_PATTERN.test(imageUrlRaw)
1532
- ? imageUrlRaw
1533
- : "";
1539
+ // they likewise cannot inject markdown or HTML.
1540
+ const lightImageUrl = trustedRecapImageUrl(env.RECAP_LIGHT_IMAGE_URL || env.RECAP_IMAGE_URL, base);
1541
+ const darkImageUrl = trustedRecapImageUrl(env.RECAP_DARK_IMAGE_URL, base);
1542
+ const fallbackImageUrl = lightImageUrl || darkImageUrl;
1534
1543
  lines.push(`### Here's a [visual recap](${safeUrl}) of what changed:`);
1535
1544
  lines.push("");
1536
- if (imageUrl) {
1537
- lines.push(`[![Visual recap](${imageUrl})](${safeUrl})`);
1545
+ if (lightImageUrl && darkImageUrl) {
1546
+ lines.push(`<a href="${safeUrl}">`);
1547
+ lines.push(`<picture>`);
1548
+ lines.push(` <source media="(prefers-color-scheme: dark)" srcset="${darkImageUrl}">`);
1549
+ lines.push(` <img alt="Visual recap" src="${lightImageUrl}">`);
1550
+ lines.push(`</picture>`);
1551
+ lines.push(`</a>`);
1552
+ lines.push("");
1553
+ }
1554
+ else if (fallbackImageUrl) {
1555
+ lines.push(`[![Visual recap](${fallbackImageUrl})](${safeUrl})`);
1538
1556
  lines.push("");
1539
1557
  }
1540
1558
  lines.push(`**[Open the full interactive recap](${safeUrl})**`);
@@ -1711,10 +1729,25 @@ async function defaultImportPlaywright() {
1711
1729
  return (await import("@playwright/test"));
1712
1730
  }
1713
1731
  }
1714
- export function withRecapScreenshotParams(url) {
1732
+ function parseRecapScreenshotTheme(value) {
1733
+ if (value === undefined)
1734
+ return undefined;
1735
+ if (value === "light" || value === "dark")
1736
+ return value;
1737
+ throw new Error("--theme must be light or dark.");
1738
+ }
1739
+ function recapScreenshotBackground(theme) {
1740
+ return theme === "dark"
1741
+ ? GITHUB_DARK_CANVAS_BACKGROUND
1742
+ : GITHUB_LIGHT_CANVAS_BACKGROUND;
1743
+ }
1744
+ export function withRecapScreenshotParams(url, options = {}) {
1715
1745
  try {
1716
1746
  const parsed = new URL(url);
1717
1747
  parsed.searchParams.set(RECAP_SCREENSHOT_QUERY_PARAM, "1");
1748
+ if (options.theme) {
1749
+ parsed.searchParams.set(RECAP_SCREENSHOT_THEME_QUERY_PARAM, options.theme);
1750
+ }
1718
1751
  return parsed.toString();
1719
1752
  }
1720
1753
  catch {
@@ -1728,6 +1761,7 @@ importPlaywright = defaultImportPlaywright) {
1728
1761
  const out = optionalArg(args, "out") ?? "recap.png";
1729
1762
  const token = optionalArg(args, "token");
1730
1763
  const appUrl = optionalArg(args, "app-url");
1764
+ const theme = parseRecapScreenshotTheme(optionalArg(args, "theme"));
1731
1765
  const done = (obj) => {
1732
1766
  process.stdout.write(`${JSON.stringify(obj)}\n`);
1733
1767
  };
@@ -1753,7 +1787,7 @@ importPlaywright = defaultImportPlaywright) {
1753
1787
  return;
1754
1788
  }
1755
1789
  }
1756
- const captureUrl = withRecapScreenshotParams(url);
1790
+ const captureUrl = withRecapScreenshotParams(url, { theme });
1757
1791
  let chromium;
1758
1792
  try {
1759
1793
  ({ chromium } = await importPlaywright());
@@ -1773,7 +1807,33 @@ importPlaywright = defaultImportPlaywright) {
1773
1807
  const context = await browser.newContext({
1774
1808
  viewport: RECAP_SHOT_VIEWPORT,
1775
1809
  deviceScaleFactor: RECAP_SHOT_DEVICE_SCALE_FACTOR,
1810
+ ...(theme ? { colorScheme: theme } : {}),
1776
1811
  });
1812
+ if (theme) {
1813
+ await context.addInitScript(({ background, nextTheme }) => {
1814
+ const applyTheme = () => {
1815
+ try {
1816
+ window.localStorage.setItem("theme", nextTheme);
1817
+ }
1818
+ catch {
1819
+ /* ignore */
1820
+ }
1821
+ const root = document.documentElement;
1822
+ root.classList.remove("light", "dark");
1823
+ root.classList.add(nextTheme);
1824
+ root.setAttribute("data-theme", nextTheme);
1825
+ root.style.colorScheme = nextTheme;
1826
+ root.style.backgroundColor = background;
1827
+ if (document.body) {
1828
+ document.body.style.backgroundColor = background;
1829
+ }
1830
+ };
1831
+ applyTheme();
1832
+ document.addEventListener("DOMContentLoaded", applyTheme, {
1833
+ once: true,
1834
+ });
1835
+ }, { background: recapScreenshotBackground(theme), nextTheme: theme });
1836
+ }
1777
1837
  if (attachToken) {
1778
1838
  // Attach the bearer ONLY to same-origin requests. Context-wide
1779
1839
  // extraHTTPHeaders would also send it to every cross-origin subresource
@@ -1813,9 +1873,23 @@ importPlaywright = defaultImportPlaywright) {
1813
1873
  }
1814
1874
  }
1815
1875
  await page.waitForTimeout(matched ? 1_200 : 500);
1816
- await page.evaluate(() => {
1876
+ await page.evaluate((background) => {
1817
1877
  document.documentElement.style.zoom = "100%";
1818
- });
1878
+ if (!background)
1879
+ return;
1880
+ const root = document.documentElement;
1881
+ root.style.backgroundColor = background;
1882
+ document.body.style.backgroundColor = background;
1883
+ for (const selector of [
1884
+ ".plans-workspace",
1885
+ "[data-plan-reader]",
1886
+ "[data-plan-document]",
1887
+ ]) {
1888
+ const el = document.querySelector(selector);
1889
+ if (el)
1890
+ el.style.backgroundColor = background;
1891
+ }
1892
+ }, theme ? recapScreenshotBackground(theme) : "");
1819
1893
  const measuredHeight = await page.evaluate((maxHeight) => {
1820
1894
  const readHeights = (selectors) => {
1821
1895
  const result = [];
@@ -2682,7 +2756,7 @@ Usage:
2682
2756
  npx @agent-native/core@latest recap mcp-config --agent claude|codex --app-url <url> [--out <path>]
2683
2757
  npx @agent-native/core@latest recap scan --diff <path>
2684
2758
  npx @agent-native/core@latest recap build-prompt --pr <n> [--repo owner/name] [--head <sha>] [--app-url <url>] [--diff <path>] [--stat <path>] [--prev-plan-id <id>] [--huge] [--local-files] [--local-dir <folder>] [--skill-source auto|latest|repo] [--out <path>]
2685
- npx @agent-native/core@latest recap shot --url <planUrl> [--token <planToken>] [--app-url <url>] [--out recap.png]
2759
+ npx @agent-native/core@latest recap shot --url <planUrl> [--token <planToken>] [--app-url <url>] [--out recap.png] [--theme light|dark]
2686
2760
  npx @agent-native/core@latest recap usage --plan-url <planUrl> --result-file <path> --app-url <url> --token <planToken> [--agent claude|codex] [--model <id>]
2687
2761
  npx @agent-native/core@latest recap agent-summary --result-file <path> [--stderr-file <path>] [--exit-code-file <path>] [--agent claude|codex]
2688
2762
  npx @agent-native/core@latest recap comment <find-plan-id|upsert> --repo owner/name --issue <n> --token <github-token>