@tangle-network/agent-app 0.60.176 → 0.60.178
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.
- package/dist/agent-profiles/d1.js +1 -1
- package/dist/agent-profiles/index.js +9 -1
- package/dist/agent-profiles/self-management.d.ts +82 -0
- package/dist/{chunk-6VXBUIM5.js → chunk-ARBBJWZA.js} +63 -6
- package/dist/{chunk-6VXBUIM5.js.map → chunk-ARBBJWZA.js.map} +1 -1
- package/dist/{chunk-MCAIZKQ5.js → chunk-CPNJRLPN.js} +15 -4
- package/dist/chunk-CPNJRLPN.js.map +1 -0
- package/dist/hub-approvals/index.js +1 -1
- package/dist/hub-approvals/present.d.ts +1 -1
- package/dist/hub-approvals/types.d.ts +35 -0
- package/dist/hub-approvals-react/dock.d.ts +3 -2
- package/dist/hub-approvals-react/email.d.ts +13 -0
- package/dist/hub-approvals-react/feedback.d.ts +20 -0
- package/dist/hub-approvals-react/index.d.ts +1 -0
- package/dist/hub-approvals-react/index.js +535 -286
- package/dist/hub-approvals-react/index.js.map +1 -1
- package/dist/hub-approvals-react/parts.d.ts +1 -1
- package/dist/hub-approvals-react/row.d.ts +3 -2
- package/package.json +1 -1
- package/dist/chunk-MCAIZKQ5.js.map +0 -1
|
@@ -249,13 +249,19 @@ function mergedFiles(declared, counted) {
|
|
|
249
249
|
return declared.map((file) => byPath.get(file.path) ?? file);
|
|
250
250
|
}
|
|
251
251
|
function emailPreview(input, reply) {
|
|
252
|
+
const from = asRecord(input.from);
|
|
253
|
+
const htmlBody = typeof input.html === "string" ? input.html : void 0;
|
|
252
254
|
return {
|
|
253
255
|
kind: "email",
|
|
254
256
|
to: list(input.to ?? input.recipients),
|
|
255
257
|
cc: list(input.cc),
|
|
256
258
|
bcc: list(input.bcc),
|
|
257
259
|
subject: text(input.subject),
|
|
258
|
-
|
|
260
|
+
from: text(input.from) ?? text(from.email) ?? text(from.address),
|
|
261
|
+
fromName: text(input.fromName) ?? text(input.from_name) ?? text(from.name),
|
|
262
|
+
previewText: text(input.previewText) ?? text(input.preview_text) ?? text(input.preheader),
|
|
263
|
+
// The payload is evidence: retain whitespace and prefer the actual HTML part.
|
|
264
|
+
body: htmlBody ?? [input.body, input.text, input.comment].find((value) => typeof value === "string"),
|
|
259
265
|
html: input.html === true || text(input.bodyType)?.toLowerCase() === "html" || typeof input.html === "string",
|
|
260
266
|
reply
|
|
261
267
|
};
|
|
@@ -349,7 +355,7 @@ function sendEmail(verb, reply = false) {
|
|
|
349
355
|
}
|
|
350
356
|
function post(channel, reply = false) {
|
|
351
357
|
return (input) => {
|
|
352
|
-
const body = text
|
|
358
|
+
const body = typeof input.text === "string" ? input.text : typeof input.commentary === "string" ? input.commentary : "";
|
|
353
359
|
const url = text(input.url);
|
|
354
360
|
const where = channel === "x" ? "X" : "LinkedIn";
|
|
355
361
|
return {
|
|
@@ -360,6 +366,11 @@ function post(channel, reply = false) {
|
|
|
360
366
|
kind: "post",
|
|
361
367
|
channel,
|
|
362
368
|
text: body,
|
|
369
|
+
images: (Array.isArray(input.images) ? input.images : input.image ? [input.image] : []).flatMap((image) => {
|
|
370
|
+
const record = asRecord(image);
|
|
371
|
+
const url2 = text(image) ?? text(record.url);
|
|
372
|
+
return url2 ? [{ url: url2, alt: text(record.alt) }] : [];
|
|
373
|
+
}),
|
|
363
374
|
...url ? { link: { url, title: text(input.title), description: text(input.description) } } : {}
|
|
364
375
|
}
|
|
365
376
|
};
|
|
@@ -534,7 +545,7 @@ function presentHubAction(item) {
|
|
|
534
545
|
preview: { kind: "fields", fields: scalarFields(input) }
|
|
535
546
|
};
|
|
536
547
|
})();
|
|
537
|
-
return { provider, ...presented, ...item.bundle ? { title: item.bundle.title } : {} };
|
|
548
|
+
return { provider, ...presented, ...item.preview ? { preview: item.preview } : {}, ...item.bundle ? { title: item.bundle.title } : {} };
|
|
538
549
|
}
|
|
539
550
|
function prField(result) {
|
|
540
551
|
const pull = asRecord(result.pullRequest);
|
|
@@ -763,4 +774,4 @@ export {
|
|
|
763
774
|
HUB_APPROVAL_RESUME_PART,
|
|
764
775
|
hubApprovalResumePart
|
|
765
776
|
};
|
|
766
|
-
//# sourceMappingURL=chunk-
|
|
777
|
+
//# sourceMappingURL=chunk-CPNJRLPN.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/** 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'\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 }\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} 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}\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', reply = false): Presenter {\n return (input) => {\n const body = typeof input.text === 'string' ? input.text : typeof input.commentary === 'string' ? input.commentary : ''\n const url = text(input.url)\n const where = channel === 'x' ? 'X' : 'LinkedIn'\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 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.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 '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"]}
|
|
@@ -19,7 +19,7 @@ export declare function hubActionFiles(actionPath: string, input: unknown): HubA
|
|
|
19
19
|
/** A Stripe minor-unit amount in its currency: `4900` USD is `$49.00`. */
|
|
20
20
|
export declare function formatMinorAmount(amount: number, currency?: string): string;
|
|
21
21
|
/** A held call in the owner's words, with the preview its integration renders. */
|
|
22
|
-
export declare function presentHubAction(item: Pick<HubApprovalItem, 'actionPath' | 'providerId' | 'input' | 'files' | 'bundle'>): HubActionPresentation;
|
|
22
|
+
export declare function presentHubAction(item: Pick<HubApprovalItem, 'actionPath' | 'providerId' | 'input' | 'files' | 'bundle' | 'preview'>): HubActionPresentation;
|
|
23
23
|
/** A start and optional end in the viewer's locale: `Tue, Oct 14, 3:00 – 3:30 PM`. */
|
|
24
24
|
export declare function formatWhen(start: string, end?: string): string;
|
|
25
25
|
/** What a decided call did: its past-tense title, key fields, link, media and files. */
|
|
@@ -82,6 +82,20 @@ export interface HubApprovalItem {
|
|
|
82
82
|
/** Files with line counts read by the host, replacing those the input declares. */
|
|
83
83
|
files?: readonly HubActionFile[];
|
|
84
84
|
bundle?: HubActionBundle | null;
|
|
85
|
+
/** Previewing and teaching never execute a call. Live approval remains a separate action. */
|
|
86
|
+
executionMode?: 'dry-run' | 'live';
|
|
87
|
+
feedback?: HubApprovalFeedback & {
|
|
88
|
+
savedAt?: string;
|
|
89
|
+
};
|
|
90
|
+
/** Host-resolved presentation, e.g. a retained page screenshot or ad creative. No remote fetches. */
|
|
91
|
+
preview?: HubActionPreview;
|
|
92
|
+
}
|
|
93
|
+
/** The host authenticates the reviewer, binds provenance and computes the edit diff. */
|
|
94
|
+
export interface HubApprovalFeedback {
|
|
95
|
+
score: number;
|
|
96
|
+
comment: string;
|
|
97
|
+
/** A teaching example only; never replaces the held input or authorizes execution. */
|
|
98
|
+
editedInput?: unknown;
|
|
85
99
|
}
|
|
86
100
|
/** A labelled value on a preview or a receipt. */
|
|
87
101
|
export interface HubActionField {
|
|
@@ -129,6 +143,9 @@ export type HubActionPreview = {
|
|
|
129
143
|
cc: readonly string[];
|
|
130
144
|
bcc: readonly string[];
|
|
131
145
|
subject?: string;
|
|
146
|
+
from?: string;
|
|
147
|
+
fromName?: string;
|
|
148
|
+
previewText?: string;
|
|
132
149
|
body?: string;
|
|
133
150
|
html: boolean;
|
|
134
151
|
reply: boolean;
|
|
@@ -143,6 +160,24 @@ export type HubActionPreview = {
|
|
|
143
160
|
title?: string;
|
|
144
161
|
description?: string;
|
|
145
162
|
};
|
|
163
|
+
images?: readonly {
|
|
164
|
+
url: string;
|
|
165
|
+
alt?: string;
|
|
166
|
+
}[];
|
|
167
|
+
} | {
|
|
168
|
+
kind: 'ad';
|
|
169
|
+
placement: string;
|
|
170
|
+
advertiser?: string;
|
|
171
|
+
headline?: string;
|
|
172
|
+
text?: string;
|
|
173
|
+
image?: string;
|
|
174
|
+
destination?: string;
|
|
175
|
+
callToAction?: string;
|
|
176
|
+
} | {
|
|
177
|
+
kind: 'page';
|
|
178
|
+
title?: string;
|
|
179
|
+
url?: string;
|
|
180
|
+
screenshot?: string;
|
|
146
181
|
} | {
|
|
147
182
|
kind: 'payment';
|
|
148
183
|
label: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type HubApprovalItem } from '../hub-approvals';
|
|
1
|
+
import { type HubApprovalItem, type HubApprovalFeedback } from '../hub-approvals';
|
|
2
2
|
/** The owner's answer to one held call. `allow` also grants a standing permission. */
|
|
3
3
|
export type HubApprovalDecision = {
|
|
4
4
|
kind: 'approve';
|
|
@@ -29,6 +29,7 @@ export interface HubApprovalDockProps {
|
|
|
29
29
|
/** Bring one call to the front, e.g. after it was picked in the Approvals list. */
|
|
30
30
|
focusId?: string | null;
|
|
31
31
|
className?: string;
|
|
32
|
+
onFeedback?: (item: HubApprovalItem, feedback: HubApprovalFeedback) => Promise<void>;
|
|
32
33
|
}
|
|
33
34
|
/**
|
|
34
35
|
* The calls waiting on the owner, pinned above the composer so a held action
|
|
@@ -37,4 +38,4 @@ export interface HubApprovalDockProps {
|
|
|
37
38
|
* permissions a host offers sit beside it. Approving shows the run in place —
|
|
38
39
|
* starting, running, then the result — without leaving the conversation.
|
|
39
40
|
*/
|
|
40
|
-
export declare function HubApprovalDock({ items, onDecide, permissions, onOpen, focusId, className }: HubApprovalDockProps): import("react").JSX.Element | null;
|
|
41
|
+
export declare function HubApprovalDock({ items, onDecide, permissions, onOpen, focusId, onFeedback, className }: HubApprovalDockProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { HubActionPreview } from '../hub-approvals';
|
|
2
|
+
type Email = Extract<HubActionPreview, {
|
|
3
|
+
kind: 'email';
|
|
4
|
+
}>;
|
|
5
|
+
/** Only embedded raster images: opening a preview must not contact a tracking pixel. */
|
|
6
|
+
export declare function embeddedPreviewImage(value: string | undefined): string | undefined;
|
|
7
|
+
/** Transport-free inbox rendering. No provider SDK, remote images or executable HTML. */
|
|
8
|
+
export declare function EmailPreview({ preview, account }: {
|
|
9
|
+
preview: Email;
|
|
10
|
+
account?: string | null;
|
|
11
|
+
}): import("react").JSX.Element;
|
|
12
|
+
export declare function linkedText(value: string): (string | import("react").JSX.Element)[];
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type HubApprovalFeedback, type HubApprovalItem } from '../hub-approvals';
|
|
2
|
+
export interface HubPreviewFeedbackProps {
|
|
3
|
+
item: HubApprovalItem;
|
|
4
|
+
onFeedback: (item: HubApprovalItem, feedback: HubApprovalFeedback) => Promise<void>;
|
|
5
|
+
/** Owner-local drafts survive collapsing/switching previews, never another viewer. */
|
|
6
|
+
drafts?: Map<string, FeedbackDraft>;
|
|
7
|
+
}
|
|
8
|
+
interface FeedbackDraft {
|
|
9
|
+
score: string;
|
|
10
|
+
comment: string;
|
|
11
|
+
editing: boolean;
|
|
12
|
+
edited: boolean;
|
|
13
|
+
subject: string;
|
|
14
|
+
body: string;
|
|
15
|
+
payload: string;
|
|
16
|
+
saved: boolean;
|
|
17
|
+
}
|
|
18
|
+
/** Host callback saves the signal; this component has no execution transport. */
|
|
19
|
+
export declare function HubPreviewFeedback({ item, onFeedback, drafts }: HubPreviewFeedbackProps): import("react").JSX.Element;
|
|
20
|
+
export {};
|
|
@@ -19,4 +19,5 @@ 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 { HubPreviewFeedback, type HubPreviewFeedbackProps } from './feedback';
|
|
22
23
|
export { HubApprovalPhasePill, HubApprovalWaitNote, HubProviderMark, openPhaseLabel } from './parts';
|