@integrity-labs/agt-cli 0.28.778 → 0.28.780

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. package/dist/bin/agt.js +5 -5
  2. package/dist/{chunk-NRMBKDER.js → chunk-HHFDK7WB.js} +2 -2
  3. package/dist/{chunk-N6DU2RYO.js → chunk-REPC7LF2.js} +101 -90
  4. package/dist/chunk-REPC7LF2.js.map +1 -0
  5. package/dist/{chunk-5S334W7F.js → chunk-VYFQRDSP.js} +9 -5
  6. package/dist/{chunk-5S334W7F.js.map → chunk-VYFQRDSP.js.map} +1 -1
  7. package/dist/{claude-pair-runtime-MI65DVTR.js → claude-pair-runtime-CK34MZ6M.js} +2 -2
  8. package/dist/lib/manager-worker.js +99 -15
  9. package/dist/lib/manager-worker.js.map +1 -1
  10. package/dist/mcp/direct-chat-channel.js +453 -0
  11. package/dist/mcp/index.js +453 -0
  12. package/dist/mcp/origami.js +453 -0
  13. package/dist/mcp/slack-channel.js +453 -0
  14. package/dist/mcp/telegram-channel.js +453 -0
  15. package/dist/{persistent-session-CGIB77UQ.js → persistent-session-ETZBTCXU.js} +3 -3
  16. package/dist/{responsiveness-probe-YINXZH3S.js → responsiveness-probe-EWUJOLVA.js} +3 -3
  17. package/dist/{session-auth-dead-OZBNHFPN.js → session-auth-dead-TDPTLVBO.js} +2 -2
  18. package/package.json +1 -1
  19. package/dist/chunk-N6DU2RYO.js.map +0 -1
  20. /package/dist/{chunk-NRMBKDER.js.map → chunk-HHFDK7WB.js.map} +0 -0
  21. /package/dist/{claude-pair-runtime-MI65DVTR.js.map → claude-pair-runtime-CK34MZ6M.js.map} +0 -0
  22. /package/dist/{persistent-session-CGIB77UQ.js.map → persistent-session-ETZBTCXU.js.map} +0 -0
  23. /package/dist/{responsiveness-probe-YINXZH3S.js.map → responsiveness-probe-EWUJOLVA.js.map} +0 -0
  24. /package/dist/{session-auth-dead-OZBNHFPN.js.map → session-auth-dead-TDPTLVBO.js.map} +0 -0
