@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
@@ -33177,6 +33177,459 @@ var ASSET_TYPES = {
33177
33177
  var DEFAULT_CHUNK_BUDGET_BYTES = 180 * 1024;
33178
33178
  var textEncoder = new TextEncoder();
33179
33179
 
33180
+ // ../core/dist/integrations/oauth-providers.js
33181
+ var OAUTH_PROVIDERS = {
33182
+ "google-workspace": {
33183
+ definitionId: "google-workspace",
33184
+ authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
33185
+ tokenUrl: "https://oauth2.googleapis.com/token",
33186
+ revokeUrl: "https://oauth2.googleapis.com/revoke",
33187
+ defaultScopes: [
33188
+ "https://www.googleapis.com/auth/gmail.modify",
33189
+ "https://www.googleapis.com/auth/calendar",
33190
+ "https://www.googleapis.com/auth/drive",
33191
+ "https://www.googleapis.com/auth/spreadsheets",
33192
+ "https://www.googleapis.com/auth/documents",
33193
+ "https://www.googleapis.com/auth/chat.messages",
33194
+ "https://www.googleapis.com/auth/chat.spaces.readonly"
33195
+ ],
33196
+ supportsRefresh: true,
33197
+ extraAuthorizeParams: {
33198
+ access_type: "offline",
33199
+ prompt: "consent"
33200
+ },
33201
+ clientAuthMethod: "body",
33202
+ userInfoUrl: "https://www.googleapis.com/oauth2/v2/userinfo"
33203
+ },
33204
+ "github": {
33205
+ definitionId: "github",
33206
+ authorizeUrl: "https://github.com/login/oauth/authorize",
33207
+ tokenUrl: "https://github.com/login/oauth/access_token",
33208
+ // ENG-6187: revoke the existing grant on reconnect so GitHub re-prompts and
33209
+ // the four scopes below are actually granted. Without this, a stale narrow
33210
+ // grant (e.g. an old read:user-only authorization) is silently re-issued and
33211
+ // the missing-scopes banner loops forever.
33212
+ grantRevokeUrl: "https://api.github.com/applications/{client_id}/grant",
33213
+ defaultScopes: ["repo", "read:org", "gist", "workflow"],
33214
+ supportsRefresh: true,
33215
+ extraAuthorizeParams: {},
33216
+ clientAuthMethod: "body",
33217
+ userInfoUrl: "https://api.github.com/user"
33218
+ },
33219
+ "granola": {
33220
+ // Granola MCP — remote streamable-HTTP at https://mcp.granola.ai/mcp.
33221
+ // The AS is at mcp-auth.granola.ai and exposes RFC 8414 metadata at
33222
+ // /.well-known/oauth-authorization-server. Auth is OAuth 2.0 with
33223
+ // mandatory PKCE (S256) and a public client (no client_secret) issued
33224
+ // via Dynamic Client Registration (RFC 7591). The bootstrap script
33225
+ // (`packages/api/scripts/dcr-register.ts`) registers a client once at
33226
+ // deploy time; OAUTH_GRANOLA_CLIENT_ID is set from its output.
33227
+ definitionId: "granola",
33228
+ authorizeUrl: "https://mcp-auth.granola.ai/oauth2/authorize",
33229
+ tokenUrl: "https://mcp-auth.granola.ai/oauth2/token",
33230
+ // Minimal scope set: `offline_access` earns the refresh_token so the
33231
+ // refresh cron can rotate the bearer without operator action; `openid`
33232
+ // is required for the OIDC code flow even when we don't request an
33233
+ // id_token. Profile/email are intentionally omitted — we have no
33234
+ // userInfoUrl wired up here, so requesting them would over-ask consent
33235
+ // for fields the callback can't read.
33236
+ defaultScopes: ["openid", "offline_access"],
33237
+ supportsRefresh: true,
33238
+ extraAuthorizeParams: {},
33239
+ clientAuthMethod: "body",
33240
+ pkce: "S256",
33241
+ publicClient: true,
33242
+ mcpUrl: "https://mcp.granola.ai/mcp",
33243
+ // Curated surface (matches the catalog seed's defined_scopes[].tools).
33244
+ toolAllowlist: ["search-meetings", "read-transcript", "read-summary", "list-folders"]
33245
+ },
33246
+ "brand-ninja": {
33247
+ // ENG-6820: Brand Ninja External-Content MCP, remote streamable-HTTP at
33248
+ // https://ext-api.app.brandninja.ai/v1/mcp. Same shape as Granola: the
33249
+ // server exposes RFC 8414 authorization-server metadata at
33250
+ // /.well-known/oauth-authorization-server (values below are taken verbatim
33251
+ // from that document, not inferred). Auth is OAuth 2.0 authorization-code
33252
+ // with mandatory PKCE (S256) and a public client (token_endpoint_auth_method
33253
+ // 'none') issued via Dynamic Client Registration (RFC 7591). The bootstrap
33254
+ // script (packages/api/scripts/dcr-register.ts) registers a client once at
33255
+ // deploy time against the registration_endpoint
33256
+ // (https://ext-api.app.brandninja.ai/v1/oauth/register); OAUTH_BRAND_NINJA_CLIENT_ID
33257
+ // is set from its output. The AS advertises the refresh_token grant, so the
33258
+ // shared oauth-refresh cron rotates the bearer without operator action.
33259
+ definitionId: "brand-ninja",
33260
+ authorizeUrl: "https://prod-brandninja.auth.ap-southeast-2.amazoncognito.com/oauth2/authorize",
33261
+ tokenUrl: "https://prod-brandninja.auth.ap-southeast-2.amazoncognito.com/oauth2/token",
33262
+ // The resource server (ext-api.app.brandninja.ai) advertises exactly two
33263
+ // scopes: external-api/content.write (the default content surface) and
33264
+ // external-api/admin (read-only credential metadata, granted per account
33265
+ // admin). Default install is least-privilege: content.write only; an
33266
+ // operator can widen to admin out of band. No openid/offline_access in the
33267
+ // advertised scope set, so Cognito issues the refresh_token for the code grant
33268
+ // regardless, so requesting only the resource scope keeps consent minimal.
33269
+ defaultScopes: ["external-api/content.write"],
33270
+ supportsRefresh: true,
33271
+ extraAuthorizeParams: {},
33272
+ clientAuthMethod: "body",
33273
+ pkce: "S256",
33274
+ publicClient: true,
33275
+ mcpUrl: "https://ext-api.app.brandninja.ai/v1/mcp",
33276
+ // Curated surface (matches the catalog seed's defined_scopes[].tools).
33277
+ toolAllowlist: [
33278
+ "submit_content_request",
33279
+ "get_content_status",
33280
+ "list_content_requests",
33281
+ "list_channels",
33282
+ "list_brands",
33283
+ "list_topics",
33284
+ "list_timeline_templates",
33285
+ "list_content_types",
33286
+ "list_source_skills",
33287
+ "list_output_skills",
33288
+ "list_conversion_skills",
33289
+ "list_credentials",
33290
+ "search_transcripts",
33291
+ "create_source_clips",
33292
+ "create_timeline_ranking",
33293
+ "create_topic",
33294
+ "create_timeline_template",
33295
+ "create_knowledge",
33296
+ "link_knowledge"
33297
+ ]
33298
+ },
33299
+ "kajabi": {
33300
+ // Kajabi MCP — remote streamable-HTTP at https://mcp.kajabi.com/mcp.
33301
+ // Same Granola/Brand-Ninja shape: OAuth 2.0 authorization-code with
33302
+ // mandatory PKCE (S256) and a public client (token_endpoint_auth_method
33303
+ // 'none') issued via Dynamic Client Registration (RFC 7591). Values below
33304
+ // are taken verbatim from Kajabi's RFC 8414 metadata at
33305
+ // https://mcp.kajabi.com/.well-known/oauth-authorization-server (a Rails
33306
+ // Doorkeeper AS), not inferred. NOTE the authorize host differs from the
33307
+ // token host: authorize is on app.kajabi.com (the login surface), while
33308
+ // token/register/revoke are on mcp.kajabi.com — do NOT "normalise" them to
33309
+ // one host. The bootstrap script (packages/api/scripts/dcr-register.ts)
33310
+ // registers a client once at deploy time against
33311
+ // https://mcp.kajabi.com/mcp/oauth/register; OAUTH_KAJABI_CLIENT_ID is set
33312
+ // from its output. Doorkeeper RESTRICTS a dynamic client to the scopes it
33313
+ // registered with, so register with at least the union of defaultScopes
33314
+ // below (--scope 'read write:contacts write:emails write:content
33315
+ // write:commerce'). Widening defaultScopes forces a client re-register
33316
+ // (new client_id) AND a per-connection re-consent: existing tokens keep
33317
+ // the old scope set and their refreshes fail under the new client_id, so
33318
+ // each connection flips to needs_reauth until the user re-runs Connect
33319
+ // (ENG-7483). The AS advertises the refresh_token grant (no
33320
+ // openid/offline_access scope needed), so the shared oauth-refresh cron
33321
+ // rotates the bearer without operator action.
33322
+ definitionId: "kajabi",
33323
+ authorizeUrl: "https://app.kajabi.com/mcp/oauth/authorize",
33324
+ tokenUrl: "https://mcp.kajabi.com/mcp/oauth/token",
33325
+ revokeUrl: "https://mcp.kajabi.com/mcp/oauth/revoke",
33326
+ // Coarse Doorkeeper scopes (NOT openid-style). Cross-domain reads (`read`)
33327
+ // plus the write surfaces this integration ships: contact tags/segments,
33328
+ // email broadcasts/sequences, and course updates (write:content gates
33329
+ // update_course, the course-thumbnail path, ENG-7483). write:commerce is
33330
+ // requested now (Brad's call on ENG-7483) so a later offer/pricing-write
33331
+ // enablement needs no extra re-consent round; the tool allowlist below
33332
+ // still exposes no commerce write, so the callable surface stays minimal.
33333
+ defaultScopes: ["read", "write:contacts", "write:emails", "write:content", "write:commerce"],
33334
+ supportsRefresh: true,
33335
+ extraAuthorizeParams: {},
33336
+ clientAuthMethod: "body",
33337
+ pkce: "S256",
33338
+ publicClient: true,
33339
+ mcpUrl: "https://mcp.kajabi.com/mcp",
33340
+ // Curated surface (matches the catalog seed's defined_scopes[].tools). Kajabi's
33341
+ // live MCP advertises ~111 tools; the agent only needs these 28.
33342
+ // CS-1427: `enable_toolset` is included so an agent can activate its own
33343
+ // products/commerce + analytics toolsets on the connection (Kajabi gates those
33344
+ // tool groups behind a runtime toolset that returns "not active" until enabled).
33345
+ // Low-risk: this proxy still caps every tools/call to the allowlist, so a broad
33346
+ // activation can't widen what's actually callable.
33347
+ // ENG-7483: `get_course`/`update_course` enable the course-thumbnail refresh
33348
+ // (update_course covers title/description/thumbnail per Kajabi's MCP docs).
33349
+ // Fail-safe on naming drift: an allowlisted tool the server doesn't advertise
33350
+ // is logged and skipped by the proxy, never a break.
33351
+ toolAllowlist: [
33352
+ "list_sites",
33353
+ "get_site_summary",
33354
+ "select_site",
33355
+ "search_contacts",
33356
+ "get_contact",
33357
+ "search_products",
33358
+ "get_product",
33359
+ "list_offers",
33360
+ "get_offer",
33361
+ "list_offer_purchases",
33362
+ "get_revenue_analytics",
33363
+ "get_contacts_analytics",
33364
+ "list_tags",
33365
+ "create_tag",
33366
+ "tag_contact",
33367
+ "untag_contact",
33368
+ "list_segments",
33369
+ "create_segment",
33370
+ "update_segment",
33371
+ "list_broadcasts",
33372
+ "get_broadcast",
33373
+ "create_broadcast",
33374
+ "list_sequences",
33375
+ "get_sequence",
33376
+ "create_sequence",
33377
+ "enable_toolset",
33378
+ "get_course",
33379
+ "update_course",
33380
+ // ENG-7629 follow-up: pages (Dee's landing-page edit) + themes (CS-1448
33381
+ // theme-builder broadcast content). Callable via the proxy union manifest
33382
+ // + per-call enable; matches the new kajabi:pages catalog scope.
33383
+ "list_landing_pages",
33384
+ "get_landing_page",
33385
+ "update_landing_page",
33386
+ "get_theme_content"
33387
+ ],
33388
+ // CS-1446: Kajabi gates several tool groups behind a runtime `enable_toolset`
33389
+ // and does not advertise their tools in `tools/list` until the group is
33390
+ // active. The harness freezes its callable-tool manifest from the
33391
+ // connect-time `tools/list`, so a group the agent activates later never
33392
+ // becomes callable (repro: enable_toolset('courses') → get_course/
33393
+ // update_course still "No such tool available"). Pre-activate the gated
33394
+ // groups whose tools we allowlist so they are advertised in that first
33395
+ // manifest. Names are Kajabi's toolset ids (courses per CS-1446;
33396
+ // products/commerce/analytics per CS-1427). Best-effort + idempotent: an
33397
+ // unknown/unscoped name is logged and skipped by the proxy, and the
33398
+ // toolAllowlist above still caps what is actually callable.
33399
+ //
33400
+ // ENG-8392: `contacts` + `emails` were missing, so thirteen allowlisted
33401
+ // tools were unreachable by construction — list_tags, create_tag,
33402
+ // tag_contact, untag_contact, list_segments, create_segment,
33403
+ // update_segment (contacts) and list_broadcasts, get_broadcast,
33404
+ // create_broadcast, list_sequences, get_sequence, create_sequence
33405
+ // (emails). A customer agent was blocked on exactly those.
33406
+ //
33407
+ // These two ids are Kajabi's OWN spelling, not ours: the server names the
33408
+ // toolset in its rejection, e.g. `list_tags` returns
33409
+ // "The 'contacts' toolset is not active. Call enable_toolset with
33410
+ // name: 'contacts' to activate it first."
33411
+ // and `list_sequences` returns the same with 'emails'. Sourced that way
33412
+ // deliberately — a wrong id here is logged and SKIPPED by the proxy, so a
33413
+ // guess would look applied and change nothing.
33414
+ //
33415
+ // Why this went unnoticed for four rounds: `get_contacts_analytics` lives
33416
+ // in the `analytics` group, which we already pre-enable. So the contacts
33417
+ // family read as partly alive (you could see a site's contact count and
33418
+ // growth curve) while every tag and segment call failed.
33419
+ preEnableToolsets: [
33420
+ "courses",
33421
+ "products",
33422
+ "commerce",
33423
+ "analytics",
33424
+ "pages",
33425
+ "themes",
33426
+ "contacts",
33427
+ "emails"
33428
+ ],
33429
+ // ENG-8512: `update_course.thumbnail` stores a RELATIVE path into Kajabi's
33430
+ // own storage — it is rendered as
33431
+ // https://kajabi-storefronts-production.kajabi-cdn.com/kajabi-storefronts-production/<value>
33432
+ // so an absolute http(s) URL is structurally not a valid value for it.
33433
+ // Kajabi accepts one anyway, returns 200, echoes it back, ingests nothing,
33434
+ // and the course shows a broken image. Reported from a live client site
33435
+ // (DTI) via CS-1548 after it produced a false "done" report and three
33436
+ // failed cards.
33437
+ //
33438
+ // Anchored at the start so only an ABSOLUTE URL is refused; every relative
33439
+ // path — the valid shape — passes untouched. This does not enable setting a
33440
+ // thumbnail from a URL (that needs an upload path, CS-1548 item 4). It stops
33441
+ // us reporting success for a write that did not happen.
33442
+ argRejects: [
33443
+ {
33444
+ tool: "update_course",
33445
+ field: "thumbnail",
33446
+ pattern: "^\\s*https?://",
33447
+ 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."
33448
+ },
33449
+ // CS-1554: `search_contacts` accepts `tag_id`, does not apply it, and
33450
+ // returns the FULL unfiltered contact list with `filters_applied: null`.
33451
+ // Reported first-hand from a live client site (DTI) while auditing which
33452
+ // contacts carried an opt-in tag. Corroborating evidence: Kajabi's own
33453
+ // REST reference filters contacts with `filter[has_tag_id]`, not a bare
33454
+ // `tag_id` — so the argument is dropped as unrecognised and the response
33455
+ // says so, if you read `filters_applied`.
33456
+ //
33457
+ // Worse than the thumbnail case it sits next to. A broken image is
33458
+ // visible; an unfiltered list that reads as filtered produces a confident
33459
+ // wrong ANSWER, which a human then acts on. That is the same shape as the
33460
+ // incident in CS-1554 where the agent told the customer content did not
33461
+ // exist when it did.
33462
+ //
33463
+ // Any value at all is refused: the field is not partially supported, it
33464
+ // is inert. `[\s\S]` matches every stringified scalar including 0 and
33465
+ // false, which a `.`-style pattern anchored on truthiness would miss.
33466
+ //
33467
+ // NOT REPRODUCED BY ME — I have no Kajabi connection. This rests on the
33468
+ // CS-1554 first-hand report plus the REST reference. The file's own bar is
33469
+ // "provably wrong, never a guess", so a reviewer with a live Kajabi
33470
+ // connection should confirm before this merges. If `tag_id` DOES filter
33471
+ // for some tenant, drop this rule and keep the scalar fix.
33472
+ {
33473
+ tool: "search_contacts",
33474
+ field: "tag_id",
33475
+ pattern: "[\\s\\S]",
33476
+ 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."
33477
+ }
33478
+ ]
33479
+ },
33480
+ "notion-cli": {
33481
+ // Notion's public OAuth app. Tokens are workspace-scoped and long-lived —
33482
+ // Notion does not issue refresh_tokens, so `supportsRefresh: false` and
33483
+ // the refresh cron skips this provider entirely. Scopes are not part of
33484
+ // Notion's authorize URL contract; consent is governed by what the user
33485
+ // grants in the OAuth screen, so `defaultScopes` stays empty.
33486
+ // `owner=user` forces the user-OAuth variant (vs internal integration).
33487
+ // Requires OAUTH_NOTION_CLI_CLIENT_ID and OAUTH_NOTION_CLI_CLIENT_SECRET.
33488
+ definitionId: "notion-cli",
33489
+ authorizeUrl: "https://api.notion.com/v1/oauth/authorize",
33490
+ tokenUrl: "https://api.notion.com/v1/oauth/token",
33491
+ defaultScopes: [],
33492
+ supportsRefresh: false,
33493
+ extraAuthorizeParams: {
33494
+ owner: "user"
33495
+ },
33496
+ clientAuthMethod: "basic"
33497
+ },
33498
+ "xero": {
33499
+ definitionId: "xero",
33500
+ authorizeUrl: "https://login.xero.com/identity/connect/authorize",
33501
+ tokenUrl: "https://identity.xero.com/connect/token",
33502
+ revokeUrl: "https://identity.xero.com/connect/revocation",
33503
+ defaultScopes: [
33504
+ "openid",
33505
+ "profile",
33506
+ "email",
33507
+ "offline_access",
33508
+ // Granular scopes (required for apps created after March 2, 2026 —
33509
+ // do NOT revert to the broad `accounting.transactions` /
33510
+ // `accounting.contacts` scopes, Xero rejects the manifest).
33511
+ // The variant *without* `.read` is the read+write granular scope.
33512
+ "accounting.settings.read",
33513
+ // contacts: write enables agent-driven supplier/customer creation
33514
+ // (required for bill creation since a bill must reference a contact).
33515
+ "accounting.contacts",
33516
+ // invoices: write enables bill creation (Type=ACCPAY invoices) and
33517
+ // updates to sales invoices alongside the existing read access.
33518
+ "accounting.invoices",
33519
+ // attachments: write enables agents to attach the source PDF to a
33520
+ // bill at creation time. Read-only would force a follow-up manual
33521
+ // upload in Xero; write closes the loop.
33522
+ "accounting.attachments",
33523
+ // accounting.transactions.read → granular read-only replacements
33524
+ // for the surfaces we don't yet need write access on.
33525
+ "accounting.payments.read",
33526
+ "accounting.banktransactions.read",
33527
+ // manualjournals: write (CS-1439) enables the xero-broker to post
33528
+ // manual journals (reclasses, accruals, corrections) on approval. The
33529
+ // variant without `.read` is the read+write granular scope. Note: an
33530
+ // existing Xero install must RECONNECT for its token to carry this — the
33531
+ // broker posts journals with the agent's own OAuth access_token.
33532
+ "accounting.manualjournals",
33533
+ // accounting.reports.read → granular read-only replacements
33534
+ "accounting.reports.balancesheet.read",
33535
+ "accounting.reports.profitandloss.read",
33536
+ "accounting.reports.trialbalance.read",
33537
+ "accounting.reports.budgetsummary.read",
33538
+ "accounting.reports.banksummary.read",
33539
+ "accounting.reports.executivesummary.read",
33540
+ "accounting.reports.aged.read"
33541
+ ],
33542
+ // Read-only variant (ENG-6170): the `.read` granular scope for every
33543
+ // surface, so a token granted under it cannot create bills/invoices or
33544
+ // mutate contacts/attachments. Used when an install is (re)connected with
33545
+ // `read_only: true` — e.g. to lock a production-books integration to reads
33546
+ // until per-vendor broker mediation (ENG-4922) gates its writes.
33547
+ readOnlyScopes: [
33548
+ "openid",
33549
+ "profile",
33550
+ "email",
33551
+ "offline_access",
33552
+ "accounting.settings.read",
33553
+ "accounting.contacts.read",
33554
+ "accounting.invoices.read",
33555
+ "accounting.attachments.read",
33556
+ "accounting.payments.read",
33557
+ "accounting.banktransactions.read",
33558
+ "accounting.manualjournals.read",
33559
+ "accounting.reports.balancesheet.read",
33560
+ "accounting.reports.profitandloss.read",
33561
+ "accounting.reports.trialbalance.read",
33562
+ "accounting.reports.budgetsummary.read",
33563
+ "accounting.reports.banksummary.read",
33564
+ "accounting.reports.executivesummary.read",
33565
+ "accounting.reports.aged.read"
33566
+ ],
33567
+ supportsRefresh: true,
33568
+ extraAuthorizeParams: {},
33569
+ clientAuthMethod: "basic",
33570
+ userInfoUrl: "https://api.xero.com/connections"
33571
+ },
33572
+ // LinkedIn Ads (Marketing API). Confidential client with a static secret and
33573
+ // refresh tokens (~60-day access token, ~1-year rotating refresh token), so it
33574
+ // mirrors the Xero shape: clientAuthMethod 'body', supportsRefresh true, no
33575
+ // PKCE. The shared authorize/callback/refresh machinery handles the rest.
33576
+ //
33577
+ // The single shared app is Augmented Team's own LinkedIn developer app
33578
+ // (client id/secret in OAUTH_LINKEDIN_ADS_CLIENT_ID / _SECRET) - every org
33579
+ // connects its own ad accounts against it; only the per-connection tokens
33580
+ // differ. Register `${API_PUBLIC_URL}/integrations/oauth/callback` as an
33581
+ // Authorized redirect URL on the LinkedIn app.
33582
+ //
33583
+ // NOTE (linkedin-verify): the grantable scope set depends on which LinkedIn
33584
+ // API products the app is approved for (Advertising API, Lead Sync API,
33585
+ // Community Management API). Keep this list to scopes the app actually holds -
33586
+ // requesting an ungranted scope makes LinkedIn reject the authorize request.
33587
+ "linkedin-ads": {
33588
+ definitionId: "linkedin-ads",
33589
+ authorizeUrl: "https://www.linkedin.com/oauth/v2/authorization",
33590
+ tokenUrl: "https://www.linkedin.com/oauth/v2/accessToken",
33591
+ // ENG-7897: this list is EXACTLY the Advertising API scope set, because
33592
+ // Advertising API is the only product added to the Brand Ninja app. Every
33593
+ // other scope we used to request here belonged to a product the app does
33594
+ // not hold, and LinkedIn rejects the ENTIRE authorize request with
33595
+ // `unauthorized_scope_error` if ANY single requested scope is ungranted -
33596
+ // so five unapproved scopes bricked the connect for every customer, on
33597
+ // every environment, rather than merely disabling five features.
33598
+ //
33599
+ // Scopes deliberately NOT requested, and the product each needs first:
33600
+ // openid / profile / email -> Sign In with LinkedIn (OpenID Connect)
33601
+ // r_organization_social -> Community Management API
33602
+ // r_marketing_leadgen_automation -> Lead Sync API
33603
+ //
33604
+ // Dropping the OIDC trio costs only the `Connected as <name>` label: the
33605
+ // userInfoUrl fetch in the callback is already best-effort and falls back
33606
+ // to a plain 'Connected'. Do NOT re-add any of these until the matching
33607
+ // product shows under "Added products" on the app - use the
33608
+ // OAUTH_LINKEDIN_ADS_SCOPES override below to widen without a deploy once
33609
+ // an approval lands, and only then promote it into this constant.
33610
+ defaultScopes: [
33611
+ // Advertising API: read + manage campaigns/creatives, and reporting.
33612
+ "r_ads",
33613
+ "rw_ads",
33614
+ "r_ads_reporting"
33615
+ ],
33616
+ // Read-only variant: reporting only, no campaign/creative mutation. Used
33617
+ // when an install is (re)connected with read_only: true. Same product
33618
+ // constraint as above - `r_organization_social` was removed with it.
33619
+ readOnlyScopes: [
33620
+ "r_ads",
33621
+ "r_ads_reporting"
33622
+ ],
33623
+ supportsRefresh: true,
33624
+ extraAuthorizeParams: {},
33625
+ clientAuthMethod: "body",
33626
+ userInfoUrl: "https://api.linkedin.com/v2/userinfo"
33627
+ }
33628
+ };
33629
+ OAUTH_PROVIDERS["xero-control-plane"] = {
33630
+ ...OAUTH_PROVIDERS["xero"]
33631
+ };
33632
+
33180
33633
  // ../core/dist/integrations/composio-account-probe.js
33181
33634
  var BODY_MAX_BYTES = 1024 * 1024;
33182
33635