@tangle-network/agent-app 0.60.178 → 0.60.180

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 (60) hide show
  1. package/dist/agent-profiles/d1.js +3 -3
  2. package/dist/agent-profiles/index.js +3 -3
  3. package/dist/assistant/index.js +7 -5
  4. package/dist/assistant/index.js.map +1 -1
  5. package/dist/channels/index.js +1 -1
  6. package/dist/chat-routes/index.js +4 -4
  7. package/dist/{chunk-GIJY3YCH.js → chunk-3RHAF2P5.js} +11 -13
  8. package/dist/chunk-3RHAF2P5.js.map +1 -0
  9. package/dist/{chunk-IAFPBYQQ.js → chunk-6ZUVYAKB.js} +506 -315
  10. package/dist/chunk-6ZUVYAKB.js.map +1 -0
  11. package/dist/{chunk-ER3KSBA4.js → chunk-75ZIWV4U.js} +4 -4
  12. package/dist/{chunk-7PSYT35Z.js → chunk-7BYY7QKC.js} +5 -5
  13. package/dist/{chunk-7PSYT35Z.js.map → chunk-7BYY7QKC.js.map} +1 -1
  14. package/dist/chunk-A2GG4D4A.js +43 -0
  15. package/dist/chunk-A2GG4D4A.js.map +1 -0
  16. package/dist/{chunk-6CKNC32J.js → chunk-AJZ3EJB5.js} +2 -2
  17. package/dist/chunk-ATQQCG4I.js +194 -0
  18. package/dist/chunk-ATQQCG4I.js.map +1 -0
  19. package/dist/{chunk-4WEUWCA4.js → chunk-EQRVOMMS.js} +2 -2
  20. package/dist/{chunk-ARBBJWZA.js → chunk-KOTNMTHV.js} +3 -3
  21. package/dist/{chunk-LSUELMHY.js → chunk-LN5RBVGP.js} +6 -33
  22. package/dist/{chunk-LSUELMHY.js.map → chunk-LN5RBVGP.js.map} +1 -1
  23. package/dist/{chunk-CPNJRLPN.js → chunk-WSEXFTN4.js} +46 -7
  24. package/dist/chunk-WSEXFTN4.js.map +1 -0
  25. package/dist/{chunk-NO2YNV5C.js → chunk-YXLN4PXK.js} +2 -2
  26. package/dist/hub-approvals/index.js +1 -1
  27. package/dist/hub-approvals/types.d.ts +16 -1
  28. package/dist/hub-approvals-react/feedback.d.ts +25 -5
  29. package/dist/hub-approvals-react/index.d.ts +1 -0
  30. package/dist/hub-approvals-react/index.js +413 -257
  31. package/dist/hub-approvals-react/index.js.map +1 -1
  32. package/dist/hub-approvals-react/media.d.ts +12 -0
  33. package/dist/integrations-react/index.js +1 -1
  34. package/dist/preset-cloudflare/index.js +2 -2
  35. package/dist/public-consultation/index.d.ts +1 -1
  36. package/dist/sandbox/index.js +4 -4
  37. package/dist/stories/app-shell/interaction-evidence.d.ts +31 -0
  38. package/dist/studio-react/index.js +2 -2
  39. package/dist/theme/tokens.css +158 -0
  40. package/dist/tools/index.js +4 -4
  41. package/dist/web-react/action-dialog.d.ts +2 -2
  42. package/dist/web-react/agent-profile-editor.js +1 -1
  43. package/dist/web-react/agent-profile-form-kit.d.ts +1 -1
  44. package/dist/web-react/async/index.js +1 -1
  45. package/dist/web-react/index.d.ts +2 -0
  46. package/dist/web-react/index.js +12 -5
  47. package/dist/web-react/review-inbox.d.ts +33 -0
  48. package/dist/work-product/index.js +2 -2
  49. package/dist/workspace-react/index.js +1 -1
  50. package/package.json +2 -2
  51. package/dist/chunk-CPNJRLPN.js.map +0 -1
  52. package/dist/chunk-GIJY3YCH.js.map +0 -1
  53. package/dist/chunk-IAFPBYQQ.js.map +0 -1
  54. package/dist/chunk-QJYJOMMO.js +0 -78
  55. package/dist/chunk-QJYJOMMO.js.map +0 -1
  56. /package/dist/{chunk-ER3KSBA4.js.map → chunk-75ZIWV4U.js.map} +0 -0
  57. /package/dist/{chunk-6CKNC32J.js.map → chunk-AJZ3EJB5.js.map} +0 -0
  58. /package/dist/{chunk-4WEUWCA4.js.map → chunk-EQRVOMMS.js.map} +0 -0
  59. /package/dist/{chunk-ARBBJWZA.js.map → chunk-KOTNMTHV.js.map} +0 -0
  60. /package/dist/{chunk-NO2YNV5C.js.map → chunk-YXLN4PXK.js.map} +0 -0
@@ -101,7 +101,13 @@ var PROVIDER_NAMES = {
101
101
  hubspot: "HubSpot",
102
102
  linear: "Linear",
103
103
  inkbox: "Inkbox",
104
- resend: "Resend"
104
+ resend: "Resend",
105
+ "instagram-business": "Instagram",
106
+ "facebook-pages": "Facebook",
107
+ "meta-ads": "Meta Ads",
108
+ "linkedin-ads": "LinkedIn Ads",
109
+ tiktok: "TikTok",
110
+ "youtube-data": "YouTube"
105
111
  };
106
112
  function hubProviderName(id) {
107
113
  if (PROVIDER_NAMES[id]) return PROVIDER_NAMES[id];
@@ -353,11 +359,31 @@ function sendEmail(verb, reply = false) {
353
359
  };
354
360
  };
355
361
  }