package/dist/mcp/index.js CHANGED
@@ -40371,6 +40371,459 @@ var ASSET_TYPES = {
40371
40371
  var DEFAULT_CHUNK_BUDGET_BYTES = 180 * 1024;
40372
40372
  var textEncoder = new TextEncoder();
40373
40373
 
40374
+ // ../core/dist/integrations/oauth-providers.js
40375
+ var OAUTH_PROVIDERS = {
40376
+ "google-workspace": {
40377
+ definitionId: "google-workspace",
40378
+ authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
40379
+ tokenUrl: "https://oauth2.googleapis.com/token",
40380
+ revokeUrl: "https://oauth2.googleapis.com/revoke",
40381
+ defaultScopes: [
40382
+ "https://www.googleapis.com/auth/gmail.modify",
40383
+ "https://www.googleapis.com/auth/calendar",
40384
+ "https://www.googleapis.com/auth/drive",
40385
+ "https://www.googleapis.com/auth/spreadsheets",
40386
+ "https://www.googleapis.com/auth/documents",
40387
+ "https://www.googleapis.com/auth/chat.messages",
40388
+ "https://www.googleapis.com/auth/chat.spaces.readonly"
40389
+ ],
40390
+ supportsRefresh: true,
40391
+ extraAuthorizeParams: {
40392
+ access_type: "offline",
40393
+ prompt: "consent"
40394
+ },
40395
+ clientAuthMethod: "body",
40396
+ userInfoUrl: "https://www.googleapis.com/oauth2/v2/userinfo"
40397
+ },
40398
+ "github": {
40399
+ definitionId: "github",
40400
+ authorizeUrl: "https://github.com/login/oauth/authorize",
40401
+ tokenUrl: "https://github.com/login/oauth/access_token",
40402
+ // ENG-6187: revoke the existing grant on reconnect so GitHub re-prompts and
40403
+ // the four scopes below are actually granted. Without this, a stale narrow
40404
+ // grant (e.g. an old read:user-only authorization) is silently re-issued and
40405
+ // the missing-scopes banner loops forever.
40406
+ grantRevokeUrl: "https://api.github.com/applications/{client_id}/grant",
40407
+ defaultScopes: ["repo", "read:org", "gist", "workflow"],
40408
+ supportsRefresh: true,
40409
+ extraAuthorizeParams: {},
40410
+ clientAuthMethod: "body",
40411
+ userInfoUrl: "https://api.github.com/user"
40412
+ },
40413
+ "granola": {
40414
+ // Granola MCP — remote streamable-HTTP at https://mcp.granola.ai/mcp.
40415
+ // The AS is at mcp-auth.granola.ai and exposes RFC 8414 metadata at
40416
+ // /.well-known/oauth-authorization-server. Auth is OAuth 2.0 with
40417
+ // mandatory PKCE (S256) and a public client (no client_secret) issued
40418
+ // via Dynamic Client Registration (RFC 7591). The bootstrap script
40419
+ // (`packages/api/scripts/dcr-register.ts`) registers a client once at
40420
+ // deploy time; OAUTH_GRANOLA_CLIENT_ID is set from its output.
40421
+ definitionId: "granola",
40422
+ authorizeUrl: "https://mcp-auth.granola.ai/oauth2/authorize",
40423
+ tokenUrl: "https://mcp-auth.granola.ai/oauth2/token",
40424
+ // Minimal scope set: `offline_access` earns the refresh_token so the
40425
+ // refresh cron can rotate the bearer without operator action; `openid`
40426
+ // is required for the OIDC code flow even when we don't request an
40427
+ // id_token. Profile/email are intentionally omitted — we have no
40428
+ // userInfoUrl wired up here, so requesting them would over-ask consent
40429
+ // for fields the callback can't read.
40430
+ defaultScopes: ["openid", "offline_access"],
40431
+ supportsRefresh: true,
40432
+ extraAuthorizeParams: {},
40433
+ clientAuthMethod: "body",
40434
+ pkce: "S256",
40435
+ publicClient: true,
40436
+ mcpUrl: "https://mcp.granola.ai/mcp",
40437
+ // Curated surface (matches the catalog seed's defined_scopes[].tools).
40438
+ toolAllowlist: ["search-meetings", "read-transcript", "read-summary", "list-folders"]
40439
+ },
40440
+ "brand-ninja": {
40441
+ // ENG-6820: Brand Ninja External-Content MCP, remote streamable-HTTP at
40442
+ // https://ext-api.app.brandninja.ai/v1/mcp. Same shape as Granola: the
40443
+ // server exposes RFC 8414 authorization-server metadata at
40444
+ // /.well-known/oauth-authorization-server (values below are taken verbatim
40445
+ // from that document, not inferred). Auth is OAuth 2.0 authorization-code
40446
+ // with mandatory PKCE (S256) and a public client (token_endpoint_auth_method
40447
+ // 'none') issued via Dynamic Client Registration (RFC 7591). The bootstrap
40448
+ // script (packages/api/scripts/dcr-register.ts) registers a client once at
40449
+ // deploy time against the registration_endpoint
40450
+ // (https://ext-api.app.brandninja.ai/v1/oauth/register); OAUTH_BRAND_NINJA_CLIENT_ID
40451
+ // is set from its output. The AS advertises the refresh_token grant, so the
40452
+ // shared oauth-refresh cron rotates the bearer without operator action.
40453
+ definitionId: "brand-ninja",
40454
+ authorizeUrl: "https://prod-brandninja.auth.ap-southeast-2.amazoncognito.com/oauth2/authorize",
40455
+ tokenUrl: "https://prod-brandninja.auth.ap-southeast-2.amazoncognito.com/oauth2/token",
40456
+ // The resource server (ext-api.app.brandninja.ai) advertises exactly two
40457
+ // scopes: external-api/content.write (the default content surface) and
40458
+ // external-api/admin (read-only credential metadata, granted per account
40459
+ // admin). Default install is least-privilege: content.write only; an
40460
+ // operator can widen to admin out of band. No openid/offline_access in the
40461
+ // advertised scope set, so Cognito issues the refresh_token for the code grant
40462
+ // regardless, so requesting only the resource scope keeps consent minimal.
40463
+ defaultScopes: ["external-api/content.write"],
40464
+ supportsRefresh: true,
40465
+ extraAuthorizeParams: {},
40466
+ clientAuthMethod: "body",
40467
+ pkce: "S256",
40468
+ publicClient: true,
40469
+ mcpUrl: "https://ext-api.app.brandninja.ai/v1/mcp",
40470
+ // Curated surface (matches the catalog seed's defined_scopes[].tools).
40471
+ toolAllowlist: [
40472
+ "submit_content_request",
40473
+ "get_content_status",
40474
+ "list_content_requests",
40475
+ "list_channels",
40476
+ "list_brands",
40477
+ "list_topics",
40478
+ "list_timeline_templates",
40479
+ "list_content_types",
40480
+ "list_source_skills",
40481
+ "list_output_skills",
40482
+ "list_conversion_skills",
40483
+ "list_credentials",
40484
+ "search_transcripts",
40485
+ "create_source_clips",
40486
+ "create_timeline_ranking",
40487
+ "create_topic",
40488
+ "create_timeline_template",
40489
+ "create_knowledge",
40490
+ "link_knowledge"
40491
+ ]
40492
+ },
40493
+ "kajabi": {
40494
+ // Kajabi MCP — remote streamable-HTTP at https://mcp.kajabi.com/mcp.
40495
+ // Same Granola/Brand-Ninja shape: OAuth 2.0 authorization-code with
40496
+ // mandatory PKCE (S256) and a public client (token_endpoint_auth_method
40497
+ // 'none') issued via Dynamic Client Registration (RFC 7591). Values below
40498
+ // are taken verbatim from Kajabi's RFC 8414 metadata at
40499
+ // https://mcp.kajabi.com/.well-known/oauth-authorization-server (a Rails
40500
+ // Doorkeeper AS), not inferred. NOTE the authorize host differs from the
40501
+ // token host: authorize is on app.kajabi.com (the login surface), while
40502
+ // token/register/revoke are on mcp.kajabi.com — do NOT "normalise" them to
40503
+ // one host. The bootstrap script (packages/api/scripts/dcr-register.ts)
40504
+ // registers a client once at deploy time against
40505
+ // https://mcp.kajabi.com/mcp/oauth/register; OAUTH_KAJABI_CLIENT_ID is set
40506
+ // from its output. Doorkeeper RESTRICTS a dynamic client to the scopes it
40507
+ // registered with, so register with at least the union of defaultScopes
40508
+ // below (--scope 'read write:contacts write:emails write:content
40509
+ // write:commerce'). Widening defaultScopes forces a client re-register
40510
+ // (new client_id) AND a per-connection re-consent: existing tokens keep
40511
+ // the old scope set and their refreshes fail under the new client_id, so
40512
+ // each connection flips to needs_reauth until the user re-runs Connect
40513
+ // (ENG-7483). The AS advertises the refresh_token grant (no
40514
+ // openid/offline_access scope needed), so the shared oauth-refresh cron
40515
+ // rotates the bearer without operator action.
40516
+ definitionId: "kajabi",
40517
+ authorizeUrl: "https://app.kajabi.com/mcp/oauth/authorize",
40518
+ tokenUrl: "https://mcp.kajabi.com/mcp/oauth/token",
40519
+ revokeUrl: "https://mcp.kajabi.com/mcp/oauth/revoke",
40520
+ // Coarse Doorkeeper scopes (NOT openid-style). Cross-domain reads (`read`)
40521
+ // plus the write surfaces this integration ships: contact tags/segments,
40522
+ // email broadcasts/sequences, and course updates (write:content gates
40523
+ // update_course, the course-thumbnail path, ENG-7483). write:commerce is
40524
+ // requested now (Brad's call on ENG-7483) so a later offer/pricing-write
40525
+ // enablement needs no extra re-consent round; the tool allowlist below
40526
+ // still exposes no commerce write, so the callable surface stays minimal.
40527
+ defaultScopes: ["read", "write:contacts", "write:emails", "write:content", "write:commerce"],
40528
+ supportsRefresh: true,
40529
+ extraAuthorizeParams: {},
40530
+ clientAuthMethod: "body",
40531
+ pkce: "S256",
40532
+ publicClient: true,
40533
+ mcpUrl: "https://mcp.kajabi.com/mcp",
40534
+ // Curated surface (matches the catalog seed's defined_scopes[].tools). Kajabi's
40535
+ // live MCP advertises ~111 tools; the agent only needs these 28.
40536
+ // CS-1427: `enable_toolset` is included so an agent can activate its own
40537
+ // products/commerce + analytics toolsets on the connection (Kajabi gates those
40538
+ // tool groups behind a runtime toolset that returns "not active" until enabled).
40539
+ // Low-risk: this proxy still caps every tools/call to the allowlist, so a broad
40540
+ // activation can't widen what's actually callable.
40541
+ // ENG-7483: `get_course`/`update_course` enable the course-thumbnail refresh
40542
+ // (update_course covers title/description/thumbnail per Kajabi's MCP docs).
40543
+ // Fail-safe on naming drift: an allowlisted tool the server doesn't advertise
40544
+ // is logged and skipped by the proxy, never a break.
40545
+ toolAllowlist: [
40546
+ "list_sites",
40547
+ "get_site_summary",
40548
+ "select_site",
40549
+ "search_contacts",
40550
+ "get_contact",
40551
+ "search_products",
40552
+ "get_product",
40553
+ "list_offers",
40554
+ "get_offer",
40555
+ "list_offer_purchases",
40556
+ "get_revenue_analytics",
40557
+ "get_contacts_analytics",
40558
+ "list_tags",
40559
+ "create_tag",
40560
+ "tag_contact",
40561
+ "untag_contact",
40562
+ "list_segments",
40563
+ "create_segment",
40564
+ "update_segment",
40565
+ "list_broadcasts",
40566
+ "get_broadcast",
40567
+ "create_broadcast",
40568
+ "list_sequences",
40569
+ "get_sequence",
40570
+ "create_sequence",
40571
+ "enable_toolset",
40572
+ "get_course",
40573
+ "update_course",
40574
+ // ENG-7629 follow-up: pages (Dee's landing-page edit) + themes (CS-1448
40575
+ // theme-builder broadcast content). Callable via the proxy union manifest
40576
+ // + per-call enable; matches the new kajabi:pages catalog scope.
40577
+ "list_landing_pages",
40578
+ "get_landing_page",
40579
+ "update_landing_page",
40580
+ "get_theme_content"
40581
+ ],
40582
+ // CS-1446: Kajabi gates several tool groups behind a runtime `enable_toolset`
40583
+ // and does not advertise their tools in `tools/list` until the group is
40584
+ // active. The harness freezes its callable-tool manifest from the
40585
+ // connect-time `tools/list`, so a group the agent activates later never
40586
+ // becomes callable (repro: enable_toolset('courses') → get_course/
40587
+ // update_course still "No such tool available"). Pre-activate the gated
40588
+ // groups whose tools we allowlist so they are advertised in that first
40589
+ // manifest. Names are Kajabi's toolset ids (courses per CS-1446;
40590
+ // products/commerce/analytics per CS-1427). Best-effort + idempotent: an
40591
+ // unknown/unscoped name is logged and skipped by the proxy, and the
40592
+ // toolAllowlist above still caps what is actually callable.
40593
+ //
40594
+ // ENG-8392: `contacts` + `emails` were missing, so thirteen allowlisted
40595
+ // tools were unreachable by construction — list_tags, create_tag,
40596
+ // tag_contact, untag_contact, list_segments, create_segment,
40597
+ // update_segment (contacts) and list_broadcasts, get_broadcast,
40598
+ // create_broadcast, list_sequences, get_sequence, create_sequence
40599
+ // (emails). A customer agent was blocked on exactly those.
40600
+ //
40601
+ // These two ids are Kajabi's OWN spelling, not ours: the server names the
40602
+ // toolset in its rejection, e.g. `list_tags` returns
40603
+ // "The 'contacts' toolset is not active. Call enable_toolset with
40604
+ // name: 'contacts' to activate it first."
40605
+ // and `list_sequences` returns the same with 'emails'. Sourced that way
40606
+ // deliberately — a wrong id here is logged and SKIPPED by the proxy, so a
40607
+ // guess would look applied and change nothing.
40608
+ //
40609
+ // Why this went unnoticed for four rounds: `get_contacts_analytics` lives
40610
+ // in the `analytics` group, which we already pre-enable. So the contacts
40611
+ // family read as partly alive (you could see a site's contact count and
40612
+ // growth curve) while every tag and segment call failed.
40613
+ preEnableToolsets: [
40614
+ "courses",
40615
+ "products",
40616
+ "commerce",
40617
+ "analytics",
40618
+ "pages",
40619
+ "themes",
40620
+ "contacts",
40621
+ "emails"
40622
+ ],
40623
+ // ENG-8512: `update_course.thumbnail` stores a RELATIVE path into Kajabi's
40624
+ // own storage — it is rendered as
40625
+ // https://kajabi-storefronts-production.kajabi-cdn.com/kajabi-storefronts-production/<value>
40626
+ // so an absolute http(s) URL is structurally not a valid value for it.
40627
+ // Kajabi accepts one anyway, returns 200, echoes it back, ingests nothing,
40628
+ // and the course shows a broken image. Reported from a live client site
40629
+ // (DTI) via CS-1548 after it produced a false "done" report and three
40630
+ // failed cards.
40631
+ //
40632
+ // Anchored at the start so only an ABSOLUTE URL is refused; every relative
40633
+ // path — the valid shape — passes untouched. This does not enable setting a
40634
+ // thumbnail from a URL (that needs an upload path, CS-1548 item 4). It stops
40635
+ // us reporting success for a write that did not happen.
40636
+ argRejects: [
40637
+ {
40638
+ tool: "update_course",
40639
+ field: "thumbnail",
40640
+ pattern: "^\\s*https?://",
40641
+ message: "thumbnail takes a relative path inside Kajabi storage, not an external URL. Kajabi accepts a URL here, returns 200 and never ingests it, so the image would silently stay broken. Upload the asset to Kajabi first and pass the storage path it returns."
40642
+ },
40643
+ // CS-1554: `search_contacts` accepts `tag_id`, does not apply it, and
40644
+ // returns the FULL unfiltered contact list with `filters_applied: null`.
40645
+ // Reported first-hand from a live client site (DTI) while auditing which
40646
+ // contacts carried an opt-in tag. Corroborating evidence: Kajabi's own
40647
+ // REST reference filters contacts with `filter[has_tag_id]`, not a bare
40648
+ // `tag_id` — so the argument is dropped as unrecognised and the response
40649
+ // says so, if you read `filters_applied`.
40650
+ //
40651
+ // Worse than the thumbnail case it sits next to. A broken image is
40652
+ // visible; an unfiltered list that reads as filtered produces a confident
40653
+ // wrong ANSWER, which a human then acts on. That is the same shape as the
40654
+ // incident in CS-1554 where the agent told the customer content did not
40655
+ // exist when it did.
40656
+ //
40657
+ // Any value at all is refused: the field is not partially supported, it
40658
+ // is inert. `[\s\S]` matches every stringified scalar including 0 and
40659
+ // false, which a `.`-style pattern anchored on truthiness would miss.
40660
+ //
40661
+ // NOT REPRODUCED BY ME — I have no Kajabi connection. This rests on the
40662
+ // CS-1554 first-hand report plus the REST reference. The file's own bar is
40663
+ // "provably wrong, never a guess", so a reviewer with a live Kajabi
40664
+ // connection should confirm before this merges. If `tag_id` DOES filter
40665
+ // for some tenant, drop this rule and keep the scalar fix.
40666
+ {
40667
+ tool: "search_contacts",
40668
+ field: "tag_id",
40669
+ pattern: "[\\s\\S]",
40670
+ message: "tag_id is accepted by Kajabi and never applied \u2014 the call returns the FULL contact list with filters_applied: null, which reads as a filtered result and is not one. There is no working tag filter on this tool today. Use list_tags plus the per-contact tag data to determine membership, and treat any tag audit built on search_contacts(tag_id) as unfiltered."
40671
+ }
40672
+ ]
40673
+ },
40674
+ "notion-cli": {
40675
+ // Notion's public OAuth app. Tokens are workspace-scoped and long-lived —
40676
+ // Notion does not issue refresh_tokens, so `supportsRefresh: false` and
40677
+ // the refresh cron skips this provider entirely. Scopes are not part of
40678
+ // Notion's authorize URL contract; consent is governed by what the user
40679
+ // grants in the OAuth screen, so `defaultScopes` stays empty.
40680
+ // `owner=user` forces the user-OAuth variant (vs internal integration).
40681
+ // Requires OAUTH_NOTION_CLI_CLIENT_ID and OAUTH_NOTION_CLI_CLIENT_SECRET.
40682
+ definitionId: "notion-cli",
40683
+ authorizeUrl: "https://api.notion.com/v1/oauth/authorize",
40684
+ tokenUrl: "https://api.notion.com/v1/oauth/token",
40685
+ defaultScopes: [],
40686
+ supportsRefresh: false,
40687
+ extraAuthorizeParams: {
40688
+ owner: "user"
40689
+ },
40690
+ clientAuthMethod: "basic"
40691
+ },
40692
+ "xero": {
40693
+ definitionId: "xero",
40694
+ authorizeUrl: "https://login.xero.com/identity/connect/authorize",
40695
+ tokenUrl: "https://identity.xero.com/connect/token",
40696
+ revokeUrl: "https://identity.xero.com/connect/revocation",
40697
+ defaultScopes: [
40698
+ "openid",
40699
+ "profile",
40700
+ "email",
40701
+ "offline_access",
40702
+ // Granular scopes (required for apps created after March 2, 2026 —
40703
+ // do NOT revert to the broad `accounting.transactions` /
40704
+ // `accounting.contacts` scopes, Xero rejects the manifest).
40705
+ // The variant *without* `.read` is the read+write granular scope.
40706
+ "accounting.settings.read",
40707
+ // contacts: write enables agent-driven supplier/customer creation
40708
+ // (required for bill creation since a bill must reference a contact).
40709
+ "accounting.contacts",
40710
+ // invoices: write enables bill creation (Type=ACCPAY invoices) and
40711
+ // updates to sales invoices alongside the existing read access.
40712
+ "accounting.invoices",
40713
+ // attachments: write enables agents to attach the source PDF to a
40714
+ // bill at creation time. Read-only would force a follow-up manual
40715
+ // upload in Xero; write closes the loop.
40716
+ "accounting.attachments",
40717
+ // accounting.transactions.read → granular read-only replacements
40718
+ // for the surfaces we don't yet need write access on.
40719
+ "accounting.payments.read",
40720
+ "accounting.banktransactions.read",
40721
+ // manualjournals: write (CS-1439) enables the xero-broker to post
40722
+ // manual journals (reclasses, accruals, corrections) on approval. The
40723
+ // variant without `.read` is the read+write granular scope. Note: an
40724
+ // existing Xero install must RECONNECT for its token to carry this — the
40725
+ // broker posts journals with the agent's own OAuth access_token.
40726
+ "accounting.manualjournals",
40727
+ // accounting.reports.read → granular read-only replacements
40728
+ "accounting.reports.balancesheet.read",
40729
+ "accounting.reports.profitandloss.read",
40730
+ "accounting.reports.trialbalance.read",
40731
+ "accounting.reports.budgetsummary.read",
40732
+ "accounting.reports.banksummary.read",
40733
+ "accounting.reports.executivesummary.read",
40734
+ "accounting.reports.aged.read"
40735
+ ],
40736
+ // Read-only variant (ENG-6170): the `.read` granular scope for every
40737
+ // surface, so a token granted under it cannot create bills/invoices or
40738
+ // mutate contacts/attachments. Used when an install is (re)connected with
40739
+ // `read_only: true` — e.g. to lock a production-books integration to reads
40740
+ // until per-vendor broker mediation (ENG-4922) gates its writes.
40741
+ readOnlyScopes: [
40742
+ "openid",
40743
+ "profile",
40744
+ "email",
40745
+ "offline_access",
40746
+ "accounting.settings.read",
40747
+ "accounting.contacts.read",
40748
+ "accounting.invoices.read",
40749
+ "accounting.attachments.read",
40750
+ "accounting.payments.read",
40751
+ "accounting.banktransactions.read",
40752
+ "accounting.manualjournals.read",
40753
+ "accounting.reports.balancesheet.read",
40754
+ "accounting.reports.profitandloss.read",
40755
+ "accounting.reports.trialbalance.read",
40756
+ "accounting.reports.budgetsummary.read",
40757
+ "accounting.reports.banksummary.read",
40758
+ "accounting.reports.executivesummary.read",
40759
+ "accounting.reports.aged.read"
40760
+ ],
40761
+ supportsRefresh: true,
40762
+ extraAuthorizeParams: {},
40763
+ clientAuthMethod: "basic",
40764
+ userInfoUrl: "https://api.xero.com/connections"
40765
+ },
40766
+ // LinkedIn Ads (Marketing API). Confidential client with a static secret and
40767
+ // refresh tokens (~60-day access token, ~1-year rotating refresh token), so it
40768
+ // mirrors the Xero shape: clientAuthMethod 'body', supportsRefresh true, no
40769
+ // PKCE. The shared authorize/callback/refresh machinery handles the rest.
40770
+ //
40771
+ // The single shared app is Augmented Team's own LinkedIn developer app
40772
+ // (client id/secret in OAUTH_LINKEDIN_ADS_CLIENT_ID / _SECRET) - every org
40773
+ // connects its own ad accounts against it; only the per-connection tokens
40774
+ // differ. Register `${API_PUBLIC_URL}/integrations/oauth/callback` as an
40775
+ // Authorized redirect URL on the LinkedIn app.
40776
+ //
40777
+ // NOTE (linkedin-verify): the grantable scope set depends on which LinkedIn
40778
+ // API products the app is approved for (Advertising API, Lead Sync API,
40779
+ // Community Management API). Keep this list to scopes the app actually holds -
40780
+ // requesting an ungranted scope makes LinkedIn reject the authorize request.
40781
+ "linkedin-ads": {
40782
+ definitionId: "linkedin-ads",
40783
+ authorizeUrl: "https://www.linkedin.com/oauth/v2/authorization",
40784
+ tokenUrl: "https://www.linkedin.com/oauth/v2/accessToken",
40785
+ // ENG-7897: this list is EXACTLY the Advertising API scope set, because
40786
+ // Advertising API is the only product added to the Brand Ninja app. Every
40787
+ // other scope we used to request here belonged to a product the app does
40788
+ // not hold, and LinkedIn rejects the ENTIRE authorize request with
40789
+ // `unauthorized_scope_error` if ANY single requested scope is ungranted -
40790
+ // so five unapproved scopes bricked the connect for every customer, on
40791
+ // every environment, rather than merely disabling five features.
40792
+ //
40793
+ // Scopes deliberately NOT requested, and the product each needs first:
40794
+ // openid / profile / email -> Sign In with LinkedIn (OpenID Connect)
40795
+ // r_organization_social -> Community Management API
40796
+ // r_marketing_leadgen_automation -> Lead Sync API
40797
+ //
40798
+ // Dropping the OIDC trio costs only the `Connected as <name>` label: the
40799
+ // userInfoUrl fetch in the callback is already best-effort and falls back
40800
+ // to a plain 'Connected'. Do NOT re-add any of these until the matching
40801
+ // product shows under "Added products" on the app - use the
40802
+ // OAUTH_LINKEDIN_ADS_SCOPES override below to widen without a deploy once
40803
+ // an approval lands, and only then promote it into this constant.
40804
+ defaultScopes: [
40805
+ // Advertising API: read + manage campaigns/creatives, and reporting.
40806
+ "r_ads",
40807
+ "rw_ads",
40808
+ "r_ads_reporting"
40809
+ ],
40810
+ // Read-only variant: reporting only, no campaign/creative mutation. Used
40811
+ // when an install is (re)connected with read_only: true. Same product
40812
+ // constraint as above - `r_organization_social` was removed with it.
40813
+ readOnlyScopes: [
40814
+ "r_ads",
40815
+ "r_ads_reporting"
40816
+ ],
40817
+ supportsRefresh: true,
40818
+ extraAuthorizeParams: {},
40819
+ clientAuthMethod: "body",
40820
+ userInfoUrl: "https://api.linkedin.com/v2/userinfo"
40821
+ }
40822
+ };
40823
+ OAUTH_PROVIDERS["xero-control-plane"] = {
40824
+ ...OAUTH_PROVIDERS["xero"]
40825
+ };
40826
+
40374
40827
  // ../core/dist/integrations/composio-account-probe.js
40375
40828
  var BODY_MAX_BYTES = 1024 * 1024;
40376
40829