@elizaos/plugin-finances 2.0.3-beta.5 → 2.0.3-beta.7
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/actions/finances.d.ts +38 -0
- package/dist/actions/finances.d.ts.map +1 -0
- package/dist/actions/finances.js +368 -0
- package/dist/actions/finances.js.map +1 -0
- package/dist/components/finances/FinancesSpatialView.d.ts +80 -0
- package/dist/components/finances/FinancesSpatialView.d.ts.map +1 -0
- package/dist/components/finances/FinancesSpatialView.js +157 -0
- package/dist/components/finances/FinancesSpatialView.js.map +1 -0
- package/dist/components/finances/FinancesView.d.ts +97 -0
- package/dist/components/finances/FinancesView.d.ts.map +1 -0
- package/dist/components/finances/FinancesView.js +231 -0
- package/dist/components/finances/FinancesView.js.map +1 -0
- package/dist/components/finances/finances-view-bundle.d.ts +10 -0
- package/dist/components/finances/finances-view-bundle.d.ts.map +1 -0
- package/dist/components/finances/finances-view-bundle.js +5 -0
- package/dist/components/finances/finances-view-bundle.js.map +1 -0
- package/dist/db/finances-repository.d.ts +51 -0
- package/dist/db/finances-repository.d.ts.map +1 -0
- package/dist/db/finances-repository.js +521 -0
- package/dist/db/finances-repository.js.map +1 -0
- package/dist/db/index.d.ts +3 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +6 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/schema.d.ts +2615 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +133 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/db/sql.d.ts +65 -0
- package/dist/db/sql.d.ts.map +1 -0
- package/dist/db/sql.js +182 -0
- package/dist/db/sql.js.map +1 -0
- package/dist/finance-normalize.d.ts +24 -0
- package/dist/finance-normalize.d.ts.map +1 -0
- package/dist/finance-normalize.js +66 -0
- package/dist/finance-normalize.js.map +1 -0
- package/dist/finances-service.d.ts +179 -0
- package/dist/finances-service.d.ts.map +1 -0
- package/dist/finances-service.js +1122 -0
- package/dist/finances-service.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +109 -0
- package/dist/index.js.map +1 -0
- package/dist/payment-csv-import.d.ts +23 -0
- package/dist/payment-csv-import.d.ts.map +1 -0
- package/dist/payment-csv-import.js +271 -0
- package/dist/payment-csv-import.js.map +1 -0
- package/dist/payment-recurrence.d.ts +14 -0
- package/dist/payment-recurrence.d.ts.map +1 -0
- package/dist/payment-recurrence.js +190 -0
- package/dist/payment-recurrence.js.map +1 -0
- package/dist/payment-types.d.ts +158 -0
- package/dist/payment-types.d.ts.map +1 -0
- package/dist/payment-types.js +1 -0
- package/dist/payment-types.js.map +1 -0
- package/dist/plugin.d.ts +15 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +31 -0
- package/dist/plugin.js.map +1 -0
- package/dist/register-terminal-view.d.ts +15 -0
- package/dist/register-terminal-view.d.ts.map +1 -0
- package/dist/register-terminal-view.js +21 -0
- package/dist/register-terminal-view.js.map +1 -0
- package/dist/register.d.ts +9 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +5 -0
- package/dist/register.js.map +1 -0
- package/dist/services/browser-bridge-seam.d.ts +40 -0
- package/dist/services/browser-bridge-seam.d.ts.map +1 -0
- package/dist/services/browser-bridge-seam.js +39 -0
- package/dist/services/browser-bridge-seam.js.map +1 -0
- package/dist/services/gmail-seam.d.ts +40 -0
- package/dist/services/gmail-seam.d.ts.map +1 -0
- package/dist/services/gmail-seam.js +208 -0
- package/dist/services/gmail-seam.js.map +1 -0
- package/dist/services/migration.d.ts +65 -0
- package/dist/services/migration.d.ts.map +1 -0
- package/dist/services/migration.js +116 -0
- package/dist/services/migration.js.map +1 -0
- package/dist/services/subscriptions-service.d.ts +76 -0
- package/dist/services/subscriptions-service.d.ts.map +1 -0
- package/dist/services/subscriptions-service.js +1002 -0
- package/dist/services/subscriptions-service.js.map +1 -0
- package/dist/subscriptions-playbooks.d.ts +79 -0
- package/dist/subscriptions-playbooks.d.ts.map +1 -0
- package/dist/subscriptions-playbooks.js +871 -0
- package/dist/subscriptions-playbooks.js.map +1 -0
- package/dist/subscriptions-types.d.ts +80 -0
- package/dist/subscriptions-types.d.ts.map +1 -0
- package/dist/subscriptions-types.js +1 -0
- package/dist/subscriptions-types.js.map +1 -0
- package/dist/token-encryption.d.ts +42 -0
- package/dist/token-encryption.d.ts.map +1 -0
- package/dist/token-encryption.js +96 -0
- package/dist/token-encryption.js.map +1 -0
- package/dist/types.d.ts +55 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +18 -0
- package/dist/types.js.map +1 -0
- package/dist/views/bundle.js +411 -0
- package/dist/views/bundle.js.map +1 -0
- package/package.json +11 -11
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/services/subscriptions-service.ts"],"sourcesContent":["/**\n * SubscriptionsService — the subscription audit / cancellation back-end.\n *\n * Standalone successor to plugin-personal-assistant's `withSubscriptions`\n * LifeOps mixin. It holds its own runtime + {@link FinancesRepository} (the\n * finance/subscription tables already live in `app_finances`) and reaches the\n * cross-domain surfaces it needs through runtime-service seams rather than PA\n * internals:\n *\n * - **Gmail** ({@link SubscriptionsGmailGateway}) — date-windowed owner Gmail\n * search via `@elizaos/plugin-google`, for subscription-evidence discovery.\n * - **Browser bridge** ({@link SubscriptionsBrowserGateway}) — companion list\n * + session create/poll via the `lifeops_browser_plugin` runtime service\n * contract owned by `@elizaos/plugin-browser`, for `user_browser`\n * cancellation.\n * - **computer-use** — the `computeruse` runtime service, for `agent_browser`\n * cancellation playback.\n *\n * Behavior and the data it returns are preserved verbatim from the original\n * mixin. This service carries no dependency on\n * `@elizaos/plugin-personal-assistant`.\n */\n\nimport { type IAgentRuntime, logger } from \"@elizaos/core\";\nimport {\n BROWSER_SERVICE_TYPE,\n type BrowserBridgeAction,\n type BrowserService,\n type BrowserWorkspaceCommand,\n type BrowserWorkspaceCommandResult,\n} from \"@elizaos/plugin-browser\";\nimport type { CreateLifeOpsBrowserSessionRequest } from \"@elizaos/plugin-browser/lifeops-session-contracts\";\nimport type { LifeOpsGmailMessageSummary } from \"@elizaos/shared\";\nimport {\n createLifeOpsSubscriptionAudit,\n createLifeOpsSubscriptionCancellation,\n createLifeOpsSubscriptionCandidate,\n FinancesRepository,\n} from \"../db/finances-repository.js\";\nimport {\n fail,\n normalizeOptionalBoolean,\n normalizeOptionalString,\n requireAgentId,\n requireNonEmptyString,\n} from \"../finance-normalize.js\";\nimport {\n findLifeOpsSubscriptionPlaybook,\n type LifeOpsSubscriptionPlaybook,\n listLifeOpsSubscriptionPlaybooks,\n PLAYBOOK_UNSUPPORTED_FLOW_ERROR,\n type SubscriptionAutomationStep,\n} from \"../subscriptions-playbooks.js\";\nimport type {\n LifeOpsSubscriptionAudit,\n LifeOpsSubscriptionAuditSummary,\n LifeOpsSubscriptionCancellation,\n LifeOpsSubscriptionCancellationRequest,\n LifeOpsSubscriptionCancellationSummary,\n LifeOpsSubscriptionCandidate,\n LifeOpsSubscriptionDiscoveryRequest,\n LifeOpsSubscriptionExecutor,\n} from \"../subscriptions-types.js\";\nimport {\n createSubscriptionsBrowserGateway,\n type SubscriptionsBrowserGateway,\n} from \"./browser-bridge-seam.js\";\nimport {\n createSubscriptionsGmailGateway,\n type SubscriptionsGmailGateway,\n} from \"./gmail-seam.js\";\n\n/** Optional construction options (mirrors the finances service shape). */\nexport type SubscriptionsServiceOptions = {\n ownerEntityId?: string | null;\n /** Injectable for tests — defaults to the runtime-resolved Gmail seam. */\n gmailGateway?: SubscriptionsGmailGateway;\n /** Injectable for tests — defaults to the runtime-resolved browser seam. */\n browserGateway?: SubscriptionsBrowserGateway;\n};\n\ntype BrowserArtifact = {\n kind: \"screenshot\" | \"page_probe\";\n label: string;\n detail: string;\n};\n\ntype BrowserActionParams =\n | { action: \"open\" | \"navigate\"; url: string }\n | { action: \"wait\"; text?: string; selector?: string; timeout?: number }\n | { action: \"click\"; text?: string; selector?: string }\n | { action: \"get_dom\" | \"screenshot\" };\n\ntype BrowserActionResult = {\n success?: boolean;\n message?: string | null;\n content?: unknown;\n url?: string | null;\n title?: string | null;\n error?: string | null;\n data?: unknown;\n screenshot?: string | null;\n};\n\ntype ComputerUseBrowserService = {\n executeBrowserAction(\n params: BrowserActionParams,\n ): Promise<BrowserActionResult>;\n};\n\ntype BrowserActionExecutor = {\n executeBrowserAction(\n params: BrowserActionParams,\n ): Promise<BrowserActionResult>;\n};\n\nconst DEFAULT_SUBSCRIPTION_BROWSER_WAIT_MS = 5_000;\n\nfunction isComputerUseBrowserService(\n service: unknown,\n): service is ComputerUseBrowserService {\n return (\n Boolean(service) &&\n typeof service === \"object\" &&\n typeof (service as { executeBrowserAction?: unknown })\n .executeBrowserAction === \"function\"\n );\n}\n\nfunction isBrowserService(service: unknown): service is BrowserService {\n return (\n Boolean(service) &&\n typeof service === \"object\" &&\n typeof (service as { execute?: unknown }).execute === \"function\"\n );\n}\n\nfunction resultRecord(value: unknown): Record<string, unknown> | null {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : null;\n}\n\nfunction resultStringField(\n value: unknown,\n field: \"title\" | \"url\",\n): string | null {\n const record = resultRecord(value);\n const candidate = record?.[field];\n return typeof candidate === \"string\" && candidate.trim() ? candidate : null;\n}\n\nfunction workspaceResultContent(\n result: BrowserWorkspaceCommandResult,\n): string | null {\n if (typeof result.value === \"string\") {\n return result.value;\n }\n if (result.snapshot?.data) {\n return result.snapshot.data;\n }\n if (result.value !== undefined) {\n return JSON.stringify(result.value);\n }\n if (result.elements) {\n return JSON.stringify(result.elements);\n }\n if (result.tab) {\n return `${result.tab.title} ${result.tab.url}`.trim();\n }\n return null;\n}\n\nfunction workspaceResultToBrowserActionResult(\n result: BrowserWorkspaceCommandResult,\n): BrowserActionResult {\n const content = workspaceResultContent(result);\n return {\n success: true,\n message: `browser workspace ${result.subaction} completed`,\n content,\n url: result.tab?.url ?? resultStringField(result.value, \"url\"),\n title: result.tab?.title ?? resultStringField(result.value, \"title\"),\n data: {\n mode: result.mode,\n subaction: result.subaction,\n value: result.value,\n tab: result.tab,\n elements: result.elements,\n },\n screenshot: result.snapshot?.data ?? null,\n };\n}\n\nclass BrowserServiceActionExecutor implements BrowserActionExecutor {\n private currentTabId: string | null = null;\n\n constructor(private readonly browser: BrowserService) {}\n\n async executeBrowserAction(\n params: BrowserActionParams,\n ): Promise<BrowserActionResult> {\n try {\n const command = await this.toWorkspaceCommand(params);\n const result = await this.browser.execute(command, \"workspace\");\n if (result.tab?.id) {\n this.currentTabId = result.tab.id;\n }\n return workspaceResultToBrowserActionResult(result);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n success: false,\n message,\n error: message,\n };\n }\n }\n\n private async toWorkspaceCommand(\n params: BrowserActionParams,\n ): Promise<BrowserWorkspaceCommand> {\n const id = this.currentTabId ?? undefined;\n switch (params.action) {\n case \"open\": {\n const reusableId = await this.findReusableBlankWorkspaceTabId();\n if (reusableId) {\n return { id: reusableId, subaction: \"navigate\", url: params.url };\n }\n return { show: true, subaction: \"open\", url: params.url };\n }\n case \"navigate\":\n return id\n ? { id, subaction: \"navigate\", url: params.url }\n : { show: true, subaction: \"open\", url: params.url };\n case \"wait\":\n return {\n ...(id ? { id } : {}),\n ...(params.selector ? { selector: params.selector } : {}),\n ...(params.text ? { text: params.text } : {}),\n subaction: \"wait\",\n timeoutMs: params.timeout ?? DEFAULT_SUBSCRIPTION_BROWSER_WAIT_MS,\n };\n case \"click\":\n return {\n ...(id ? { id } : {}),\n ...(params.selector\n ? { selector: params.selector }\n : { findBy: \"text\", text: params.text }),\n subaction: \"click\",\n };\n case \"get_dom\":\n return {\n ...(id ? { id } : {}),\n getMode: \"html\",\n selector: \"body\",\n subaction: \"get\",\n };\n case \"screenshot\":\n return {\n ...(id ? { id } : {}),\n fullPage: true,\n subaction: \"screenshot\",\n };\n }\n }\n\n private async findReusableBlankWorkspaceTabId(): Promise<string | null> {\n try {\n const result = await this.browser.execute(\n { subaction: \"list\" },\n \"workspace\",\n );\n const tabs = result.tabs ?? [];\n const current = this.currentTabId\n ? tabs.find(\n (candidate) =>\n candidate.id === this.currentTabId &&\n candidate.visible &&\n candidate.url.trim() === \"about:blank\",\n )\n : null;\n const tab =\n current ??\n tabs.find(\n (candidate) =>\n candidate.visible && candidate.url.trim() === \"about:blank\",\n );\n return tab?.id ?? null;\n } catch {\n return null;\n }\n }\n}\n\nfunction resolveAgentBrowserExecutor(\n runtime: IAgentRuntime,\n): BrowserActionExecutor | null {\n const computerUseService = runtime.getService(\"computeruse\");\n if (isComputerUseBrowserService(computerUseService)) {\n return computerUseService;\n }\n const browserService = runtime.getService(BROWSER_SERVICE_TYPE);\n return isBrowserService(browserService)\n ? new BrowserServiceActionExecutor(browserService)\n : null;\n}\n\ntype BrowserSignalProbe = {\n status:\n | \"clear\"\n | \"completed\"\n | \"needs_login\"\n | \"needs_mfa\"\n | \"phone_only\"\n | \"chat_only\";\n detail: string | null;\n};\n\nconst MAX_AUDIT_MESSAGES = 80;\nconst DEFAULT_AUDIT_WINDOW_DAYS = 180;\n\nfunction normalizeSubscriptionLookup(value: string): string {\n return value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\nfunction slugifySubscriptionValue(value: string): string {\n return value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\");\n}\n\nfunction guessCadence(\n message: Pick<LifeOpsGmailMessageSummary, \"subject\" | \"snippet\">,\n): LifeOpsSubscriptionCandidate[\"cadence\"] {\n const blob = `${message.subject} ${message.snippet}`.toLowerCase();\n if (/\\bannual\\b|\\byearly\\b|\\byear\\b|\\b12 month\\b|\\b12-month\\b/.test(blob)) {\n return \"annual\";\n }\n if (\n /\\bmonth\\b|\\bmonthly\\b|\\brenewal\\b|\\bsubscription\\b|\\bbilling\\b/.test(blob)\n ) {\n return \"monthly\";\n }\n return \"unknown\";\n}\n\nfunction guessState(\n message: Pick<LifeOpsGmailMessageSummary, \"subject\" | \"snippet\">,\n): LifeOpsSubscriptionCandidate[\"state\"] {\n const blob = `${message.subject} ${message.snippet}`.toLowerCase();\n if (\n /\\bcancelled\\b|\\bcanceled\\b|\\bended\\b|\\bexpires on\\b|\\bexpired\\b/.test(blob)\n ) {\n return \"canceled\";\n }\n if (/\\brenewal\\b|\\breceipt\\b|\\bbilled\\b|\\bpayment\\b/.test(blob)) {\n return \"active\";\n }\n return \"uncertain\";\n}\n\nfunction parseUsdAmount(\n message: Pick<LifeOpsGmailMessageSummary, \"subject\" | \"snippet\">,\n): number | null {\n const blob = `${message.subject} ${message.snippet}`;\n const match = blob.match(/\\$([0-9]+(?:\\.[0-9]{1,2})?)/);\n if (!match) {\n return null;\n }\n const value = Number(match[1]);\n return Number.isFinite(value) ? value : null;\n}\n\nfunction annualizeAmount(\n amount: number | null,\n cadence: LifeOpsSubscriptionCandidate[\"cadence\"],\n): number | null {\n if (amount === null) {\n return null;\n }\n if (cadence === \"monthly\") {\n return Number((amount * 12).toFixed(2));\n }\n if (cadence === \"annual\") {\n return Number(amount.toFixed(2));\n }\n return null;\n}\n\nfunction summarizeEvidence(\n serviceName: string,\n evidence: LifeOpsGmailMessageSummary[],\n): string {\n const latest = evidence[0];\n if (!latest) {\n return `No recent email evidence found for ${serviceName}.`;\n }\n return `${serviceName}: ${evidence.length} matching email${evidence.length === 1 ? \"\" : \"s\"}, latest \"${latest.subject}\" on ${latest.receivedAt}.`;\n}\n\nfunction messageBlob(message: LifeOpsGmailMessageSummary): string {\n return [\n message.subject,\n message.snippet,\n message.from,\n message.fromEmail ?? \"\",\n ]\n .join(\" \")\n .toLowerCase();\n}\n\nfunction scoreMessageAgainstPlaybook(\n message: LifeOpsGmailMessageSummary,\n playbook: LifeOpsSubscriptionPlaybook,\n): number {\n const blob = messageBlob(message);\n let score = 0;\n for (const alias of [playbook.serviceName, ...playbook.aliases]) {\n if (blob.includes(alias.toLowerCase())) {\n score += 2;\n }\n }\n for (const keyword of playbook.auditSubjectKeywords) {\n if (blob.includes(keyword.toLowerCase())) {\n score += 1;\n }\n }\n for (const domain of playbook.auditDomains) {\n if (blob.includes(domain.toLowerCase())) {\n score += 1;\n }\n }\n return score;\n}\n\nfunction resolvePlaybookFromMessage(\n text: string,\n): LifeOpsSubscriptionPlaybook | null {\n return findLifeOpsSubscriptionPlaybook(text);\n}\n\nfunction resolvePlaybookFromCandidate(\n candidate: Pick<LifeOpsSubscriptionCandidate, \"serviceSlug\" | \"serviceName\">,\n): LifeOpsSubscriptionPlaybook | null {\n return (\n findLifeOpsSubscriptionPlaybook(candidate.serviceSlug) ??\n findLifeOpsSubscriptionPlaybook(candidate.serviceName)\n );\n}\n\nfunction companionSelectorForClickTextStep(\n playbook: LifeOpsSubscriptionPlaybook,\n step: Extract<SubscriptionAutomationStep, { kind: \"click_text\" }>,\n): string {\n const clickText = step.text.trim().toLowerCase();\n if (clickText === \"cancel subscription\") {\n const selector = playbook.companionSelectors?.cancel;\n if (selector) {\n return selector;\n }\n }\n if (clickText === \"confirm cancellation\") {\n const selector = playbook.companionSelectors?.confirm;\n if (selector) {\n return selector;\n }\n }\n fail(\n 400,\n `${playbook.serviceName} companion playbook is missing a selector for \"${step.text}\"`,\n );\n}\n\nfunction toUserBrowserActions(\n playbook: LifeOpsSubscriptionPlaybook,\n): CreateLifeOpsBrowserSessionRequest[\"actions\"] {\n const actions: Array<Omit<BrowserBridgeAction, \"id\">> = [];\n for (const step of playbook.steps ?? []) {\n switch (step.kind) {\n case \"open\":\n case \"navigate\":\n actions.push({\n kind: step.kind,\n label: `${playbook.serviceName}: ${step.kind}`,\n url: step.url,\n selector: null,\n text: null,\n accountAffecting: false,\n requiresConfirmation: false,\n metadata: { playbookKey: playbook.key },\n });\n break;\n case \"click_text\":\n actions.push({\n kind: \"click\",\n label: `${playbook.serviceName}: click ${step.text}`,\n url: null,\n selector: companionSelectorForClickTextStep(playbook, step),\n text: step.text,\n accountAffecting: true,\n requiresConfirmation: step.destructive ?? false,\n metadata: { playbookKey: playbook.key },\n });\n break;\n case \"click_selector\":\n actions.push({\n kind: \"click\",\n label: `${playbook.serviceName}: click selector`,\n url: null,\n selector: step.selector,\n text: null,\n accountAffecting: true,\n requiresConfirmation: step.destructive ?? false,\n metadata: { playbookKey: playbook.key },\n });\n break;\n case \"wait_text\":\n case \"assert_text\":\n case \"wait_selector\":\n case \"screenshot\":\n actions.push({\n kind: \"read_page\",\n label: `${playbook.serviceName}: inspect page`,\n url: null,\n selector: null,\n text: null,\n accountAffecting: false,\n requiresConfirmation: false,\n metadata: {\n playbookKey: playbook.key,\n expected:\n step.kind === \"wait_selector\"\n ? step.selector\n : \"text\" in step\n ? step.text\n : step.label,\n },\n });\n break;\n }\n }\n return actions as CreateLifeOpsBrowserSessionRequest[\"actions\"];\n}\n\nfunction browserResultText(result: BrowserActionResult): string {\n return [\n result.message ?? \"\",\n typeof result.content === \"string\" ? result.content : \"\",\n typeof result.url === \"string\" ? result.url : \"\",\n typeof result.title === \"string\" ? result.title : \"\",\n result.error ?? \"\",\n result.data ? JSON.stringify(result.data) : \"\",\n ]\n .join(\" \")\n .toLowerCase();\n}\n\nfunction summarizeCancellationStatus(\n cancellation: LifeOpsSubscriptionCancellation,\n): string {\n switch (cancellation.status) {\n case \"completed\":\n return `${cancellation.serviceName} cancellation completed.`;\n case \"awaiting_confirmation\":\n return `Cancellation for ${cancellation.serviceName} is ready for final confirmation.`;\n case \"needs_login\":\n return `${cancellation.serviceName} needs the user to sign in before cancellation can continue.`;\n case \"needs_mfa\":\n return `${cancellation.serviceName} needs multi-factor verification before cancellation can continue.`;\n case \"phone_only\":\n return `${cancellation.serviceName} can only be canceled by phone.`;\n case \"chat_only\":\n return `${cancellation.serviceName} can only be canceled through support chat.`;\n case \"already_canceled\":\n return `${cancellation.serviceName} already appears to be canceled.`;\n case \"unsupported_surface\":\n if (\n typeof cancellation.error === \"string\" &&\n cancellation.error.startsWith(PLAYBOOK_UNSUPPORTED_FLOW_ERROR)\n ) {\n return (\n cancellation.evidenceSummary ??\n `I can open the ${cancellation.serviceName} cancel page for you, but I haven't learned the exact click-flow yet. Want me to open the page and you finish the cancel?`\n );\n }\n return `I don't have a cancellation surface for ${cancellation.serviceName} yet${cancellation.error ? `: ${cancellation.error}` : \".\"}`;\n case \"failed\":\n return `Cancellation for ${cancellation.serviceName} failed${cancellation.error ? `: ${cancellation.error}` : \".\"}`;\n default:\n return `${cancellation.serviceName} cancellation status: ${cancellation.status}.`;\n }\n}\n\nfunction extractEvidenceMessages(\n messages: LifeOpsGmailMessageSummary[],\n): Array<Record<string, unknown>> {\n return messages.slice(0, 5).map((message) => ({\n messageId: message.id,\n subject: message.subject,\n from: message.from,\n receivedAt: message.receivedAt,\n snippet: message.snippet,\n htmlLink: message.htmlLink,\n }));\n}\n\nasync function probeBrowserSignals(\n browser: BrowserActionExecutor,\n playbook: LifeOpsSubscriptionPlaybook,\n): Promise<BrowserSignalProbe> {\n const dom = await browser.executeBrowserAction({ action: \"get_dom\" });\n const blob = browserResultText(dom);\n for (const marker of playbook.cancellationMarkers) {\n if (blob.includes(marker.toLowerCase())) {\n return { status: \"completed\", detail: marker };\n }\n }\n for (const marker of playbook.phoneOnlyMarkers) {\n if (blob.includes(marker.toLowerCase())) {\n return { status: \"phone_only\", detail: marker };\n }\n }\n for (const marker of playbook.chatOnlyMarkers) {\n if (blob.includes(marker.toLowerCase())) {\n return { status: \"chat_only\", detail: marker };\n }\n }\n for (const marker of playbook.mfaMarkers) {\n if (blob.includes(marker.toLowerCase())) {\n return { status: \"needs_mfa\", detail: marker };\n }\n }\n for (const marker of playbook.loginMarkers) {\n if (blob.includes(marker.toLowerCase())) {\n return { status: \"needs_login\", detail: marker };\n }\n }\n return { status: \"clear\", detail: null };\n}\n\nfunction selectorForBrowserClickTextStep(\n playbook: LifeOpsSubscriptionPlaybook,\n step: Extract<SubscriptionAutomationStep, { kind: \"click_text\" }>,\n): string | undefined {\n const clickText = step.text.trim().toLowerCase();\n if (clickText === \"cancel subscription\") {\n return playbook.companionSelectors?.cancel;\n }\n if (clickText === \"confirm cancellation\") {\n return playbook.companionSelectors?.confirm;\n }\n return undefined;\n}\n\nasync function executeBrowserStep(\n browser: BrowserActionExecutor,\n playbook: LifeOpsSubscriptionPlaybook,\n step: SubscriptionAutomationStep,\n): Promise<BrowserActionResult> {\n const params: BrowserActionParams = ((): BrowserActionParams => {\n switch (step.kind) {\n case \"open\":\n return { action: \"open\", url: step.url };\n case \"navigate\":\n return { action: \"navigate\", url: step.url };\n case \"wait_text\":\n return { action: \"wait\", text: step.text, timeout: step.timeoutMs };\n case \"wait_selector\":\n return {\n action: \"wait\",\n selector: step.selector,\n timeout: step.timeoutMs,\n };\n case \"click_text\": {\n const selector = selectorForBrowserClickTextStep(playbook, step);\n return { action: \"click\", selector, text: step.text };\n }\n case \"click_selector\":\n return { action: \"click\", selector: step.selector };\n case \"assert_text\":\n return { action: \"get_dom\" };\n case \"screenshot\":\n return { action: \"screenshot\" };\n }\n })();\n return browser.executeBrowserAction(params);\n}\n\nfunction findServiceInText(\n text: string,\n): { serviceName: string; serviceSlug: string } | null {\n const playbook = resolvePlaybookFromMessage(text);\n if (!playbook) {\n return null;\n }\n return {\n serviceName: playbook.serviceName,\n serviceSlug: playbook.key,\n };\n}\n\nexport class SubscriptionsService {\n public readonly repository: FinancesRepository;\n public readonly ownerEntityId: string | null;\n private readonly gmail: SubscriptionsGmailGateway;\n private readonly browser: SubscriptionsBrowserGateway;\n\n constructor(\n public readonly runtime: IAgentRuntime,\n options: SubscriptionsServiceOptions = {},\n ) {\n this.repository = new FinancesRepository(runtime);\n this.ownerEntityId = normalizeOptionalString(options.ownerEntityId) ?? null;\n this.gmail =\n options.gmailGateway ??\n createSubscriptionsGmailGateway(runtime, requireAgentId(runtime));\n this.browser =\n options.browserGateway ??\n createSubscriptionsBrowserGateway(runtime, this.ownerEntityId);\n }\n\n agentId(): string {\n return requireAgentId(this.runtime);\n }\n\n private logSubscriptionsWarn(operation: string, message: string): void {\n logger.warn(\n {\n boundary: \"finances\",\n operation,\n agentId: this.agentId(),\n },\n message,\n );\n }\n\n async listSubscriptionPlaybooks(): Promise<LifeOpsSubscriptionPlaybook[]> {\n return [...listLifeOpsSubscriptionPlaybooks()];\n }\n\n /**\n * Best-effort merchant→playbook lookup used by the Payments dashboard to\n * deep-link from a recurring charge row to the cancellation flow. Returns\n * a *trimmed* playbook descriptor (no `steps`) so callers don't render\n * automation internals.\n */\n findSubscriptionPlaybookForMerchant(merchant: string): {\n key: string;\n serviceName: string;\n managementUrl: string;\n executorPreference: LifeOpsSubscriptionPlaybook[\"executorPreference\"];\n } | null {\n const playbook = findLifeOpsSubscriptionPlaybook(merchant);\n if (!playbook) {\n return null;\n }\n return {\n key: playbook.key,\n serviceName: playbook.serviceName,\n managementUrl: playbook.managementUrl,\n executorPreference: playbook.executorPreference,\n };\n }\n\n async getLatestSubscriptionAudit(): Promise<LifeOpsSubscriptionAuditSummary | null> {\n const audit = await this.repository.getLatestSubscriptionAudit(\n this.agentId(),\n );\n if (!audit) {\n return null;\n }\n const candidates = await this.repository.listSubscriptionCandidatesForAudit(\n this.agentId(),\n audit.id,\n );\n return { audit, candidates };\n }\n\n async auditSubscriptions(\n request: LifeOpsSubscriptionDiscoveryRequest = {},\n ): Promise<LifeOpsSubscriptionAuditSummary> {\n const queryWindowDays = Math.max(\n 1,\n Math.min(\n 365,\n Number.isFinite(request.queryWindowDays)\n ? Math.trunc(request.queryWindowDays as number)\n : DEFAULT_AUDIT_WINDOW_DAYS,\n ),\n );\n const serviceQuery = normalizeOptionalString(request.serviceQuery) ?? null;\n let messages: LifeOpsGmailMessageSummary[] = [];\n let source: LifeOpsSubscriptionAudit[\"source\"] = \"gmail\";\n\n try {\n const found = await this.gmail.searchSubscriptionMessages({\n windowDays: queryWindowDays,\n maxResults: MAX_AUDIT_MESSAGES,\n });\n const sinceMs = Date.now() - queryWindowDays * 86_400_000;\n messages = found.filter((message) => {\n const receivedMs = Date.parse(message.receivedAt);\n return !Number.isNaN(receivedMs) && receivedMs >= sinceMs;\n });\n } catch (error) {\n source = serviceQuery ? \"manual\" : \"gmail\";\n this.logSubscriptionsWarn(\n \"subscriptions_audit\",\n `gmail discovery unavailable: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n\n const playbooks = serviceQuery\n ? listLifeOpsSubscriptionPlaybooks().filter((playbook) => {\n const lookup = normalizeSubscriptionLookup(serviceQuery);\n return (\n normalizeSubscriptionLookup(playbook.serviceName) === lookup ||\n playbook.aliases.some(\n (alias) => normalizeSubscriptionLookup(alias) === lookup,\n ) ||\n normalizeSubscriptionLookup(playbook.key) === lookup\n );\n })\n : listLifeOpsSubscriptionPlaybooks();\n\n const candidates: LifeOpsSubscriptionCandidate[] = [];\n for (const playbook of playbooks) {\n const evidence = messages\n .map((message) => ({\n message,\n score: scoreMessageAgainstPlaybook(message, playbook),\n }))\n .filter((candidate) => candidate.score > 0)\n .sort((left, right) => right.score - left.score);\n if (evidence.length === 0 && source !== \"manual\") {\n continue;\n }\n const bestEvidence = evidence[0] ?? null;\n const bestMessage = bestEvidence?.message;\n const cadence = bestMessage ? guessCadence(bestMessage) : \"unknown\";\n const state = bestMessage ? guessState(bestMessage) : \"uncertain\";\n const amount = bestMessage ? parseUsdAmount(bestMessage) : null;\n const confidence = bestEvidence\n ? Math.min(0.98, 0.45 + bestEvidence.score * 0.12)\n : 0.4;\n const candidate = createLifeOpsSubscriptionCandidate({\n agentId: this.agentId(),\n auditId: \"\",\n serviceSlug: playbook.key,\n serviceName: playbook.serviceName,\n provider: bestMessage\n ? (bestMessage.fromEmail ?? bestMessage.from)\n : playbook.serviceName,\n cadence,\n state,\n confidence,\n annualCostEstimateUsd: annualizeAmount(amount, cadence),\n managementUrl: playbook.managementUrl,\n latestEvidenceAt: bestMessage ? bestMessage.receivedAt : null,\n evidenceJson: extractEvidenceMessages(\n evidence.map((item) => item.message),\n ),\n metadata: {\n playbookKey: playbook.key,\n evidenceCount: evidence.length,\n source,\n },\n });\n candidates.push(candidate);\n }\n\n const audit = createLifeOpsSubscriptionAudit({\n agentId: this.agentId(),\n source,\n queryWindowDays,\n status: \"completed\",\n totalCandidates: candidates.length,\n activeCandidates: candidates.filter(\n (candidate) => candidate.state === \"active\",\n ).length,\n canceledCandidates: candidates.filter(\n (candidate) => candidate.state === \"canceled\",\n ).length,\n uncertainCandidates: candidates.filter(\n (candidate) => candidate.state === \"uncertain\",\n ).length,\n summary:\n candidates.length === 0\n ? source === \"manual\"\n ? \"No matching subscription playbooks were found for the requested service.\"\n : \"No subscription evidence was found in recent Gmail receipts.\"\n : `Found ${candidates.length} likely subscription${candidates.length === 1 ? \"\" : \"s\"} from recent LifeOps signals.`,\n metadata: {\n serviceQuery,\n scannedMessageCount: messages.length,\n playbookCount: playbooks.length,\n },\n });\n await this.repository.createSubscriptionAudit(audit);\n\n for (const candidate of candidates) {\n const persisted = {\n ...candidate,\n auditId: audit.id,\n };\n await this.repository.createSubscriptionCandidate(persisted);\n }\n\n const persistedCandidates =\n await this.repository.listSubscriptionCandidatesForAudit(\n this.agentId(),\n audit.id,\n );\n return { audit, candidates: persistedCandidates };\n }\n\n async getSubscriptionCancellationStatus(args: {\n cancellationId?: string | null;\n serviceName?: string | null;\n serviceSlug?: string | null;\n }): Promise<LifeOpsSubscriptionCancellationSummary | null> {\n const serviceSlug = normalizeOptionalString(args.serviceSlug);\n let cancellation =\n normalizeOptionalString(args.cancellationId) !== undefined\n ? await this.repository.getSubscriptionCancellation(\n this.agentId(),\n requireNonEmptyString(args.cancellationId, \"cancellationId\"),\n )\n : await this.repository.getLatestSubscriptionCancellation(\n this.agentId(),\n serviceSlug,\n );\n\n if (!cancellation && normalizeOptionalString(args.serviceName)) {\n const playbook = resolvePlaybookFromMessage(\n requireNonEmptyString(args.serviceName, \"serviceName\"),\n );\n cancellation = await this.repository.getLatestSubscriptionCancellation(\n this.agentId(),\n playbook?.key,\n );\n }\n\n if (!cancellation) {\n return null;\n }\n\n if (cancellation.browserSessionId) {\n const session = await this.browser.getBrowserSession(\n cancellation.browserSessionId,\n );\n if (session) {\n const nextStatus =\n session.status === \"done\"\n ? \"completed\"\n : session.status === \"failed\"\n ? \"failed\"\n : session.status === \"awaiting_confirmation\"\n ? \"awaiting_confirmation\"\n : \"running\";\n if (nextStatus !== cancellation.status) {\n cancellation = {\n ...cancellation,\n status: nextStatus,\n evidenceSummary:\n cancellation.evidenceSummary ??\n `Agent Browser Bridge session ${session.status}.`,\n error:\n nextStatus === \"failed\"\n ? JSON.stringify(session.result)\n : cancellation.error,\n updatedAt: new Date().toISOString(),\n finishedAt:\n nextStatus === \"completed\" || nextStatus === \"failed\"\n ? new Date().toISOString()\n : cancellation.finishedAt,\n };\n await this.repository.updateSubscriptionCancellation(cancellation);\n }\n }\n }\n\n const candidate = cancellation.candidateId\n ? await this.repository.getSubscriptionCandidate(\n this.agentId(),\n cancellation.candidateId,\n )\n : null;\n return { cancellation, candidate };\n }\n\n async cancelSubscription(\n request: LifeOpsSubscriptionCancellationRequest,\n ): Promise<LifeOpsSubscriptionCancellationSummary> {\n const candidate = request.candidateId\n ? await this.repository.getSubscriptionCandidate(\n this.agentId(),\n request.candidateId,\n )\n : null;\n const requestedServiceName = normalizeOptionalString(request.serviceName);\n const requestedServiceSlug = normalizeOptionalString(request.serviceSlug);\n const playbook =\n (candidate ? resolvePlaybookFromCandidate(candidate) : null) ??\n (requestedServiceSlug\n ? resolvePlaybookFromMessage(requestedServiceSlug)\n : null) ??\n (requestedServiceName\n ? resolvePlaybookFromMessage(requestedServiceName)\n : null);\n\n if (!candidate && !playbook && !requestedServiceName) {\n fail(\n 400,\n \"cancelSubscription requires a known candidateId or recognizable serviceName/serviceSlug\",\n );\n }\n\n const serviceName =\n candidate?.serviceName ?? playbook?.serviceName ?? requestedServiceName;\n if (!serviceName) {\n fail(\n 400,\n \"cancelSubscription requires a known candidateId or recognizable serviceName/serviceSlug\",\n );\n }\n const serviceSlug =\n candidate?.serviceSlug ??\n playbook?.key ??\n requestedServiceSlug ??\n slugifySubscriptionValue(serviceName);\n\n const connectedCompanions = await this.browser.listBrowserCompanions();\n const explicitExecutor = normalizeOptionalString(request.executor);\n const executor = (explicitExecutor ??\n (connectedCompanions.some(\n (companion) => companion.connectionState === \"connected\",\n )\n ? \"user_browser\"\n : (playbook?.executorPreference ??\n \"agent_browser\"))) as LifeOpsSubscriptionExecutor;\n\n const confirmed =\n normalizeOptionalBoolean(request.confirmed, \"confirmed\") ?? false;\n let cancellation = createLifeOpsSubscriptionCancellation({\n agentId: this.agentId(),\n auditId: candidate?.auditId ?? null,\n candidateId: candidate?.id ?? null,\n serviceSlug,\n serviceName,\n executor,\n status: \"draft\",\n confirmed,\n currentStep: null,\n browserSessionId: null,\n evidenceSummary: null,\n artifactCount: 0,\n managementUrl:\n candidate?.managementUrl ?? playbook?.managementUrl ?? null,\n error: null,\n metadata: {\n playbookKey: playbook?.key ?? null,\n candidateState: candidate?.state ?? null,\n },\n finishedAt: null,\n });\n await this.repository.createSubscriptionCancellation(cancellation);\n\n if (!playbook) {\n cancellation = {\n ...cancellation,\n status: \"unsupported_surface\",\n error: \"No known cancellation playbook for this service.\",\n updatedAt: new Date().toISOString(),\n finishedAt: new Date().toISOString(),\n };\n await this.repository.updateSubscriptionCancellation(cancellation);\n return { cancellation, candidate };\n }\n\n if (!playbook.steps || playbook.steps.length === 0) {\n // We know where the management page lives, but this playbook has no\n // automated click-flow. Do NOT pretend to cancel by\n // opening the URL and taking a screenshot — surface the truthful\n // unsupported-surface state so the owner can finish it manually.\n cancellation = {\n ...cancellation,\n status: \"unsupported_surface\",\n error: `${PLAYBOOK_UNSUPPORTED_FLOW_ERROR}:${playbook.key}`,\n evidenceSummary: `I can open the ${playbook.serviceName} cancel page for you, but I haven't learned the exact click-flow yet. Want me to open the page and you finish the cancel? Management URL: ${playbook.managementUrl}`,\n managementUrl: playbook.managementUrl,\n metadata: {\n ...cancellation.metadata,\n playbookUnsupportedFlow: true,\n managementUrl: playbook.managementUrl,\n },\n updatedAt: new Date().toISOString(),\n finishedAt: new Date().toISOString(),\n };\n await this.repository.updateSubscriptionCancellation(cancellation);\n return { cancellation, candidate };\n }\n\n if (candidate?.state === \"canceled\") {\n cancellation = {\n ...cancellation,\n status: \"already_canceled\",\n evidenceSummary: summarizeEvidence(serviceName, []),\n updatedAt: new Date().toISOString(),\n finishedAt: new Date().toISOString(),\n };\n await this.repository.updateSubscriptionCancellation(cancellation);\n return { cancellation, candidate };\n }\n\n if (executor === \"user_browser\") {\n const companion = connectedCompanions.find(\n (entry) => entry.connectionState === \"connected\",\n );\n if (!companion) {\n cancellation = {\n ...cancellation,\n status: \"blocked\",\n error: \"No connected Agent Browser Bridge companion is available.\",\n updatedAt: new Date().toISOString(),\n finishedAt: new Date().toISOString(),\n };\n await this.repository.updateSubscriptionCancellation(cancellation);\n return { cancellation, candidate };\n }\n const session = await this.browser.createBrowserSession({\n title: `Manage ${serviceName} subscription`,\n browser: companion.browser,\n companionId: companion.id,\n profileId: companion.profileId,\n actions: toUserBrowserActions(playbook),\n });\n cancellation = {\n ...cancellation,\n status:\n session.status === \"awaiting_confirmation\"\n ? \"awaiting_confirmation\"\n : \"running\",\n currentStep: \"browser_session_created\",\n browserSessionId: session.id,\n updatedAt: new Date().toISOString(),\n metadata: {\n ...cancellation.metadata,\n browserSessionStatus: session.status,\n },\n };\n await this.repository.updateSubscriptionCancellation(cancellation);\n return { cancellation, candidate };\n }\n\n const browser = resolveAgentBrowserExecutor(this.runtime);\n if (!browser) {\n cancellation = {\n ...cancellation,\n status: \"failed\",\n error: \"Agent browser service is not available.\",\n updatedAt: new Date().toISOString(),\n finishedAt: new Date().toISOString(),\n };\n await this.repository.updateSubscriptionCancellation(cancellation);\n return { cancellation, candidate };\n }\n\n const artifacts: BrowserArtifact[] = [];\n cancellation = {\n ...cancellation,\n status: \"running\",\n currentStep: \"starting_playbook\",\n updatedAt: new Date().toISOString(),\n };\n await this.repository.updateSubscriptionCancellation(cancellation);\n\n for (const step of playbook.steps) {\n if (\"destructive\" in step && step.destructive && !confirmed) {\n cancellation = {\n ...cancellation,\n status: \"awaiting_confirmation\",\n currentStep:\n step.kind === \"click_text\"\n ? step.text\n : step.kind === \"click_selector\"\n ? step.selector\n : \"destructive_step\",\n evidenceSummary:\n cancellation.evidenceSummary ??\n `Ready to confirm ${serviceName} cancellation.`,\n artifactCount: artifacts.length,\n metadata: {\n ...cancellation.metadata,\n artifacts,\n },\n updatedAt: new Date().toISOString(),\n };\n await this.repository.updateSubscriptionCancellation(cancellation);\n return { cancellation, candidate };\n }\n\n const result = await executeBrowserStep(browser, playbook, step);\n if (!result.success) {\n cancellation = {\n ...cancellation,\n status: \"failed\",\n currentStep: step.kind,\n error: result.error ?? result.message ?? \"browser step failed\",\n artifactCount: artifacts.length,\n metadata: {\n ...cancellation.metadata,\n artifacts,\n lastBrowserResult: result,\n },\n updatedAt: new Date().toISOString(),\n finishedAt: new Date().toISOString(),\n };\n await this.repository.updateSubscriptionCancellation(cancellation);\n return { cancellation, candidate };\n }\n\n if (step.kind === \"screenshot\" && result.screenshot) {\n artifacts.push({\n kind: \"screenshot\",\n label: step.label,\n detail: `screenshot:${result.screenshot.length}`,\n });\n }\n\n const probe = await probeBrowserSignals(browser, playbook);\n if (probe.status === \"needs_login\") {\n cancellation = {\n ...cancellation,\n status: \"needs_login\",\n currentStep: step.kind,\n evidenceSummary: probe.detail,\n artifactCount: artifacts.length,\n metadata: {\n ...cancellation.metadata,\n artifacts,\n },\n updatedAt: new Date().toISOString(),\n finishedAt: new Date().toISOString(),\n };\n await this.repository.updateSubscriptionCancellation(cancellation);\n return { cancellation, candidate };\n }\n if (probe.status === \"needs_mfa\") {\n cancellation = {\n ...cancellation,\n status: \"needs_mfa\",\n currentStep: step.kind,\n evidenceSummary: probe.detail,\n artifactCount: artifacts.length,\n metadata: {\n ...cancellation.metadata,\n artifacts,\n },\n updatedAt: new Date().toISOString(),\n finishedAt: new Date().toISOString(),\n };\n await this.repository.updateSubscriptionCancellation(cancellation);\n return { cancellation, candidate };\n }\n if (probe.status === \"phone_only\" || probe.status === \"chat_only\") {\n cancellation = {\n ...cancellation,\n status: probe.status,\n currentStep: step.kind,\n evidenceSummary: probe.detail,\n artifactCount: artifacts.length,\n metadata: {\n ...cancellation.metadata,\n artifacts,\n },\n updatedAt: new Date().toISOString(),\n finishedAt: new Date().toISOString(),\n };\n await this.repository.updateSubscriptionCancellation(cancellation);\n return { cancellation, candidate };\n }\n }\n\n const finalProbe = await probeBrowserSignals(browser, playbook);\n cancellation = {\n ...cancellation,\n status: finalProbe.status === \"completed\" ? \"completed\" : \"blocked\",\n currentStep: \"done\",\n evidenceSummary:\n finalProbe.detail ??\n `${serviceName} flow finished in the local browser.`,\n artifactCount: artifacts.length,\n metadata: {\n ...cancellation.metadata,\n artifacts,\n },\n updatedAt: new Date().toISOString(),\n finishedAt: new Date().toISOString(),\n };\n await this.repository.updateSubscriptionCancellation(cancellation);\n return { cancellation, candidate };\n }\n\n summarizeSubscriptionAudit(summary: LifeOpsSubscriptionAuditSummary): string {\n if (summary.candidates.length === 0) {\n return summary.audit.summary;\n }\n return [\n summary.audit.summary,\n ...summary.candidates.slice(0, 5).map((candidate) => {\n const annual =\n candidate.annualCostEstimateUsd === null\n ? \"\"\n : `, est $${candidate.annualCostEstimateUsd.toFixed(2)}/yr`;\n return `- ${candidate.serviceName} (${candidate.state}, ${candidate.cadence}${annual})`;\n }),\n ].join(\"\\n\");\n }\n\n summarizeSubscriptionCancellation(\n summary: LifeOpsSubscriptionCancellationSummary,\n ): string {\n const status = summarizeCancellationStatus(summary.cancellation);\n const lines = [status];\n if (\n summary.cancellation.evidenceSummary &&\n summary.cancellation.evidenceSummary !== status\n ) {\n lines.push(summary.cancellation.evidenceSummary);\n }\n if (summary.candidate) {\n lines.push(\n `Candidate confidence ${summary.candidate.confidence.toFixed(2)} from ${summary.candidate.provider}.`,\n );\n }\n return lines.join(\" \");\n }\n\n resolveSubscriptionIntent(text: string): {\n mode: \"audit\" | \"cancel\" | \"status\" | null;\n serviceName?: string;\n serviceSlug?: string;\n executor?: LifeOpsSubscriptionExecutor;\n } {\n const normalized = text.trim().toLowerCase();\n if (!normalized) {\n return { mode: null };\n }\n const matchedService = findServiceInText(text);\n if (\n /\\baudit\\b|\\breport\\b|\\breview\\b|\\bfind\\b.*\\bsubscription\\b|\\bwhat subscriptions\\b/.test(\n normalized,\n )\n ) {\n return {\n mode: \"audit\",\n ...matchedService,\n };\n }\n if (\n /\\bcancel\\b|\\bunsubscribe\\b|\\bend\\b.*\\bsubscription\\b/.test(normalized)\n ) {\n return {\n mode: \"cancel\",\n ...matchedService,\n executor: /\\bin my browser\\b|\\bpersonal browser\\b/.test(normalized)\n ? \"user_browser\"\n : \"agent_browser\",\n };\n }\n if (\n /\\bstatus\\b|\\bwhat happened\\b|\\bupdate\\b.*\\bsubscription\\b/.test(\n normalized,\n )\n ) {\n return {\n mode: \"status\",\n ...matchedService,\n };\n }\n return { mode: null, ...matchedService };\n }\n}\n"],"mappings":"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","names":["candidate"]}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { LifeOpsSubscriptionExecutor } from "./subscriptions-types.js";
|
|
2
|
+
export type SubscriptionAutomationStep = {
|
|
3
|
+
kind: "open";
|
|
4
|
+
url: string;
|
|
5
|
+
} | {
|
|
6
|
+
kind: "navigate";
|
|
7
|
+
url: string;
|
|
8
|
+
} | {
|
|
9
|
+
kind: "wait_text";
|
|
10
|
+
text: string;
|
|
11
|
+
timeoutMs?: number;
|
|
12
|
+
} | {
|
|
13
|
+
kind: "wait_selector";
|
|
14
|
+
selector: string;
|
|
15
|
+
timeoutMs?: number;
|
|
16
|
+
} | {
|
|
17
|
+
kind: "click_text";
|
|
18
|
+
text: string;
|
|
19
|
+
destructive?: boolean;
|
|
20
|
+
} | {
|
|
21
|
+
kind: "click_selector";
|
|
22
|
+
selector: string;
|
|
23
|
+
destructive?: boolean;
|
|
24
|
+
} | {
|
|
25
|
+
kind: "assert_text";
|
|
26
|
+
text: string;
|
|
27
|
+
} | {
|
|
28
|
+
kind: "screenshot";
|
|
29
|
+
label: string;
|
|
30
|
+
};
|
|
31
|
+
export type SubscriptionCancellationCapability = {
|
|
32
|
+
kind: "executable_playbook";
|
|
33
|
+
label: "Executable cancellation playbook";
|
|
34
|
+
executionSurface: "browser_steps";
|
|
35
|
+
manualFallback: false;
|
|
36
|
+
} | {
|
|
37
|
+
kind: "management_url_manual_fallback";
|
|
38
|
+
label: "Management URL manual fallback";
|
|
39
|
+
executionSurface: "management_url";
|
|
40
|
+
manualFallback: true;
|
|
41
|
+
reason: "no_verified_click_flow";
|
|
42
|
+
};
|
|
43
|
+
export interface LifeOpsSubscriptionPlaybook {
|
|
44
|
+
key: string;
|
|
45
|
+
serviceName: string;
|
|
46
|
+
aliases: string[];
|
|
47
|
+
executorPreference: LifeOpsSubscriptionExecutor;
|
|
48
|
+
cancellationCapability: SubscriptionCancellationCapability;
|
|
49
|
+
managementUrl: string;
|
|
50
|
+
managementPath?: string;
|
|
51
|
+
auditDomains: string[];
|
|
52
|
+
auditSubjectKeywords: string[];
|
|
53
|
+
loginMarkers: string[];
|
|
54
|
+
mfaMarkers: string[];
|
|
55
|
+
phoneOnlyMarkers: string[];
|
|
56
|
+
chatOnlyMarkers: string[];
|
|
57
|
+
cancellationMarkers: string[];
|
|
58
|
+
/**
|
|
59
|
+
* Concrete browser automation steps. When undefined, the service has no
|
|
60
|
+
* real click-flow implemented — the caller must report a
|
|
61
|
+
* `PLAYBOOK_NOT_IMPLEMENTED` failure rather than pretend to cancel.
|
|
62
|
+
*/
|
|
63
|
+
steps?: SubscriptionAutomationStep[];
|
|
64
|
+
companionSelectors?: {
|
|
65
|
+
cancel?: string;
|
|
66
|
+
confirm?: string;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Error-code prefix used by the subscriptions mixin and action when a
|
|
71
|
+
* playbook is registered (we know the management URL) but no concrete
|
|
72
|
+
* click-flow is available yet. Shared with the action so callers
|
|
73
|
+
* can pattern-match structured failures instead of parsing free text.
|
|
74
|
+
*/
|
|
75
|
+
export declare const PLAYBOOK_UNSUPPORTED_FLOW_ERROR = "PLAYBOOK_UNSUPPORTED_FLOW";
|
|
76
|
+
export declare const LIFEOPS_SUBSCRIPTION_PLAYBOOKS: readonly LifeOpsSubscriptionPlaybook[];
|
|
77
|
+
export declare function listLifeOpsSubscriptionPlaybooks(): readonly LifeOpsSubscriptionPlaybook[];
|
|
78
|
+
export declare function findLifeOpsSubscriptionPlaybook(serviceNameOrSlug: string | null | undefined): LifeOpsSubscriptionPlaybook | null;
|
|
79
|
+
//# sourceMappingURL=subscriptions-playbooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscriptions-playbooks.d.ts","sourceRoot":"","sources":["../src/subscriptions-playbooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AAE5E,MAAM,MAAM,0BAA0B,GAClC;IACE,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb,GACD;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb,GACD;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GACD;IACE,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GACD;IACE,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GACD;IACE,IAAI,EAAE,gBAAgB,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GACD;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd,GACD;IACE,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEN,MAAM,MAAM,kCAAkC,GAC1C;IACE,IAAI,EAAE,qBAAqB,CAAC;IAC5B,KAAK,EAAE,kCAAkC,CAAC;IAC1C,gBAAgB,EAAE,eAAe,CAAC;IAClC,cAAc,EAAE,KAAK,CAAC;CACvB,GACD;IACE,IAAI,EAAE,gCAAgC,CAAC;IACvC,KAAK,EAAE,gCAAgC,CAAC;IACxC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,cAAc,EAAE,IAAI,CAAC;IACrB,MAAM,EAAE,wBAAwB,CAAC;CAClC,CAAC;AAEN,MAAM,WAAW,2BAA2B;IAC1C,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,kBAAkB,EAAE,2BAA2B,CAAC;IAChD,sBAAsB,EAAE,kCAAkC,CAAC;IAC3D,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B;;;;OAIG;IACH,KAAK,CAAC,EAAE,0BAA0B,EAAE,CAAC;IACrC,kBAAkB,CAAC,EAAE;QACnB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAID;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B,8BAA8B,CAAC;AA0H3E,eAAO,MAAM,8BAA8B,EAAE,SAAS,2BAA2B,EAkwB9E,CAAC;AAUJ,wBAAgB,gCAAgC,IAAI,SAAS,2BAA2B,EAAE,CAEzF;AAED,wBAAgB,+BAA+B,CAC7C,iBAAiB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC3C,2BAA2B,GAAG,IAAI,CA0BpC"}
|