356
- function post(channel, reply = false) {
362
+ function post(channel, reply = false, sponsored = false) {
357
363
  return (input) => {
358
- const body = typeof input.text === "string" ? input.text : typeof input.commentary === "string" ? input.commentary : "";
359
- const url = text(input.url);
360
- const where = channel === "x" ? "X" : "LinkedIn";
364
+ const container = asRecord(input.container);
365
+ const body = [input.text, input.commentary, input.caption, input.message, container.caption, input.title].find((value) => typeof value === "string") ?? "";
366
+ const url = text(input.url) ?? text(input.link);
367
+ const where = { x: "X", linkedin: "LinkedIn", instagram: "Instagram", facebook: "Facebook", tiktok: "TikTok" }[channel];
368
+ const media = (Array.isArray(input.media) ? input.media : []).flatMap((value) => {
369
+ const entry = asRecord(value);
370
+ if (entry.kind !== "image" && entry.kind !== "video" || typeof entry.src !== "string") return [];
371
+ return [{
372
+ kind: entry.kind,
373
+ src: entry.src,
374
+ alt: typeof entry.alt === "string" ? entry.alt : "",
375
+ ...typeof entry.poster === "string" ? { poster: entry.poster } : {},
376
+ ...typeof entry.width === "number" ? { width: entry.width } : {},
377
+ ...typeof entry.height === "number" ? { height: entry.height } : {}
378
+ }];
379
+ });
380
+ if (!media.length) {
381
+ const video = text(input.video_url) ?? text(container.video_url);
382
+ const image = text(input.imageUrl) ?? text(input.image_url) ?? text(container.image_url);
383
+ if (video) media.push({ kind: "video", src: video, alt: "" });
384
+ else if (image) media.push({ kind: "image", src: image, alt: "" });
385
+ }
386
+ const placement = channel === "tiktok" || container.media_type === "REELS" ? "vertical" : container.media_type === "CAROUSEL" ? "carousel" : "feed";
361
387
  return {
362
388
  action: reply ? `Reply on ${where}` : `Post on ${where}`,
363
389
  title: `${reply ? "Reply" : "Post"} on ${where}${body ? `: \u201C${clipped(body, 60)}\u201D` : ""}`,
@@ -366,12 +392,18 @@ function post(channel, reply = false) {
366
392
  kind: "post",
367
393
  channel,
368
394
  text: body,
395
+ ...media.length ? { media } : {},
396
+ placement,
397
+ ...sponsored ? { sponsored: true } : {},
398
+ displayName: text(input.displayName),
399
+ handle: text(input.handle),
400
+ callToAction: text(input.callToAction),
369
401
  images: (Array.isArray(input.images) ? input.images : input.image ? [input.image] : []).flatMap((image) => {
370
402
  const record = asRecord(image);
371
403
  const url2 = text(image) ?? text(record.url);
372
404
  return url2 ? [{ url: url2, alt: text(record.alt) }] : [];
373
405
  }),
374
- ...url ? { link: { url, title: text(input.title), description: text(input.description) } } : {}
406
+ ...url ? { link: { url, title: text(input.headline) ?? text(input.title), description: text(input.description) } } : {}
375
407
  }
376
408
  };
377
409
  };
@@ -459,6 +491,13 @@ var PRESENTERS = {
459
491
  "x.tweets.create": post("x"),
460
492
  "linkedin.posts.create": post("linkedin"),
461
493
  "linkedin.shares.create": post("linkedin"),
494
+ "instagram-business.media.createContainer": post("instagram"),
495
+ "tiktok.publishing.videoFromUrl": post("tiktok"),
496
+ "tiktok.publishing.photosFromUrls": post("tiktok"),
497
+ "facebook-pages.pages.feed.create": post("facebook"),
498
+ "facebook-pages.pages.photos.create": post("facebook"),
499
+ "meta-ads.creatives.createLink": post("facebook", false, true),
500
+ "linkedin-ads.creatives.create": post("linkedin", false, true),
462
501
  "slack.post_message": (input) => {
463
502
  const channel = text(input.channel) ?? text(input.channelId);
464
503
  const where = channel ? channel.startsWith("#") || /^[CDG][A-Z0-9]{6,}$/.test(channel) ? channel : `#${channel}` : void 0;
@@ -774,4 +813,4 @@ export {
774
813
  HUB_APPROVAL_RESUME_PART,
775
814
  hubApprovalResumePart
776
815
  };
777
- //# sourceMappingURL=chunk-CPNJRLPN.js.map
816
+ //# sourceMappingURL=chunk-WSEXFTN4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hub-approvals/types.ts","../src/hub-approvals/result.ts","../src/hub-approvals/unknown.ts","../src/hub-approvals/present.ts","../src/hub-approvals/index.ts"],"sourcesContent":["/**\n * The vocabulary of a Hub action that waits on a person: where it stands, what\n * it will do in the owner's words, and what it did once it ran.\n */\n\n/** Where one held action stands, as the dock, the list and the transcript show it. */\nexport type HubApprovalPhase =\n /** Held by Hub; the viewer can decide it. */\n | 'waiting'\n /** Held by Hub; someone else (the workspace owner) decides it. */\n | 'blocked'\n /** Approved here; the run has not started. */\n | 'queued'\n /** Approved; Hub is running the call. */\n | 'running'\n | 'done'\n /** Approved, but Hub could not run it. */\n | 'failed'\n /** The provider may have acted; verify there before requesting it again. */\n | 'unknown'\n | 'denied'\n | 'expired'\n\n/** Phases that still need someone's decision. */\nexport const HUB_APPROVAL_OPEN_PHASES: ReadonlySet<HubApprovalPhase> = new Set(['waiting', 'blocked'])\n/** Phases between a decision and its result. */\nexport const HUB_APPROVAL_ACTIVE_PHASES: ReadonlySet<HubApprovalPhase> = new Set(['queued', 'running'])\n\n/** A file a held write changes. Counts stay undefined until someone has read them. */\nexport interface HubActionFile {\n path: string\n /** A rename reads as a modification of its new path. */\n change: 'added' | 'modified' | 'deleted'\n additions?: number\n deletions?: number\n}\n\n/**\n * The change a held call serves, when it is one step of a larger change such\n * as a pull request. The dock then names the change rather than the step.\n */\nexport interface HubActionBundle {\n /** What the whole change does, e.g. `Open PR: Fix the hero on acme/site`. */\n title: string\n steps?: ReadonlyArray<{ label: string; state: 'done' | 'current' | 'upcoming' }>\n}\n\n/** Whether an open call waits for the owner, in the owner's words. */\nexport interface HubApprovalWait {\n /** True when nothing runs until the owner decides; false when a permission runs it. */\n owner: boolean\n /** One sentence: `Publishing always needs your approval.` or `Runs under this conversation’s auto-approve.` */\n reason: string\n /** A stable cause the host can test, e.g. `never_grantable`, `loop_guard`, `daily_cap`. */\n code?: string\n}\n\n/** One held Hub action and its decision, in the form every surface renders. */\nexport interface HubApprovalItem {\n /** Stable within a conversation, such as `<messageId>:<partId>`. */\n id: string\n /** `provider.action`, e.g. `github.pulls.propose`. */\n actionPath: string\n providerId: string\n /** The call's input as Hub received it. */\n input: unknown\n phase: HubApprovalPhase\n /** The connected account the action runs as, e.g. `octocat` or `ops@acme.com`. */\n account?: string | null\n requestedAt?: string | null\n /** When the decision window closes. */\n expiresAt?: string | null\n /** Hub's result, or a bounded projection of it from {@link summarizeHubResult}. */\n result?: unknown\n error?: string | null\n /** The standing permission granted with the approval. */\n grant?: { scope: string; expiresAt: string | null } | null\n /** Set when a permissions mode, not a person, approved it. */\n autoApproved?: string | null\n /**\n * For an open call, what happens next without the viewer: it waits for the\n * owner, and why, or it runs on its own once the agent's reply finishes.\n */\n wait?: HubApprovalWait | null\n /** Files with line counts read by the host, replacing those the input declares. */\n files?: readonly HubActionFile[]\n bundle?: HubActionBundle | null\n /** Previewing and teaching never execute a call. Live approval remains a separate action. */\n executionMode?: 'dry-run' | 'live'\n feedback?: HubApprovalFeedback & { savedAt?: string }\n /** Host-resolved presentation, e.g. a retained page screenshot or ad creative. No remote fetches. */\n preview?: HubActionPreview\n}\n\n/** The host authenticates the reviewer, binds provenance and computes the edit diff. */\nexport interface HubApprovalFeedback {\n score: number\n comment: string\n /** A teaching example only; never replaces the held input or authorizes execution. */\n editedInput?: unknown\n}\n\n/** A labelled value on a preview or a receipt. */\nexport interface HubActionField {\n label: string\n value: string\n href?: string\n /** Render in the monospace face: shas, ids, paths. */\n mono?: boolean\n}\n\n/** Frozen media bytes supplied by the host; renderers never resolve a provider URL. */\nexport interface HubPreviewMedia {\n kind: 'image' | 'video'\n src: string\n alt: string\n poster?: string\n width?: number\n height?: number\n}\n\n/** What a held call will do, shaped for its integration's renderer. */\nexport type HubActionPreview =\n | {\n kind: 'pull-request'\n repository?: string\n title?: string\n body?: string\n head?: string\n base?: string\n draft?: boolean\n files: readonly HubActionFile[]\n }\n | { kind: 'commit'; repository?: string; message?: string; tree?: string; parents: readonly string[] }\n | { kind: 'branch'; repository?: string; branch?: string; sha?: string }\n | { kind: 'files'; repository?: string; files: readonly HubActionFile[] }\n | { kind: 'issue'; repository?: string; number?: number; title?: string; body?: string; verdict?: string }\n | {\n kind: 'email'\n to: readonly string[]\n cc: readonly string[]\n bcc: readonly string[]\n subject?: string\n from?: string\n fromName?: string\n previewText?: string\n body?: string\n html: boolean\n reply: boolean\n }\n | {\n kind: 'post'\n channel: 'x' | 'linkedin' | 'slack' | 'instagram' | 'facebook' | 'tiktok' | 'youtube'\n text: string\n /** The post's place, such as a Slack channel. */\n where?: string\n link?: { url: string; title?: string; description?: string }\n images?: readonly { url: string; alt?: string }[]\n media?: readonly HubPreviewMedia[]\n placement?: 'feed' | 'vertical' | 'carousel'\n sponsored?: boolean\n displayName?: string\n handle?: string\n callToAction?: string\n }\n | { kind: 'ad'; placement: string; advertiser?: string; headline?: string; text?: string; image?: string; destination?: string; callToAction?: string }\n | { kind: 'page'; title?: string; url?: string; screenshot?: string }\n | { kind: 'payment'; label: string; amount?: number; currency?: string; customer?: string; description?: string }\n | { kind: 'speech'; text: string; voice?: string; seconds?: number }\n | { kind: 'call'; to?: string; from?: string; purpose?: string }\n | {\n kind: 'event'\n title?: string\n start?: string\n end?: string\n location?: string\n attendees: readonly string[]\n description?: string\n }\n | { kind: 'fields'; fields: readonly HubActionField[] }\n\n/** A held call in the owner's words. */\nexport interface HubActionPresentation {\n provider: { id: string; name: string }\n /** The imperative, e.g. `Open pull request`. */\n action: string\n /** One line naming the action and its object, e.g. `Open PR: Fix the hero on acme/site`. */\n title: string\n /** Where it acts: a repository, recipients, a channel or a customer. */\n target?: string\n preview: HubActionPreview\n}\n\n/** What a decided call did, as its receipt shows it. */\nexport interface HubActionReceipt {\n provider: { id: string; name: string }\n /** The result in past tense, e.g. `Opened PR #123` or `Sent email to ada@acme.com`. */\n title: string\n /** The result's own page, when it has one: the pull request, the post, the event. */\n href?: string\n status: 'done' | 'unknown' | 'failed' | 'denied' | 'expired' | 'running' | 'waiting'\n fields: readonly HubActionField[]\n files?: readonly HubActionFile[]\n media?: { kind: 'audio'; src: string; seconds?: number }\n error?: string\n /** Guidance for an uncertain outcome, separate from a confirmed failure. */\n warning?: string\n}\n","/**\n * Hub results, read the same way by every receipt: unwrapped from Hub's\n * envelope and bounded before a host persists them.\n */\n\nconst MAX_DEPTH = 4\nconst MAX_KEYS = 24\nconst MAX_ITEMS = 50\nconst MAX_STRING = 600\n\nexport function asRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : {}\n}\n\n/**\n * The provider's own result inside Hub's envelopes. `tools.invoke` answers\n * `{ result: … }` and a connector may wrap its body in `data`; a JSON string,\n * as an older host stored it, is parsed first.\n */\nexport function unwrapHubResult(value: unknown): unknown {\n let current: unknown = value\n if (typeof current === 'string') {\n const text = current\n try {\n current = JSON.parse(text)\n } catch {\n // An older host stored `Hub result: {…}`-style text with a JSON tail.\n const start = text.indexOf('{')\n if (start < 0) return value\n try {\n current = JSON.parse(text.slice(start))\n } catch {\n return value\n }\n }\n }\n for (let depth = 0; depth < 3; depth++) {\n const record = asRecord(current)\n const keys = Object.keys(record)\n const inner = keys.find((key) => key === 'result' || key === 'data')\n // Only a thin envelope is unwrapped; a body that happens to carry a `data`\n // field among its own fields is the result itself.\n if (!inner || keys.length > 3 || record[inner] === null || typeof record[inner] !== 'object') break\n current = record[inner]\n }\n return current\n}\n\nfunction bounded(value: unknown, depth: number): unknown {\n if (value === null || typeof value === 'boolean') return value\n if (typeof value === 'number') return Number.isFinite(value) ? value : null\n if (typeof value === 'string') return value.length > MAX_STRING ? `${value.slice(0, MAX_STRING - 1)}…` : value\n if (depth >= MAX_DEPTH) return undefined\n if (Array.isArray(value)) {\n return value.slice(0, MAX_ITEMS).map((item) => bounded(item, depth + 1)).filter((item) => item !== undefined)\n }\n if (typeof value === 'object') {\n const out: Record<string, unknown> = {}\n for (const [key, entry] of Object.entries(value as Record<string, unknown>).slice(0, MAX_KEYS)) {\n const kept = bounded(entry, depth + 1)\n if (kept !== undefined) out[key] = kept\n }\n return out\n }\n return undefined\n}\n\n/**\n * A bounded copy of a Hub result for a host to store with the decision: the\n * envelope removed, strings, arrays and nesting capped. Receipts read it in\n * place of the full result.\n */\nexport function summarizeHubResult(result: unknown): unknown {\n return bounded(unwrapHubResult(result), 0)\n}\n\n/** The first non-empty string among `keys`, searched one level into nested records. */\nexport function readText(value: unknown, ...keys: string[]): string | undefined {\n const record = asRecord(value)\n for (const key of keys) {\n const found = record[key]\n if (typeof found === 'string' && found.trim()) return found.trim()\n if (typeof found === 'number' && Number.isFinite(found)) return String(found)\n }\n return undefined\n}\n\nexport function readNumber(value: unknown, ...keys: string[]): number | undefined {\n const record = asRecord(value)\n for (const key of keys) {\n const found = record[key]\n if (typeof found === 'number' && Number.isFinite(found)) return found\n }\n return undefined\n}\n\n/** A link a result names for itself, in the order providers use them. */\nexport function resultLink(value: unknown): string | undefined {\n const url = readText(value, 'html_url', 'htmlLink', 'webLink', 'web_url', 'permalink', 'hosted_invoice_url', 'url', 'link')\n return url && /^https:\\/\\//.test(url) ? url : undefined\n}\n","/** Internal safety copy shared by uncertain-outcome surfaces. */\nexport const HUB_APPROVAL_UNKNOWN_WARNING = 'Check the provider before requesting it again'\n","/**\n * Hub actions in an owner's words. Known integrations read as what they do —\n * `github.pulls.propose` is \"Open PR: Fix the hero on acme/site\", `gmail.send`\n * is \"Send email to ada@acme.com\" — and any other Hub action falls back to its\n * own name and its input's scalar fields.\n */\n\nimport { asRecord, readNumber, readText, resultLink, unwrapHubResult } from './result'\nimport { HUB_APPROVAL_UNKNOWN_WARNING } from './unknown'\nimport type {\n HubActionField,\n HubActionFile,\n HubActionPresentation,\n HubActionPreview,\n HubActionReceipt,\n HubApprovalItem,\n HubPreviewMedia,\n} from './types'\n\nconst PROVIDER_NAMES: Record<string, string> = {\n github: 'GitHub',\n gitlab: 'GitLab',\n gmail: 'Gmail',\n google: 'Google',\n 'google-calendar': 'Google Calendar',\n 'microsoft-calendar': 'Outlook Calendar',\n 'outlook-mail': 'Outlook',\n outlook: 'Outlook',\n twitter: 'X',\n x: 'X',\n linkedin: 'LinkedIn',\n stripe: 'Stripe',\n phony: 'ph0ny',\n slack: 'Slack',\n notion: 'Notion',\n hubspot: 'HubSpot',\n linear: 'Linear',\n inkbox: 'Inkbox',\n resend: 'Resend',\n 'instagram-business': 'Instagram',\n 'facebook-pages': 'Facebook',\n 'meta-ads': 'Meta Ads',\n 'linkedin-ads': 'LinkedIn Ads',\n tiktok: 'TikTok',\n 'youtube-data': 'YouTube',\n}\n\n/** A provider's display name: `github` is GitHub, `outlook-mail` is Outlook. */\nexport function hubProviderName(id: string): string {\n if (PROVIDER_NAMES[id]) return PROVIDER_NAMES[id]\n const words = id.split(/[-_\\s]+/).filter(Boolean)\n return words.map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(' ') || id\n}\n\n/** `provider.action` split at the first dot. */\nexport function splitHubActionPath(actionPath: string): { provider: string; action: string } {\n const separator = actionPath.indexOf('.')\n return separator < 0 ? { provider: '', action: actionPath } : { provider: actionPath.slice(0, separator), action: actionPath.slice(separator + 1) }\n}\n\nfunction text(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value.trim() : undefined\n}\n\nfunction clipped(value: string, max = 80): string {\n const single = value.replace(/\\s+/g, ' ').trim()\n return single.length > max ? `${single.slice(0, max - 1).trimEnd()}…` : single\n}\n\nfunction list(value: unknown): string[] {\n if (typeof value === 'string') return value.split(/[,;]/).map((entry) => entry.trim()).filter(Boolean)\n if (!Array.isArray(value)) return []\n return value.flatMap((entry) => {\n if (typeof entry === 'string' && entry.trim()) return [entry.trim()]\n const record = asRecord(entry)\n const address = text(record.email) ?? text(record.address) ?? text(asRecord(record.emailAddress).address)\n return address ? [address] : []\n })\n}\n\nfunction people(addresses: readonly string[]): string {\n if (addresses.length === 0) return ''\n if (addresses.length === 1) return addresses[0]!\n return `${addresses[0]} and ${addresses.length - 1} more`\n}\n\nfunction shortSha(sha: string | undefined): string | undefined {\n return sha && /^[0-9a-f]{7,}$/i.test(sha) ? sha.slice(0, 7) : sha\n}\n\n// ---------- verbs ----------\n\nconst PAST: Record<string, string> = {\n add: 'added', approve: 'approved', archive: 'archived', assign: 'assigned', book: 'booked', cancel: 'canceled',\n capture: 'captured', charge: 'charged', clone: 'cloned', close: 'closed', comment: 'commented', create: 'created',\n deactivate: 'deactivated', delete: 'deleted', enroll: 'enrolled', export: 'exported', finalize: 'finalized',\n forward: 'forwarded', import: 'imported', ingest: 'ingested', invite: 'invited', like: 'liked', make: 'made',\n merge: 'merged', move: 'moved', open: 'opened', pay: 'paid', place: 'placed', post: 'posted', provision: 'provisioned',\n publish: 'published', put: 'put', react: 'reacted', refund: 'refunded', remove: 'removed', reply: 'replied',\n retweet: 'reposted', review: 'reviewed', run: 'ran', save: 'saved', schedule: 'scheduled', send: 'sent', set: 'set',\n share: 'shared', start: 'started', stop: 'stopped', submit: 'submitted', subscribe: 'subscribed',\n synthesize: 'synthesized', transfer: 'transferred', translate: 'translated', update: 'updated', upload: 'uploaded',\n upsert: 'saved', void: 'voided', watch: 'watched', write: 'wrote',\n}\n\n/** The past tense of an English verb this vocabulary uses. */\nexport function pastTense(verb: string): string {\n const lower = verb.toLowerCase()\n const past = PAST[lower] ?? (lower.endsWith('e') ? `${lower}d` : `${lower}ed`)\n return verb.charAt(0) === verb.charAt(0).toUpperCase() ? past.charAt(0).toUpperCase() + past.slice(1) : past\n}\n\nfunction words(action: string): string[] {\n return action\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .split(/[._\\-\\s]+/)\n .map((word) => word.toLowerCase())\n .filter(Boolean)\n}\n\nfunction singular(word: string): string {\n if (word.endsWith('ies')) return `${word.slice(0, -3)}y`\n if (word.endsWith('sses') || word.endsWith('ss')) return word\n return word.endsWith('s') && word.length > 3 ? word.slice(0, -1) : word\n}\n\n/** A Hub action's own name as a sentence: `payment-intents.create` is \"Create payment intent\". */\nfunction genericVerb(action: string): { verb: string; noun: string } {\n const parts = words(action)\n const index = parts.findIndex((word) => word in PAST)\n if (index < 0) return { verb: '', noun: parts.join(' ') }\n const noun = [...parts.slice(0, index), ...parts.slice(index + 1)].map(singular).join(' ')\n return { verb: parts[index]!, noun }\n}\n\nfunction sentence(verb: string, noun: string): string {\n const phrase = [verb, noun].filter(Boolean).join(' ')\n return phrase.charAt(0).toUpperCase() + phrase.slice(1)\n}\n\n// ---------- inputs ----------\n\nfunction repository(input: Record<string, unknown>): string | undefined {\n const owner = text(input.owner)\n const repo = text(input.repo)\n if (owner && repo) return `${owner}/${repo}`\n return repo ?? text(input.repository)\n}\n\nfunction branchOf(ref: unknown): string | undefined {\n return text(ref)?.replace(/^refs\\/heads\\//, '')\n}\n\n/** The files a call writes, as its input declares them. */\nexport function hubActionFiles(actionPath: string, input: unknown): HubActionFile[] {\n const fields = asRecord(input)\n const { action } = splitHubActionPath(actionPath)\n const entries = action === 'git.createTree' ? fields.tree : fields.files\n if (!Array.isArray(entries)) return []\n return entries.flatMap((entry): HubActionFile[] => {\n const item = asRecord(entry)\n const path = text(item.path)\n if (!path) return []\n const deleted = item.delete === true || (item.sha === null && item.content === undefined)\n return [{ path, change: deleted ? 'deleted' : 'modified' }]\n })\n}\n\n/** Counted files replace declared ones by path; the declared order stays. */\nfunction mergedFiles(declared: readonly HubActionFile[], counted: readonly HubActionFile[] | undefined): HubActionFile[] {\n if (!counted || counted.length === 0) return [...declared]\n if (declared.length === 0) return [...counted]\n const byPath = new Map(counted.map((file) => [file.path, file]))\n return declared.map((file) => byPath.get(file.path) ?? file)\n}\n\nfunction emailPreview(input: Record<string, unknown>, reply: boolean): HubActionPreview {\n const from = asRecord(input.from)\n const htmlBody = typeof input.html === 'string' ? input.html : undefined\n return {\n kind: 'email',\n to: list(input.to ?? input.recipients),\n cc: list(input.cc),\n bcc: list(input.bcc),\n subject: text(input.subject),\n from: text(input.from) ?? text(from.email) ?? text(from.address),\n fromName: text(input.fromName) ?? text(input.from_name) ?? text(from.name),\n previewText: text(input.previewText) ?? text(input.preview_text) ?? text(input.preheader),\n // The payload is evidence: retain whitespace and prefer the actual HTML part.\n body: htmlBody ?? [input.body, input.text, input.comment].find((value): value is string => typeof value === 'string'),\n html: input.html === true || text(input.bodyType)?.toLowerCase() === 'html' || typeof input.html === 'string',\n reply,\n }\n}\n\nfunction speechSeconds(input: Record<string, unknown>): number | undefined {\n const spoken = text(input.text)\n if (!spoken) return undefined\n const speed = typeof input.speed === 'number' && input.speed > 0 ? input.speed : 1\n // About 2.5 spoken words a second at normal speed.\n return Math.max(1, Math.round(spoken.split(/\\s+/).length / 2.5 / speed))\n}\n\nfunction voiceName(input: Record<string, unknown>): string | undefined {\n const voice = text(input.voiceId)\n // An opaque provider id says nothing to an owner; a named voice does.\n if (voice && !/^[0-9a-f-]{16,}$/i.test(voice) && voice.length <= 32) return voice.charAt(0).toUpperCase() + voice.slice(1)\n return text(input.provider)\n}\n\nconst CURRENCY_DIGITS: Record<string, number> = { jpy: 0, krw: 0, vnd: 0, clp: 0, bhd: 3, kwd: 3, omr: 3 }\n\n/** A Stripe minor-unit amount in its currency: `4900` USD is `$49.00`. */\nexport function formatMinorAmount(amount: number, currency = 'usd'): string {\n const code = currency.toLowerCase()\n const digits = CURRENCY_DIGITS[code] ?? 2\n try {\n return new Intl.NumberFormat('en-US', { style: 'currency', currency: code.toUpperCase(), minimumFractionDigits: digits })\n .format(amount / 10 ** digits)\n } catch {\n return `${(amount / 10 ** digits).toFixed(digits)} ${code.toUpperCase()}`\n }\n}\n\n/** Scalar input fields, for an action no renderer knows. */\nfunction scalarFields(input: Record<string, unknown>, max = 6): HubActionField[] {\n return Object.entries(input).flatMap(([key, value]): HubActionField[] => {\n if (key.startsWith('__')) return []\n if (typeof value === 'string' && value.trim()) return [{ label: labelOf(key), value: clipped(value, 160) }]\n if (typeof value === 'number' || typeof value === 'boolean') return [{ label: labelOf(key), value: String(value) }]\n const strings = Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === 'string') : []\n return strings.length > 0 ? [{ label: labelOf(key), value: clipped(strings.join(', '), 160) }] : []\n }).slice(0, max)\n}\n\nfunction labelOf(key: string): string {\n const spaced = key.replace(/([a-z0-9])([A-Z])/g, '$1 $2').replace(/[_-]+/g, ' ').trim().toLowerCase()\n return spaced.charAt(0).toUpperCase() + spaced.slice(1)\n}\n\n// ---------- presentation ----------\n\ntype Presenter = (input: Record<string, unknown>, item: Pick<HubApprovalItem, 'actionPath' | 'files'>) => Omit<HubActionPresentation, 'provider'>\n\nfunction pullRequest(input: Record<string, unknown>, item: Pick<HubApprovalItem, 'actionPath' | 'files'>): Omit<HubActionPresentation, 'provider'> {\n const repo = repository(input)\n const title = text(input.title) ?? 'Untitled change'\n return {\n action: 'Open pull request',\n title: `Open PR: ${clipped(title)}${repo ? ` on ${repo}` : ''}`,\n ...(repo ? { target: repo } : {}),\n preview: {\n kind: 'pull-request',\n repository: repo,\n title,\n body: text(input.body),\n head: branchOf(input.branch ?? input.head),\n base: text(input.base),\n draft: item.actionPath.endsWith('.propose') ? true : input.draft === true,\n files: mergedFiles(hubActionFiles(item.actionPath, input), item.files),\n },\n }\n}\n\nfunction issueLike(verb: string, noun: string): Presenter {\n return (input) => {\n const repo = repository(input)\n const number = readNumber(input, 'issue_number', 'pull_number', 'number')\n const title = text(input.title)\n const object = number !== undefined ? `${noun} #${number}` : title ? `${noun}: ${clipped(title)}` : noun\n return {\n action: sentence(verb, noun.toLowerCase()),\n title: `${sentence(verb, object)}${repo ? ` on ${repo}` : ''}`,\n ...(repo ? { target: repo } : {}),\n preview: {\n kind: 'issue',\n repository: repo,\n number,\n title,\n body: text(input.body),\n verdict: text(input.event)?.toLowerCase().replace(/_/g, ' '),\n },\n }\n }\n}\n\nfunction sendEmail(verb: 'Send' | 'Save draft', reply = false): Presenter {\n return (input) => {\n const preview = emailPreview(input, reply)\n const recipients = preview.kind === 'email' ? people(preview.to) : ''\n const action = reply ? 'Send reply' : verb === 'Send' ? 'Send email' : 'Save draft'\n return {\n action,\n title: reply ? 'Send reply' : `${action}${recipients ? ` to ${recipients}` : ''}`,\n ...(recipients ? { target: recipients } : {}),\n preview,\n }\n }\n}\n\nfunction post(channel: 'x' | 'linkedin' | 'instagram' | 'facebook' | 'tiktok', reply = false, sponsored = false): Presenter {\n return (input) => {\n const container = asRecord(input.container)\n const body = [input.text, input.commentary, input.caption, input.message, container.caption, input.title]\n .find((value): value is string => typeof value === 'string') ?? ''\n const url = text(input.url) ?? text(input.link)\n const where = { x: 'X', linkedin: 'LinkedIn', instagram: 'Instagram', facebook: 'Facebook', tiktok: 'TikTok' }[channel]\n const media = (Array.isArray(input.media) ? input.media : []).flatMap((value): HubPreviewMedia[] => {\n const entry = asRecord(value)\n if ((entry.kind !== 'image' && entry.kind !== 'video') || typeof entry.src !== 'string') return []\n return [{ kind: entry.kind, src: entry.src, alt: typeof entry.alt === 'string' ? entry.alt : '',\n ...(typeof entry.poster === 'string' ? { poster: entry.poster } : {}),\n ...(typeof entry.width === 'number' ? { width: entry.width } : {}),\n ...(typeof entry.height === 'number' ? { height: entry.height } : {}) }]\n })\n if (!media.length) {\n const video = text(input.video_url) ?? text(container.video_url)\n const image = text(input.imageUrl) ?? text(input.image_url) ?? text(container.image_url)\n if (video) media.push({ kind: 'video', src: video, alt: '' })\n else if (image) media.push({ kind: 'image', src: image, alt: '' })\n }\n const placement = channel === 'tiktok' || container.media_type === 'REELS' ? 'vertical'\n : container.media_type === 'CAROUSEL' ? 'carousel' : 'feed'\n return {\n action: reply ? `Reply on ${where}` : `Post on ${where}`,\n title: `${reply ? 'Reply' : 'Post'} on ${where}${body ? `: “${clipped(body, 60)}”` : ''}`,\n target: where,\n preview: {\n kind: 'post',\n channel,\n text: body,\n ...(media.length ? { media } : {}),\n placement,\n ...(sponsored ? { sponsored: true } : {}),\n displayName: text(input.displayName),\n handle: text(input.handle),\n callToAction: text(input.callToAction),\n images: (Array.isArray(input.images) ? input.images : input.image ? [input.image] : []).flatMap((image) => {\n const record = asRecord(image)\n const url = text(image) ?? text(record.url)\n return url ? [{ url, alt: text(record.alt) }] : []\n }),\n ...(url ? { link: { url, title: text(input.headline) ?? text(input.title), description: text(input.description) } } : {}),\n },\n }\n }\n}\n\nfunction payment(label: string): Presenter {\n return (input) => {\n const amount = readNumber(input, 'amount')\n const currency = text(input.currency)\n const customer = text(input.customerId) ?? text(input.customer) ?? text(input.email)\n const formatted = amount !== undefined ? formatMinorAmount(amount, currency) : undefined\n const object = formatted ? `${label} of ${formatted}` : label\n return {\n action: sentence('create', label),\n title: `${sentence('create', object)}${customer ? ` for ${customer}` : ''}`,\n ...(customer ? { target: customer } : {}),\n preview: { kind: 'payment', label, amount, currency, customer, description: text(input.description) },\n }\n }\n}\n\nfunction calendarEvent(input: Record<string, unknown>, _item?: Pick<HubApprovalItem, 'actionPath' | 'files'>): Omit<HubActionPresentation, 'provider'> {\n const title = text(input.summary) ?? text(input.title) ?? text(input.subject)\n return {\n action: 'Book event',\n title: title ? `Book “${clipped(title, 60)}”` : 'Book an event',\n preview: {\n kind: 'event',\n title,\n start: text(input.start) ?? text(asRecord(input.start).dateTime),\n end: text(input.end) ?? text(asRecord(input.end).dateTime),\n location: text(input.location) ?? text(asRecord(input.location).displayName),\n attendees: list(input.attendees),\n description: text(input.description),\n },\n }\n}\n\nconst PRESENTERS: Record<string, Presenter> = {\n 'github.pulls.propose': pullRequest,\n 'github.pulls.create': pullRequest,\n 'github.git.createTree': (input, item) => {\n const repo = repository(input)\n const files = mergedFiles(hubActionFiles(item.actionPath, input), item.files)\n return {\n action: 'Write files',\n title: `Write ${files.length === 1 ? files[0]!.path : `${files.length} files`}${repo ? ` to ${repo}` : ''}`,\n ...(repo ? { target: repo } : {}),\n preview: { kind: 'files', repository: repo, files },\n }\n },\n 'github.git.createCommit': (input) => {\n const repo = repository(input)\n const message = text(input.message)\n return {\n action: 'Create commit',\n title: `Commit${message ? ` “${clipped(message, 60)}”` : ''}${repo ? ` to ${repo}` : ''}`,\n ...(repo ? { target: repo } : {}),\n preview: { kind: 'commit', repository: repo, message, tree: text(input.tree), parents: list(input.parents) },\n }\n },\n 'github.git.createRef': (input) => {\n const repo = repository(input)\n const branch = branchOf(input.ref)\n return {\n action: 'Create branch',\n title: `Create branch ${branch ?? ''}${repo ? ` in ${repo}` : ''}`.replace(/\\s+/g, ' ').trim(),\n ...(repo ? { target: repo } : {}),\n preview: { kind: 'branch', repository: repo, branch, sha: text(input.sha) },\n }\n },\n 'github.pulls.merge': issueLike('merge', 'PR'),\n 'github.pulls.reviews.create': issueLike('review', 'PR'),\n 'github.issues.create': issueLike('open', 'Issue'),\n 'github.issues.update': issueLike('update', 'Issue'),\n 'github.issues.createComment': issueLike('comment on', 'Issue'),\n 'gmail.send': sendEmail('Send'),\n 'gmail.send_reply': sendEmail('Send', true),\n 'outlook-mail.send_message': sendEmail('Send'),\n 'outlook-mail.send_draft': sendEmail('Send'),\n 'outlook-mail.create_draft': sendEmail('Save draft'),\n 'outlook-mail.send_reply': sendEmail('Send', true),\n 'inkbox.email.send': sendEmail('Send'),\n 'resend.emails.send': sendEmail('Send'),\n 'resend.emails.reply': sendEmail('Send', true),\n 'twitter.tweets.create': post('x'),\n 'twitter.tweets.reply': post('x', true),\n 'x.tweets.create': post('x'),\n 'linkedin.posts.create': post('linkedin'),\n 'linkedin.shares.create': post('linkedin'),\n 'instagram-business.media.createContainer': post('instagram'),\n 'tiktok.publishing.videoFromUrl': post('tiktok'),\n 'tiktok.publishing.photosFromUrls': post('tiktok'),\n 'facebook-pages.pages.feed.create': post('facebook'),\n 'facebook-pages.pages.photos.create': post('facebook'),\n 'meta-ads.creatives.createLink': post('facebook', false, true),\n 'linkedin-ads.creatives.create': post('linkedin', false, true),\n 'slack.post_message': (input) => {\n const channel = text(input.channel) ?? text(input.channelId)\n const where = channel ? (channel.startsWith('#') || /^[CDG][A-Z0-9]{6,}$/.test(channel) ? channel : `#${channel}`) : undefined\n return {\n action: 'Post in Slack',\n title: `Post in ${where ?? 'Slack'}`,\n ...(where ? { target: where } : {}),\n preview: { kind: 'post', channel: 'slack', text: text(input.text) ?? '', where },\n }\n },\n 'stripe.payment-intents.create': payment('payment'),\n 'stripe.payment-links.create': payment('payment link'),\n 'stripe.invoices.create': payment('invoice'),\n 'stripe.refunds.create': payment('refund'),\n 'stripe.subscriptions.create': payment('subscription'),\n 'phony.synthesize_speech': (input) => {\n const seconds = speechSeconds(input)\n const voice = voiceName(input)\n const detail = [voice, seconds ? `${seconds} s` : undefined].filter(Boolean)\n return {\n action: 'Create voice memo',\n title: `Create voice memo${detail.length ? ` (${detail.join(', ')})` : ''}`,\n preview: { kind: 'speech', text: text(input.text) ?? '', voice, seconds },\n }\n },\n 'phony.start_outbound_call': (input) => {\n const to = text(input.toNumber) ?? text(input.to)\n const mission = asRecord(input.mission)\n return {\n action: 'Start call',\n title: to ? `Call ${to}` : 'Start an outbound call',\n ...(to ? { target: to } : {}),\n preview: {\n kind: 'call',\n to,\n from: text(input.fromNumber),\n purpose: text(mission.goal) ?? text(mission.objective) ?? text(mission.summary) ?? text(input.missionId),\n },\n }\n },\n 'phony.create_agent': (input) => {\n const name = text(input.name)\n return {\n action: 'Create voice agent',\n title: `Create voice agent${name ? ` “${clipped(name, 60)}”` : ''}`,\n preview: { kind: 'fields', fields: scalarFields(input) },\n }\n },\n 'phony.update_agent': (input) => ({\n action: 'Update voice agent',\n title: 'Update a voice agent',\n preview: { kind: 'fields', fields: scalarFields(input) },\n }),\n 'phony.clone_voice': (input) => {\n const name = text(input.name)\n return {\n action: 'Clone voice',\n title: `Clone your voice${name ? ` as “${clipped(name, 60)}”` : ''}`,\n preview: { kind: 'fields', fields: scalarFields(input) },\n }\n },\n 'google-calendar.create_event': calendarEvent,\n 'google-calendar.book_slot': calendarEvent,\n 'google-calendar.update_event': (input, item) => {\n const event = calendarEvent(input, item)\n const title = event.preview.kind === 'event' ? event.preview.title : undefined\n return { ...event, action: 'Update event', title: title ? `Update “${clipped(title, 60)}”` : 'Update an event' }\n },\n 'microsoft-calendar.book_slot': calendarEvent,\n}\n\n/** A held call in the owner's words, with the preview its integration renders. */\nexport function presentHubAction(item: Pick<HubApprovalItem, 'actionPath' | 'providerId' | 'input' | 'files' | 'bundle' | 'preview'>): HubActionPresentation {\n const { provider: pathProvider, action } = splitHubActionPath(item.actionPath)\n const providerId = item.providerId || pathProvider\n const provider = { id: providerId, name: hubProviderName(providerId) }\n const input = asRecord(item.input)\n const known = PRESENTERS[item.actionPath]\n const presented = known\n ? known(input, item)\n : (() => {\n const { verb, noun } = genericVerb(action)\n const phrase = sentence(verb, noun) || action\n const object = text(input.name) ?? text(input.title) ?? text(input.subject) ?? text(input.label)\n return {\n action: phrase,\n title: object ? `${phrase} “${clipped(object, 60)}”` : phrase,\n preview: { kind: 'fields', fields: scalarFields(input) } as HubActionPreview,\n }\n })()\n return { provider, ...presented, ...(item.preview ? { preview: item.preview } : {}), ...(item.bundle ? { title: item.bundle.title } : {}) }\n}\n\n// ---------- receipts ----------\n\nfunction prField(result: Record<string, unknown>): HubActionField | undefined {\n const pull = asRecord(result.pullRequest)\n const number = readNumber(pull, 'number') ?? readNumber(result, 'number')\n if (number === undefined) return undefined\n return { label: 'Pull request', value: `#${number}`, href: resultLink(pull) ?? resultLink(result) }\n}\n\nfunction receiptTitle(item: HubApprovalItem, presentation: HubActionPresentation, result: Record<string, unknown>): string {\n const { action } = splitHubActionPath(item.actionPath)\n const input = asRecord(item.input)\n const pull = asRecord(result.pullRequest)\n const number = readNumber(pull, 'number') ?? readNumber(result, 'number')\n switch (item.actionPath) {\n case 'github.pulls.propose':\n case 'github.pulls.create':\n return number !== undefined ? `Opened PR #${number}` : 'Opened pull request'\n case 'github.git.createCommit': {\n const sha = shortSha(readText(result, 'sha'))\n return sha ? `Created commit ${sha}` : 'Created commit'\n }\n case 'github.git.createTree': {\n const files = hubActionFiles(item.actionPath, input).length\n return `Wrote ${files === 1 ? '1 file' : `${files} files`}`\n }\n case 'github.git.createRef':\n return `Created branch ${branchOf(readText(result, 'ref') ?? input.ref) ?? ''}`.trim()\n case 'github.issues.create':\n return number !== undefined ? `Opened issue #${number}` : 'Opened issue'\n case 'github.issues.createComment': {\n const on = readNumber(input, 'issue_number')\n return on !== undefined ? `Commented on #${on}` : 'Commented'\n }\n case 'github.pulls.reviews.create': {\n const on = readNumber(input, 'pull_number')\n return on !== undefined ? `Reviewed PR #${on}` : 'Reviewed pull request'\n }\n case 'github.pulls.merge': {\n const on = readNumber(input, 'pull_number')\n return on !== undefined ? `Merged PR #${on}` : 'Merged pull request'\n }\n case 'phony.synthesize_speech':\n return 'Created voice memo'\n }\n if (presentation.preview.kind === 'email') {\n const to = people(presentation.preview.to)\n if (presentation.preview.reply) return 'Sent reply'\n return action.includes('draft') && !action.startsWith('send') ? `Saved draft${to ? ` to ${to}` : ''}` : `Sent email${to ? ` to ${to}` : ''}`\n }\n if (presentation.preview.kind === 'post') {\n return presentation.preview.channel === 'slack' ? `Posted in ${presentation.preview.where ?? 'Slack'}` : `Posted on ${presentation.target ?? presentation.provider.name}`\n }\n if (presentation.preview.kind === 'event') {\n const verb = presentation.action === 'Update event' ? 'Updated' : 'Booked'\n return presentation.preview.title ? `${verb} “${clipped(presentation.preview.title, 60)}”` : `${verb} event`\n }\n if (presentation.preview.kind === 'call') return presentation.preview.to ? `Started call to ${presentation.preview.to}` : 'Started call'\n const [first = '', ...rest] = presentation.action.split(' ')\n return [pastTense(first), ...rest].join(' ')\n}\n\nfunction postLink(item: HubApprovalItem, result: Record<string, unknown>): string | undefined {\n const id = readText(result, 'id', 'urn', 'postUrn')\n if (!id) return resultLink(result)\n if (item.providerId === 'twitter' || item.providerId === 'x') return /^\\d+$/.test(id) ? `https://x.com/i/web/status/${id}` : resultLink(result)\n if (item.providerId === 'linkedin') return id.startsWith('urn:li:') ? `https://www.linkedin.com/feed/update/${id}/` : resultLink(result)\n return resultLink(result)\n}\n\nfunction receiptFields(item: HubApprovalItem, presentation: HubActionPresentation, result: Record<string, unknown>): HubActionField[] {\n const fields: HubActionField[] = []\n const preview = presentation.preview\n switch (preview.kind) {\n case 'pull-request': {\n const pr = prField(result)\n if (pr) fields.push(pr)\n const head = readText(result, 'branch') ?? preview.head\n const base = readText(result, 'base') ?? preview.base\n if (head && base) fields.push({ label: 'Branch', value: `${head} → ${base}`, mono: true })\n const commit = asRecord(result.commit)\n const sha = readText(commit, 'sha')\n if (sha) fields.push({ label: 'Commit', value: shortSha(sha)!, href: resultLink(commit), mono: true })\n const repo = readText(result, 'repository') ?? preview.repository\n if (repo) fields.push({ label: 'Repository', value: repo, href: `https://github.com/${repo}` })\n return fields\n }\n case 'commit': {\n const sha = readText(result, 'sha')\n if (sha) fields.push({ label: 'Commit', value: shortSha(sha)!, href: resultLink(result)?.includes('api.github.com') ? undefined : resultLink(result), mono: true })\n if (preview.message) fields.push({ label: 'Message', value: clipped(preview.message, 120) })\n return fields\n }\n case 'branch': {\n const branch = branchOf(readText(result, 'ref')) ?? preview.branch\n if (branch && preview.repository) fields.push({ label: 'Branch', value: branch, href: `https://github.com/${preview.repository}/tree/${branch}`, mono: true })\n return fields\n }\n case 'files': {\n const sha = readText(result, 'sha')\n if (sha) fields.push({ label: 'Tree', value: shortSha(sha)!, mono: true })\n return fields\n }\n case 'email': {\n if (preview.subject) fields.push({ label: 'Subject', value: clipped(preview.subject, 120) })\n if (preview.cc.length) fields.push({ label: 'Cc', value: preview.cc.join(', ') })\n return fields\n }\n case 'payment': {\n const amount = readNumber(result, 'amount', 'amount_total', 'total') ?? preview.amount\n const currency = readText(result, 'currency') ?? preview.currency\n if (amount !== undefined) fields.push({ label: 'Amount', value: formatMinorAmount(amount, currency) })\n const customer = readText(result, 'customer_email', 'customer') ?? preview.customer\n if (customer) fields.push({ label: 'Customer', value: customer, mono: customer.startsWith('cus_') })\n const status = readText(result, 'status')\n if (status) fields.push({ label: 'Status', value: status })\n return fields\n }\n case 'speech': {\n const seconds = readNumber(result, 'durationSeconds', 'duration')\n if (seconds !== undefined) fields.push({ label: 'Length', value: `${Math.round(seconds * 10) / 10} s` })\n if (preview.voice) fields.push({ label: 'Voice', value: preview.voice })\n return fields\n }\n case 'event': {\n if (preview.start) fields.push({ label: 'When', value: formatWhen(preview.start, preview.end) })\n if (preview.attendees.length) fields.push({ label: 'Guests', value: people(preview.attendees) })\n return fields\n }\n case 'call': {\n const status = readText(asRecord(result.call), 'status') ?? readText(result, 'status')\n if (status) fields.push({ label: 'Status', value: status })\n return fields\n }\n default: {\n const id = readText(result, 'id', 'number', 'key')\n if (id) fields.push({ label: 'ID', value: id, mono: true })\n const status = readText(result, 'status', 'state')\n if (status) fields.push({ label: 'Status', value: status })\n const name = readText(result, 'name', 'title')\n if (name) fields.push({ label: 'Name', value: clipped(name, 80) })\n return fields\n }\n }\n}\n\n/** A start and optional end in the viewer's locale: `Tue, Oct 14, 3:00 – 3:30 PM`. */\nexport function formatWhen(start: string, end?: string): string {\n const from = new Date(start)\n if (Number.isNaN(from.getTime())) return end ? `${start} – ${end}` : start\n const day = from.toLocaleDateString(undefined, { weekday: 'short', month: 'short', day: 'numeric' })\n const time = (date: Date) => date.toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit' })\n const to = end ? new Date(end) : null\n if (!to || Number.isNaN(to.getTime())) return `${day}, ${time(from)}`\n return to.toDateString() === from.toDateString() ? `${day}, ${time(from)} – ${time(to)}` : `${day}, ${time(from)} – ${to.toLocaleDateString(undefined, { month: 'short', day: 'numeric' })}, ${time(to)}`\n}\n\nfunction receiptFiles(result: Record<string, unknown>): HubActionFile[] | undefined {\n if (!Array.isArray(result.files)) return undefined\n return result.files.flatMap((entry): HubActionFile[] => {\n const file = asRecord(entry)\n const path = text(file.path) ?? text(file.filename)\n if (!path) return []\n const status = text(file.status)\n const change = status === 'added' ? 'added' : status === 'removed' || status === 'deleted' ? 'deleted' : 'modified'\n return [{ path, change, additions: readNumber(file, 'additions'), deletions: readNumber(file, 'deletions') }]\n })\n}\n\n/** What a decided call did: its past-tense title, key fields, link, media and files. */\nexport function hubActionReceipt(item: HubApprovalItem): HubActionReceipt {\n const presentation = presentHubAction(item)\n const result = asRecord(unwrapHubResult(item.result))\n const status: HubActionReceipt['status'] = item.phase === 'done' || item.phase === 'unknown' || item.phase === 'failed' || item.phase === 'denied' || item.phase === 'expired'\n ? item.phase\n : item.phase === 'queued' || item.phase === 'running' ? 'running' : 'waiting'\n const base = { provider: presentation.provider, status }\n if (status === 'denied') return { ...base, title: `Denied: ${presentation.title}`, fields: [] }\n if (status === 'expired') return { ...base, title: `Expired: ${presentation.title}`, fields: [] }\n if (status === 'unknown') return { ...base, title: `May have run: ${presentation.title}`, fields: [], warning: HUB_APPROVAL_UNKNOWN_WARNING }\n if (status === 'failed') return { ...base, title: `Could not ${presentation.action.charAt(0).toLowerCase()}${presentation.action.slice(1)}`, fields: [], ...(item.error ? { error: item.error } : {}) }\n if (status !== 'done') return { ...base, title: presentation.title, fields: [] }\n const title = receiptTitle(item, presentation, result)\n const fields = receiptFields(item, presentation, result)\n const pull = asRecord(result.pullRequest)\n const href = presentation.preview.kind === 'post'\n ? postLink(item, result)\n : resultLink(pull) ?? (item.actionPath.startsWith('github.git.') ? undefined : resultLink(result))\n const audio = readText(result, 'audioUrl')\n const seconds = readNumber(result, 'durationSeconds', 'duration')\n const files = receiptFiles(result)\n return {\n ...base,\n title,\n ...(href ? { href } : {}),\n fields,\n ...(files && files.length ? { files } : {}),\n ...(audio && /^https:\\/\\//.test(audio) ? { media: { kind: 'audio' as const, src: audio, ...(seconds !== undefined ? { seconds } : {}) } } : {}),\n }\n}\n","/**\n * `./hub-approvals` — Hub actions that wait on a person, in the owner's words.\n *\n * Pure and browser-safe: a host maps its held calls into {@link HubApprovalItem}s\n * and every surface — the approval dock above the composer, the Approvals list\n * beside the conversation, and the receipts in the transcript — renders the\n * same presentation from them. Servers use {@link summarizeHubResult} to store\n * a bounded result with the decision.\n */\n\nimport type { HubApprovalPhase } from './types'\n\nexport * from './types'\nexport {\n formatMinorAmount,\n formatWhen,\n hubActionFiles,\n hubActionReceipt,\n hubProviderName,\n pastTense,\n presentHubAction,\n splitHubActionPath,\n} from './present'\nexport { summarizeHubResult, unwrapHubResult } from './result'\n\n/** A phase as a status label. */\nexport const HUB_APPROVAL_PHASE_LABELS: Record<HubApprovalPhase, string> = {\n waiting: 'Waiting for you',\n blocked: 'Waiting for the owner',\n queued: 'Queued',\n running: 'Running',\n done: 'Done',\n failed: 'Failed',\n unknown: 'May have run',\n denied: 'Denied',\n expired: 'Expired',\n}\n\n/**\n * The part type marking a user message that resumes the agent after a\n * decision. The message's text goes to the agent unchanged; a transcript\n * renders the decided actions' receipts in its place, never a chat bubble.\n */\nexport const HUB_APPROVAL_RESUME_PART = 'hub-approval-resume'\n\nexport interface HubApprovalResumePart {\n type: typeof HUB_APPROVAL_RESUME_PART\n /** The assistant message whose held calls this resume reports. */\n messageId: string\n}\n\n/** The resume marker among a message's parts, if it carries one. */\nexport function hubApprovalResumePart(parts: ReadonlyArray<Record<string, unknown>> | null | undefined): HubApprovalResumePart | null {\n for (const part of parts ?? []) {\n if (part?.type === HUB_APPROVAL_RESUME_PART && typeof part.messageId === 'string' && part.messageId) {\n return { type: HUB_APPROVAL_RESUME_PART, messageId: part.messageId }\n }\n }\n return null\n}\n"],"mappings":"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","names":["text","words","url"]}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ToolInputError,
3
3
  validateOpenUIJsonNode
4
- } from "./chunk-7PSYT35Z.js";
4
+ } from "./chunk-7BYY7QKC.js";
5
5
 
6
6
  // src/tools/render-ui-schema.ts
7
7
  function assertRenderUiSchema(value) {
@@ -14,4 +14,4 @@ function assertRenderUiSchema(value) {
14
14
  export {
15
15
  assertRenderUiSchema
16
16
  };
17
- //# sourceMappingURL=chunk-NO2YNV5C.js.map
17
+ //# sourceMappingURL=chunk-YXLN4PXK.js.map
@@ -14,7 +14,7 @@ import {
14
14
  splitHubActionPath,
15
15
  summarizeHubResult,
16
16
  unwrapHubResult
17
- } from "../chunk-CPNJRLPN.js";
17
+ } from "../chunk-WSEXFTN4.js";
18
18
  export {
19
19
  HUB_APPROVAL_ACTIVE_PHASES,
20
20
  HUB_APPROVAL_OPEN_PHASES,
@@ -105,6 +105,15 @@ export interface HubActionField {
105
105
  /** Render in the monospace face: shas, ids, paths. */
106
106
  mono?: boolean;
107
107
  }
108
+ /** Frozen media bytes supplied by the host; renderers never resolve a provider URL. */
109
+ export interface HubPreviewMedia {
110
+ kind: 'image' | 'video';
111
+ src: string;
112
+ alt: string;
113
+ poster?: string;
114
+ width?: number;
115
+ height?: number;
116
+ }
108
117
  /** What a held call will do, shaped for its integration's renderer. */
109
118
  export type HubActionPreview = {
110
119
  kind: 'pull-request';
@@ -151,7 +160,7 @@ export type HubActionPreview = {
151
160
  reply: boolean;
152
161
  } | {
153
162
  kind: 'post';
154
- channel: 'x' | 'linkedin' | 'slack';
163
+ channel: 'x' | 'linkedin' | 'slack' | 'instagram' | 'facebook' | 'tiktok' | 'youtube';
155
164
  text: string;
156
165
  /** The post's place, such as a Slack channel. */
157
166
  where?: string;
@@ -164,6 +173,12 @@ export type HubActionPreview = {
164
173
  url: string;
165
174
  alt?: string;
166
175
  }[];
176
+ media?: readonly HubPreviewMedia[];
177
+ placement?: 'feed' | 'vertical' | 'carousel';
178
+ sponsored?: boolean;
179
+ displayName?: string;
180
+ handle?: string;
181
+ callToAction?: string;
167
182
  } | {
168
183
  kind: 'ad';
169
184
  placement: string;
@@ -1,11 +1,11 @@
1
- import { type HubApprovalFeedback, type HubApprovalItem } from '../hub-approvals';
1
+ import { type HubActionPreview, type HubApprovalFeedback, type HubApprovalItem } from '../hub-approvals';
2
2
  export interface HubPreviewFeedbackProps {
3
3
  item: HubApprovalItem;
4
4
  onFeedback: (item: HubApprovalItem, feedback: HubApprovalFeedback) => Promise<void>;
5
5
  /** Owner-local drafts survive collapsing/switching previews, never another viewer. */
6
- drafts?: Map<string, FeedbackDraft>;
6
+ drafts?: Map<string, ReviewFeedbackDraft>;
7
7
  }
8
- interface FeedbackDraft {
8
+ export interface ReviewFeedbackDraft {
9
9
  score: string;
10
10
  comment: string;
11
11
  editing: boolean;
@@ -15,6 +15,26 @@ interface FeedbackDraft {
15
15
  payload: string;
16
16
  saved: boolean;
17
17
  }
18
- /** Host callback saves the signal; this component has no execution transport. */
18
+ export type ReviewVerdict = 'approve' | 'reject' | 'request_changes';
19
+ export interface ReviewFeedbackFormHandle {
20
+ focusScore: () => void;
21
+ focusComment: () => void;
22
+ submitVerdict: (verdict: ReviewVerdict) => Promise<void>;
23
+ }
24
+ export interface ReviewFeedbackFormProps {
25
+ input: unknown;
26
+ preview?: HubActionPreview;
27
+ feedback?: HubApprovalFeedback;
28
+ draftKey: string;
29
+ drafts?: Map<string, ReviewFeedbackDraft>;
30
+ onFeedback?: (feedback: HubApprovalFeedback) => Promise<void>;
31
+ onVerdict?: (verdict: ReviewVerdict, feedback: HubApprovalFeedback) => Promise<void>;
32
+ allowedVerdicts?: readonly ReviewVerdict[];
33
+ approveLabel?: string;
34
+ disabled?: boolean;
35
+ editNote?: string;
36
+ }
37
+ /** One form for Hub previews, assets and work products. Hosts own storage and authority. */
38
+ export declare const ReviewFeedbackForm: import("react").ForwardRefExoticComponent<ReviewFeedbackFormProps & import("react").RefAttributes<ReviewFeedbackFormHandle>>;
39
+ /** Existing Hub adapter: teaching never calls the effect transport. */
19
40
  export declare function HubPreviewFeedback({ item, onFeedback, drafts }: HubPreviewFeedbackProps): import("react").JSX.Element;
20
- export {};
@@ -19,5 +19,6 @@ export { HubApprovalsList, type HubApprovalsListProps } from './list';
19
19
  export { HubApprovalRow, type HubApprovalRowProps } from './row';
20
20
  export { HubActionReceiptCard, HubApprovalReceipts, type HubActionReceiptCardProps, type HubApprovalReceiptsProps } from './receipt';
21
21
  export { HubActionPreviewView } from './preview';
22
+ export { ReviewFeedbackForm, type ReviewFeedbackFormProps, type ReviewFeedbackFormHandle, type ReviewFeedbackDraft, type ReviewVerdict } from './feedback';
22
23
  export { HubPreviewFeedback, type HubPreviewFeedbackProps } from './feedback';
23
24
  export { HubApprovalPhasePill, HubApprovalWaitNote, HubProviderMark, openPhaseLabel } from './parts';