@integrity-labs/agt-cli 0.28.21 → 0.28.22

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.
@@ -1306,45 +1306,442 @@ var HOURLY_BY_REGION = {
1306
1306
  };
1307
1307
  var KNOWN_PRICING_REGIONS = Object.keys(HOURLY_BY_REGION);
1308
1308
 
1309
- // ../../packages/core/dist/integrations/composio-linkage.js
1310
- function assessAuthConfigLinkage(input) {
1311
- const { accountAuthConfigId, serverAuthConfigIds, serverId } = input;
1312
- const serverLabel = serverId ? ` (${serverId})` : "";
1313
- if (serverAuthConfigIds == null || !accountAuthConfigId) {
1309
+ // ../../packages/core/dist/integrations/oauth-providers.js
1310
+ var OAUTH_PROVIDERS = {
1311
+ "google-workspace": {
1312
+ definitionId: "google-workspace",
1313
+ authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
1314
+ tokenUrl: "https://oauth2.googleapis.com/token",
1315
+ revokeUrl: "https://oauth2.googleapis.com/revoke",
1316
+ defaultScopes: [
1317
+ "https://www.googleapis.com/auth/gmail.modify",
1318
+ "https://www.googleapis.com/auth/calendar",
1319
+ "https://www.googleapis.com/auth/drive",
1320
+ "https://www.googleapis.com/auth/spreadsheets",
1321
+ "https://www.googleapis.com/auth/documents",
1322
+ "https://www.googleapis.com/auth/chat.messages",
1323
+ "https://www.googleapis.com/auth/chat.spaces.readonly"
1324
+ ],
1325
+ supportsRefresh: true,
1326
+ extraAuthorizeParams: {
1327
+ access_type: "offline",
1328
+ prompt: "consent"
1329
+ },
1330
+ clientAuthMethod: "body",
1331
+ userInfoUrl: "https://www.googleapis.com/oauth2/v2/userinfo"
1332
+ },
1333
+ "github": {
1334
+ definitionId: "github",
1335
+ authorizeUrl: "https://github.com/login/oauth/authorize",
1336
+ tokenUrl: "https://github.com/login/oauth/access_token",
1337
+ // ENG-6187: revoke the existing grant on reconnect so GitHub re-prompts and
1338
+ // the four scopes below are actually granted. Without this, a stale narrow
1339
+ // grant (e.g. an old read:user-only authorization) is silently re-issued and
1340
+ // the missing-scopes banner loops forever.
1341
+ grantRevokeUrl: "https://api.github.com/applications/{client_id}/grant",
1342
+ defaultScopes: ["repo", "read:org", "gist", "workflow"],
1343
+ supportsRefresh: true,
1344
+ extraAuthorizeParams: {},
1345
+ clientAuthMethod: "body",
1346
+ userInfoUrl: "https://api.github.com/user"
1347
+ },
1348
+ "granola": {
1349
+ // Granola MCP — remote streamable-HTTP at https://mcp.granola.ai/mcp.
1350
+ // The AS is at mcp-auth.granola.ai and exposes RFC 8414 metadata at
1351
+ // /.well-known/oauth-authorization-server. Auth is OAuth 2.0 with
1352
+ // mandatory PKCE (S256) and a public client (no client_secret) issued
1353
+ // via Dynamic Client Registration (RFC 7591). The bootstrap script
1354
+ // (`packages/api/scripts/dcr-register.ts`) registers a client once at
1355
+ // deploy time; OAUTH_GRANOLA_CLIENT_ID is set from its output.
1356
+ definitionId: "granola",
1357
+ authorizeUrl: "https://mcp-auth.granola.ai/oauth2/authorize",
1358
+ tokenUrl: "https://mcp-auth.granola.ai/oauth2/token",
1359
+ // Minimal scope set: `offline_access` earns the refresh_token so the
1360
+ // refresh cron can rotate the bearer without operator action; `openid`
1361
+ // is required for the OIDC code flow even when we don't request an
1362
+ // id_token. Profile/email are intentionally omitted — we have no
1363
+ // userInfoUrl wired up here, so requesting them would over-ask consent
1364
+ // for fields the callback can't read.
1365
+ defaultScopes: ["openid", "offline_access"],
1366
+ supportsRefresh: true,
1367
+ extraAuthorizeParams: {},
1368
+ clientAuthMethod: "body",
1369
+ pkce: "S256",
1370
+ publicClient: true,
1371
+ mcpUrl: "https://mcp.granola.ai/mcp"
1372
+ },
1373
+ "notion-cli": {
1374
+ // Notion's public OAuth app. Tokens are workspace-scoped and long-lived —
1375
+ // Notion does not issue refresh_tokens, so `supportsRefresh: false` and
1376
+ // the refresh cron skips this provider entirely. Scopes are not part of
1377
+ // Notion's authorize URL contract; consent is governed by what the user
1378
+ // grants in the OAuth screen, so `defaultScopes` stays empty.
1379
+ // `owner=user` forces the user-OAuth variant (vs internal integration).
1380
+ // Requires OAUTH_NOTION_CLI_CLIENT_ID and OAUTH_NOTION_CLI_CLIENT_SECRET.
1381
+ definitionId: "notion-cli",
1382
+ authorizeUrl: "https://api.notion.com/v1/oauth/authorize",
1383
+ tokenUrl: "https://api.notion.com/v1/oauth/token",
1384
+ defaultScopes: [],
1385
+ supportsRefresh: false,
1386
+ extraAuthorizeParams: {
1387
+ owner: "user"
1388
+ },
1389
+ clientAuthMethod: "basic"
1390
+ },
1391
+ "xero": {
1392
+ definitionId: "xero",
1393
+ authorizeUrl: "https://login.xero.com/identity/connect/authorize",
1394
+ tokenUrl: "https://identity.xero.com/connect/token",
1395
+ revokeUrl: "https://identity.xero.com/connect/revocation",
1396
+ defaultScopes: [
1397
+ "openid",
1398
+ "profile",
1399
+ "email",
1400
+ "offline_access",
1401
+ // Granular scopes (required for apps created after March 2, 2026 —
1402
+ // do NOT revert to the broad `accounting.transactions` /
1403
+ // `accounting.contacts` scopes, Xero rejects the manifest).
1404
+ // The variant *without* `.read` is the read+write granular scope.
1405
+ "accounting.settings.read",
1406
+ // contacts: write enables agent-driven supplier/customer creation
1407
+ // (required for bill creation since a bill must reference a contact).
1408
+ "accounting.contacts",
1409
+ // invoices: write enables bill creation (Type=ACCPAY invoices) and
1410
+ // updates to sales invoices alongside the existing read access.
1411
+ "accounting.invoices",
1412
+ // attachments: write enables agents to attach the source PDF to a
1413
+ // bill at creation time. Read-only would force a follow-up manual
1414
+ // upload in Xero; write closes the loop.
1415
+ "accounting.attachments",
1416
+ // accounting.transactions.read → granular read-only replacements
1417
+ // for the surfaces we don't yet need write access on.
1418
+ "accounting.payments.read",
1419
+ "accounting.banktransactions.read",
1420
+ "accounting.manualjournals.read",
1421
+ // accounting.reports.read → granular read-only replacements
1422
+ "accounting.reports.balancesheet.read",
1423
+ "accounting.reports.profitandloss.read",
1424
+ "accounting.reports.trialbalance.read",
1425
+ "accounting.reports.budgetsummary.read",
1426
+ "accounting.reports.banksummary.read",
1427
+ "accounting.reports.executivesummary.read",
1428
+ "accounting.reports.aged.read"
1429
+ ],
1430
+ // Read-only variant (ENG-6170): the `.read` granular scope for every
1431
+ // surface, so a token granted under it cannot create bills/invoices or
1432
+ // mutate contacts/attachments. Used when an install is (re)connected with
1433
+ // `read_only: true` — e.g. to lock a production-books integration to reads
1434
+ // until per-vendor broker mediation (ENG-4922) gates its writes.
1435
+ readOnlyScopes: [
1436
+ "openid",
1437
+ "profile",
1438
+ "email",
1439
+ "offline_access",
1440
+ "accounting.settings.read",
1441
+ "accounting.contacts.read",
1442
+ "accounting.invoices.read",
1443
+ "accounting.attachments.read",
1444
+ "accounting.payments.read",
1445
+ "accounting.banktransactions.read",
1446
+ "accounting.manualjournals.read",
1447
+ "accounting.reports.balancesheet.read",
1448
+ "accounting.reports.profitandloss.read",
1449
+ "accounting.reports.trialbalance.read",
1450
+ "accounting.reports.budgetsummary.read",
1451
+ "accounting.reports.banksummary.read",
1452
+ "accounting.reports.executivesummary.read",
1453
+ "accounting.reports.aged.read"
1454
+ ],
1455
+ supportsRefresh: true,
1456
+ extraAuthorizeParams: {},
1457
+ clientAuthMethod: "basic",
1458
+ userInfoUrl: "https://api.xero.com/connections"
1459
+ }
1460
+ };
1461
+ function getOAuthProvider(definitionId) {
1462
+ return OAUTH_PROVIDERS[definitionId];
1463
+ }
1464
+
1465
+ // ../../packages/core/dist/integrations/connectivity-probe.js
1466
+ var CONNECTIVITY_SEVERITY = {
1467
+ ok: 0,
1468
+ transient_error: 1,
1469
+ degraded: 2,
1470
+ down: 3
1471
+ };
1472
+ function worseConnectivityOutcome(a, b) {
1473
+ return CONNECTIVITY_SEVERITY[b.status] > CONNECTIVITY_SEVERITY[a.status] ? b : a;
1474
+ }
1475
+ var HTTP_PROBE_PROVIDERS = /* @__PURE__ */ new Set([
1476
+ "linear",
1477
+ "google-workspace",
1478
+ "xero",
1479
+ "v0"
1480
+ // ENG-6100: GitHub is deliberately NOT here. This set drives the ASYNC
1481
+ // connectivity monitor's routing, where github (source_type='native')
1482
+ // stays host-side (cli_command — `gh`, the credential the agent actually
1483
+ // executes with) rather than a central stored-token probe. The
1484
+ // synchronous Test button DOES probe the centrally-stored token via
1485
+ // `probeHttpProvider` (PROBE_DEFINITIONS in connectivity-http-probes.ts
1486
+ // includes 'github') — a narrower, honest "the token we stored is valid"
1487
+ // check. Unifying the monitor onto the central probe is sub-issue C's call.
1488
+ ]);
1489
+ var CLI_PROBE_ARGS = {
1490
+ gcloud: ["version"],
1491
+ // ENG-6206: `gh --version` only proves the binary exists, not that it's
1492
+ // authenticated — so a missing/mis-named token read green (the false-green
1493
+ // that hid the broken fleet). `gh auth status` exits non-zero when not
1494
+ // logged in, the honest signal. Read-only. Requires the runner to pass the
1495
+ // agent's GH_TOKEN/GITHUB_TOKEN env (see manager-worker runCli wiring).
1496
+ github: ["auth", "status"]
1497
+ // most CLIs respond to --version; override here only when they don't.
1498
+ };
1499
+ function cliArgsFor(definitionId, ct) {
1500
+ if (Array.isArray(ct?.args) && ct.args.length > 0 && ct.args.every((a) => typeof a === "string")) {
1501
+ return ct.args;
1502
+ }
1503
+ return CLI_PROBE_ARGS[definitionId] ?? ["--version"];
1504
+ }
1505
+ function mcpOverrideFrom(ct) {
1506
+ const tool = typeof ct?.tool === "string" && ct.tool.trim().length > 0 ? ct.tool.trim() : void 0;
1507
+ if (!tool)
1508
+ return {};
1509
+ const args = ct?.args && typeof ct.args === "object" && !Array.isArray(ct.args) ? ct.args : void 0;
1510
+ return { probeTool: tool, ...args ? { probeArgs: args } : {} };
1511
+ }
1512
+ function resolveConnectivityProbe(input) {
1513
+ const { definitionId, sourceType, authType } = input;
1514
+ if (authType === "managed" || sourceType === "managed") {
1314
1515
  return {
1315
- linked: null,
1316
- message: "auth_config linkage not verified \u2014 " + (serverAuthConfigIds == null ? "couldn't read the wired MCP server's auth config binding" : "Composio returned no auth_config for the connected account"),
1317
- details: {
1318
- accountAuthConfigId: accountAuthConfigId ?? null,
1319
- serverAuthConfigIds: serverAuthConfigIds ?? null,
1320
- serverId: serverId ?? null
1321
- }
1516
+ kind: "managed_composite",
1517
+ sourceType: "managed",
1518
+ readOnly: true,
1519
+ label: `${definitionId}: MCP tools/list + account binding (managed)`,
1520
+ centralReachable: false,
1521
+ // ENG-6212: carry the operator-stored override tool (if any) so both the
1522
+ // host executor and the central Test path call the same specific tool.
1523
+ ...mcpOverrideFrom(input.connectivityTest)
1322
1524
  };
1323
1525
  }
1324
- if (serverAuthConfigIds.length === 0) {
1526
+ if (HTTP_PROBE_PROVIDERS.has(definitionId)) {
1325
1527
  return {
1326
- linked: false,
1327
- message: `The agent's wired MCP server${serverLabel} has no auth config bound, so it cannot resolve the connected account (bound to auth_config ${accountAuthConfigId}) \u2014 reconnect/rebind required.`,
1328
- details: { accountAuthConfigId, serverAuthConfigIds, serverId: serverId ?? null }
1528
+ kind: "http_provider",
1529
+ sourceType: sourceType ?? "mcp_server",
1530
+ readOnly: true,
1531
+ label: `${definitionId}: read-only API check`,
1532
+ centralReachable: true,
1533
+ httpProvider: definitionId
1329
1534
  };
1330
1535
  }
1331
- if (serverAuthConfigIds.includes(accountAuthConfigId)) {
1536
+ if (getOAuthProvider(definitionId)?.mcpUrl) {
1332
1537
  return {
1333
- linked: true,
1334
- message: `Connected account's auth_config (${accountAuthConfigId}) matches the wired MCP server binding.`,
1335
- details: { accountAuthConfigId, serverAuthConfigIds, serverId: serverId ?? null }
1538
+ kind: "mcp_tools_list",
1539
+ sourceType: sourceType ?? "mcp_server",
1540
+ readOnly: true,
1541
+ label: `${definitionId}: MCP tools/list`,
1542
+ centralReachable: true
1336
1543
  };
1337
1544
  }
1338
- return {
1339
- linked: false,
1340
- message: `The connected account is bound to auth_config ${accountAuthConfigId}, but the agent's wired MCP server${serverLabel} resolves auth_config(s) [${serverAuthConfigIds.join(", ")}] \u2014 tool calls will fail with "No connected account found". Reconnect/rebind required.`,
1341
- details: { accountAuthConfigId, serverAuthConfigIds, serverId: serverId ?? null }
1342
- };
1343
- }
1344
-
1345
- // ../../packages/core/dist/integrations/composio-account-probe.js
1346
- var PROBE_TIMEOUT_MS = 1e4;
1347
- var COMPOSIO_API_BASE = "https://backend.composio.dev";
1545
+ switch (sourceType) {
1546
+ case "mcp_server":
1547
+ return {
1548
+ kind: "unsupported",
1549
+ sourceType: "mcp_server",
1550
+ readOnly: true,
1551
+ label: `${definitionId}: local-stdio MCP \u2014 no host probe available`,
1552
+ centralReachable: false
1553
+ };
1554
+ case "cli_tool":
1555
+ return {
1556
+ kind: "cli_command",
1557
+ sourceType: "cli_tool",
1558
+ readOnly: true,
1559
+ label: `${definitionId}: CLI reachability`,
1560
+ centralReachable: false,
1561
+ cliArgs: cliArgsFor(definitionId, input.connectivityTest)
1562
+ };
1563
+ case "native":
1564
+ return {
1565
+ kind: "builtin",
1566
+ sourceType: "native",
1567
+ readOnly: true,
1568
+ label: `${definitionId}: built-in check`,
1569
+ centralReachable: false
1570
+ };
1571
+ default:
1572
+ return {
1573
+ kind: "unsupported",
1574
+ sourceType: sourceType ?? "native",
1575
+ readOnly: true,
1576
+ label: `${definitionId}: no connectivity probe available`,
1577
+ centralReachable: false
1578
+ };
1579
+ }
1580
+ }
1581
+
1582
+ // ../../packages/core/dist/integrations/mcp-http-probe.js
1583
+ var MCP_ACCEPT = "application/json, text/event-stream";
1584
+ var DEFAULT_TIMEOUT_MS = 1e4;
1585
+ function isRpcEnvelopeFor(msg, expectedId) {
1586
+ return typeof msg === "object" && msg !== null && ("result" in msg || "error" in msg) && msg["id"] === expectedId;
1587
+ }
1588
+ async function parseRpc(res, expectedId) {
1589
+ const ct = res.headers.get("content-type") ?? "";
1590
+ if (ct.includes("text/event-stream")) {
1591
+ const text = await res.text();
1592
+ let dataLines = [];
1593
+ const tryFrame = () => {
1594
+ if (dataLines.length === 0)
1595
+ return null;
1596
+ try {
1597
+ const msg2 = JSON.parse(dataLines.join("\n"));
1598
+ if (isRpcEnvelopeFor(msg2, expectedId))
1599
+ return msg2;
1600
+ } catch {
1601
+ }
1602
+ return null;
1603
+ };
1604
+ for (const rawLine of text.split(/\r?\n/)) {
1605
+ if (rawLine.startsWith("data:")) {
1606
+ dataLines.push(rawLine.slice(5).trimStart());
1607
+ continue;
1608
+ }
1609
+ if (rawLine === "") {
1610
+ const frame = tryFrame();
1611
+ if (frame)
1612
+ return frame;
1613
+ dataLines = [];
1614
+ }
1615
+ }
1616
+ return tryFrame();
1617
+ }
1618
+ const msg = await res.json().catch(() => null);
1619
+ return isRpcEnvelopeFor(msg, expectedId) ? msg : null;
1620
+ }
1621
+ function httpStatusOutcome(status, step) {
1622
+ if (status === 401 || status === 403) {
1623
+ return { status: "down", message: `MCP ${step} unauthorized (${status}) \u2014 reconnect required` };
1624
+ }
1625
+ if (status >= 500) {
1626
+ return { status: "transient_error", message: `MCP ${step} returned ${status}` };
1627
+ }
1628
+ return { status: "down", message: `MCP ${step} returned ${status}` };
1629
+ }
1630
+ async function probeMcpHttp(config, fetchImpl = fetch) {
1631
+ const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
1632
+ const baseHeaders = {
1633
+ ...config.headers ?? {},
1634
+ "Content-Type": "application/json",
1635
+ Accept: MCP_ACCEPT
1636
+ };
1637
+ try {
1638
+ const initRes = await fetchImpl(config.url, {
1639
+ method: "POST",
1640
+ headers: baseHeaders,
1641
+ body: JSON.stringify({
1642
+ jsonrpc: "2.0",
1643
+ id: 1,
1644
+ method: "initialize",
1645
+ params: {
1646
+ protocolVersion: "2025-03-26",
1647
+ capabilities: {},
1648
+ clientInfo: { name: "augmented-connectivity-probe", version: "1.0.0" }
1649
+ }
1650
+ }),
1651
+ signal: AbortSignal.timeout(timeoutMs)
1652
+ });
1653
+ if (!initRes.ok)
1654
+ return httpStatusOutcome(initRes.status, "initialize");
1655
+ const sessionId = initRes.headers.get("mcp-session-id");
1656
+ const initRpc = await parseRpc(initRes, 1);
1657
+ if (!initRpc) {
1658
+ return { status: "down", message: "MCP initialize returned a non-JSON-RPC response \u2014 not an MCP server" };
1659
+ }
1660
+ if ("error" in initRpc) {
1661
+ const err = initRpc["error"];
1662
+ return { status: "down", message: `MCP initialize error: ${err?.message ?? "unknown"}` };
1663
+ }
1664
+ const sessionHeaders = { ...baseHeaders, ...sessionId ? { "Mcp-Session-Id": sessionId } : {} };
1665
+ const initializedRes = await fetchImpl(config.url, {
1666
+ method: "POST",
1667
+ headers: sessionHeaders,
1668
+ body: JSON.stringify({ jsonrpc: "2.0", method: "notifications/initialized" }),
1669
+ signal: AbortSignal.timeout(5e3)
1670
+ });
1671
+ if (!initializedRes.ok)
1672
+ return httpStatusOutcome(initializedRes.status, "initialized");
1673
+ await initializedRes.text().catch(() => "");
1674
+ const listRes = await fetchImpl(config.url, {
1675
+ method: "POST",
1676
+ headers: sessionHeaders,
1677
+ body: JSON.stringify({ jsonrpc: "2.0", id: 2, method: "tools/list" }),
1678
+ signal: AbortSignal.timeout(timeoutMs)
1679
+ });
1680
+ if (!listRes.ok)
1681
+ return httpStatusOutcome(listRes.status, "tools/list");
1682
+ const rpc = await parseRpc(listRes, 2);
1683
+ if (!rpc) {
1684
+ return { status: "down", message: "MCP tools/list returned a non-JSON-RPC response \u2014 not an MCP server" };
1685
+ }
1686
+ if ("error" in rpc) {
1687
+ const err = rpc["error"];
1688
+ return { status: "down", message: `MCP tools/list error: ${err?.message ?? "unknown"}` };
1689
+ }
1690
+ const result = rpc["result"];
1691
+ const toolCount = Array.isArray(result?.tools) ? result.tools.length : void 0;
1692
+ return {
1693
+ status: "ok",
1694
+ message: toolCount !== void 0 ? `${toolCount} tools` : "reachable",
1695
+ ...toolCount !== void 0 ? { details: { toolCount } } : {}
1696
+ };
1697
+ } catch (err) {
1698
+ const isAbort = err?.name === "TimeoutError" || err?.name === "AbortError";
1699
+ return {
1700
+ status: "transient_error",
1701
+ message: isAbort ? `MCP handshake timed out after ${timeoutMs / 1e3}s` : `MCP handshake failed: ${err.message}`
1702
+ };
1703
+ }
1704
+ }
1705
+
1706
+ // ../../packages/core/dist/integrations/composio-linkage.js
1707
+ function assessAuthConfigLinkage(input) {
1708
+ const { accountAuthConfigId, serverAuthConfigIds, serverId } = input;
1709
+ const serverLabel = serverId ? ` (${serverId})` : "";
1710
+ if (serverAuthConfigIds == null || !accountAuthConfigId) {
1711
+ return {
1712
+ linked: null,
1713
+ message: "auth_config linkage not verified \u2014 " + (serverAuthConfigIds == null ? "couldn't read the wired MCP server's auth config binding" : "Composio returned no auth_config for the connected account"),
1714
+ details: {
1715
+ accountAuthConfigId: accountAuthConfigId ?? null,
1716
+ serverAuthConfigIds: serverAuthConfigIds ?? null,
1717
+ serverId: serverId ?? null
1718
+ }
1719
+ };
1720
+ }
1721
+ if (serverAuthConfigIds.length === 0) {
1722
+ return {
1723
+ linked: false,
1724
+ message: `The agent's wired MCP server${serverLabel} has no auth config bound, so it cannot resolve the connected account (bound to auth_config ${accountAuthConfigId}) \u2014 reconnect/rebind required.`,
1725
+ details: { accountAuthConfigId, serverAuthConfigIds, serverId: serverId ?? null }
1726
+ };
1727
+ }
1728
+ if (serverAuthConfigIds.includes(accountAuthConfigId)) {
1729
+ return {
1730
+ linked: true,
1731
+ message: `Connected account's auth_config (${accountAuthConfigId}) matches the wired MCP server binding.`,
1732
+ details: { accountAuthConfigId, serverAuthConfigIds, serverId: serverId ?? null }
1733
+ };
1734
+ }
1735
+ return {
1736
+ linked: false,
1737
+ message: `The connected account is bound to auth_config ${accountAuthConfigId}, but the agent's wired MCP server${serverLabel} resolves auth_config(s) [${serverAuthConfigIds.join(", ")}] \u2014 tool calls will fail with "No connected account found". Reconnect/rebind required.`,
1738
+ details: { accountAuthConfigId, serverAuthConfigIds, serverId: serverId ?? null }
1739
+ };
1740
+ }
1741
+
1742
+ // ../../packages/core/dist/integrations/composio-account-probe.js
1743
+ var PROBE_TIMEOUT_MS = 1e4;
1744
+ var COMPOSIO_API_BASE = "https://backend.composio.dev";
1348
1745
  async function timedFetch(fetchImpl, url, init) {
1349
1746
  const controller = new AbortController();
1350
1747
  const timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);
@@ -1470,8 +1867,8 @@ async function fetchServerAuthConfigIds(fetchImpl, base, serverId, apiKey) {
1470
1867
  }
1471
1868
 
1472
1869
  // ../../packages/core/dist/integrations/composio-tool-call-probe.js
1473
- var MCP_ACCEPT = "application/json, text/event-stream";
1474
- var DEFAULT_TIMEOUT_MS = 1e4;
1870
+ var MCP_ACCEPT2 = "application/json, text/event-stream";
1871
+ var DEFAULT_TIMEOUT_MS2 = 1e4;
1475
1872
  var READONLY_VERB_TOKENS = [
1476
1873
  "LIST",
1477
1874
  "GET",
@@ -1561,7 +1958,7 @@ function classifyToolCallFailure(text) {
1561
1958
  return "auth";
1562
1959
  return "benign";
1563
1960
  }
1564
- async function parseRpc(res, expectedId) {
1961
+ async function parseRpc2(res, expectedId) {
1565
1962
  const ct = res.headers.get("content-type") ?? "";
1566
1963
  if (ct.includes("text/event-stream")) {
1567
1964
  const text = await res.text();
@@ -1589,11 +1986,11 @@ async function parseRpc(res, expectedId) {
1589
1986
  return null;
1590
1987
  }
1591
1988
  async function probeComposioMcpToolCall(config, fetchImpl = fetch) {
1592
- const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
1989
+ const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
1593
1990
  const baseHeaders = {
1594
1991
  ...config.headers ?? {},
1595
1992
  "Content-Type": "application/json",
1596
- Accept: MCP_ACCEPT
1993
+ Accept: MCP_ACCEPT2
1597
1994
  };
1598
1995
  try {
1599
1996
  const initRes = await fetchImpl(config.url, {
@@ -1615,7 +2012,7 @@ async function probeComposioMcpToolCall(config, fetchImpl = fetch) {
1615
2012
  return initRes.status >= 500 ? { status: "transient_error", message: `MCP initialize returned ${initRes.status}` } : null;
1616
2013
  }
1617
2014
  const sessionId = initRes.headers.get("mcp-session-id");
1618
- await parseRpc(initRes, 1);
2015
+ await parseRpc2(initRes, 1);
1619
2016
  const sessionHeaders = { ...baseHeaders, ...sessionId ? { "Mcp-Session-Id": sessionId } : {} };
1620
2017
  const initializedRes = await fetchImpl(config.url, {
1621
2018
  method: "POST",
@@ -1633,7 +2030,7 @@ async function probeComposioMcpToolCall(config, fetchImpl = fetch) {
1633
2030
  if (!listRes.ok) {
1634
2031
  return listRes.status >= 500 ? { status: "transient_error", message: `MCP tools/list returned ${listRes.status}` } : null;
1635
2032
  }
1636
- const listRpc = await parseRpc(listRes, 2);
2033
+ const listRpc = await parseRpc2(listRes, 2);
1637
2034
  const tools = listRpc?.["result"]?.tools ?? [];
1638
2035
  const resolved = resolveProbeTool(tools, { tool: config.toolName, args: config.toolArgs });
1639
2036
  const toolName = resolved.toolName;
@@ -1657,7 +2054,7 @@ async function probeComposioMcpToolCall(config, fetchImpl = fetch) {
1657
2054
  if (!callRes.ok) {
1658
2055
  return callRes.status >= 500 ? { status: "transient_error", message: `MCP tools/call returned ${callRes.status}` } : null;
1659
2056
  }
1660
- const callRpc = await parseRpc(callRes, 3);
2057
+ const callRpc = await parseRpc2(callRes, 3);
1661
2058
  {
1662
2059
  const errText = callRpc?.["error"]?.message;
1663
2060
  const resContent = callRpc?.["result"]?.content;
@@ -1793,436 +2190,163 @@ var context_meta_schema_default = {
1793
2190
  }
1794
2191
  },
1795
2192
  stringMapField: {
1796
- type: "object",
1797
- required: ["type", "additionalProperties"],
1798
- additionalProperties: false,
1799
- properties: {
1800
- type: { const: "object" },
1801
- additionalProperties: {
1802
- type: "object",
1803
- required: ["type"],
1804
- additionalProperties: false,
1805
- properties: {
1806
- type: { const: "string" }
1807
- }
1808
- },
1809
- title: { type: "string" },
1810
- description: { type: "string" },
1811
- default: {
1812
- type: "object",
1813
- additionalProperties: { type: "string" }
1814
- }
1815
- }
1816
- }
1817
- }
1818
- };
1819
-
1820
- // ../../packages/core/dist/integrations/context-validator.js
1821
- var ajv = new Ajv2020({ allErrors: true, strict: false });
1822
- addFormats(ajv);
1823
- var compiledMetaSchema = ajv.compile(context_meta_schema_default);
1824
-
1825
- // ../../packages/core/dist/integrations/augmented-live/codec.js
1826
- var CODEC_VERSION = 1;
1827
- var DEFAULT_KEYFRAME_INTERVAL = 10;
1828
- var DEFAULT_KEYFRAME_INTERVAL_MS = 5e3;
1829
- var DEFAULT_CHUNK_BUDGET_BYTES = 180 * 1024;
1830
- var textEncoder = new TextEncoder();
1831
- function byteLength(value) {
1832
- return textEncoder.encode(value).length;
1833
- }
1834
- function frameByteLength(frame) {
1835
- return byteLength(JSON.stringify(frame));
1836
- }
1837
- function diffStrings(base, next) {
1838
- const baseLen = base.length;
1839
- const nextLen = next.length;
1840
- let prefix = 0;
1841
- const maxPrefix = Math.min(baseLen, nextLen);
1842
- while (prefix < maxPrefix && base.charCodeAt(prefix) === next.charCodeAt(prefix)) {
1843
- prefix++;
1844
- }
1845
- let suffix = 0;
1846
- const maxSuffix = Math.min(baseLen, nextLen) - prefix;
1847
- while (suffix < maxSuffix && base.charCodeAt(baseLen - 1 - suffix) === next.charCodeAt(nextLen - 1 - suffix)) {
1848
- suffix++;
1849
- }
1850
- const deleteCount = baseLen - prefix - suffix;
1851
- const inserted = next.slice(prefix, nextLen - suffix);
1852
- const ops = [];
1853
- if (prefix > 0)
1854
- ops.push({ retain: prefix });
1855
- if (deleteCount > 0)
1856
- ops.push({ delete: deleteCount });
1857
- if (inserted.length > 0)
1858
- ops.push({ insert: inserted });
1859
- if (suffix > 0)
1860
- ops.push({ retain: suffix });
1861
- if (ops.length === 0)
1862
- ops.push({ retain: baseLen });
1863
- return ops;
1864
- }
1865
- function splitByBytes(payload, budgetBytes) {
1866
- const parts = [];
1867
- let current = "";
1868
- let currentBytes = 0;
1869
- for (const cp of payload) {
1870
- const cpBytes = byteLength(cp);
1871
- if (currentBytes + cpBytes > budgetBytes && current.length > 0) {
1872
- parts.push(current);
1873
- current = "";
1874
- currentBytes = 0;
1875
- }
1876
- current += cp;
1877
- currentBytes += cpBytes;
1878
- }
1879
- if (current.length > 0 || parts.length === 0)
1880
- parts.push(current);
1881
- return parts;
1882
- }
1883
- function chunkFrame(frame, budgetBytes = DEFAULT_CHUNK_BUDGET_BYTES) {
1884
- if (frameByteLength(frame) <= budgetBytes)
1885
- return [frame];
1886
- const payload = frame.type === "key" ? frame.content : JSON.stringify(frame.ops);
1887
- const dataBudget = Math.max(1, budgetBytes - 512);
1888
- const pieces = splitByBytes(payload, dataBudget);
1889
- return pieces.map((data, index) => {
1890
- const chunk = {
1891
- v: CODEC_VERSION,
1892
- type: "chunk",
1893
- seq: frame.seq,
1894
- kind: frame.type,
1895
- part: index,
1896
- parts: pieces.length,
1897
- data
1898
- };
1899
- if (frame.type === "patch")
1900
- chunk.baseSeq = frame.baseSeq;
1901
- return chunk;
1902
- });
1903
- }
1904
- var StreamEncoder = class {
1905
- keyframeInterval;
1906
- keyframeIntervalMs;
1907
- chunkBudgetBytes;
1908
- now;
1909
- seq = 0;
1910
- prevContent = null;
1911
- prevSeq = 0;
1912
- framesSinceKey = 0;
1913
- lastKeyAt = 0;
1914
- constructor(options = {}) {
1915
- this.keyframeInterval = options.keyframeInterval ?? DEFAULT_KEYFRAME_INTERVAL;
1916
- this.keyframeIntervalMs = options.keyframeIntervalMs ?? DEFAULT_KEYFRAME_INTERVAL_MS;
1917
- this.chunkBudgetBytes = options.chunkBudgetBytes ?? DEFAULT_CHUNK_BUDGET_BYTES;
1918
- this.now = options.now ?? (() => Date.now());
1919
- }
1920
- /** Encode one snapshot of the artifact into wire frames. */
1921
- encode(content) {
1922
- const seq = ++this.seq;
1923
- const now = this.now();
1924
- const mustKeyframe = this.prevContent === null || this.framesSinceKey >= this.keyframeInterval || now - this.lastKeyAt >= this.keyframeIntervalMs;
1925
- let frame;
1926
- if (mustKeyframe) {
1927
- frame = { v: CODEC_VERSION, type: "key", seq, content };
1928
- this.framesSinceKey = 0;
1929
- this.lastKeyAt = now;
1930
- } else {
1931
- frame = {
1932
- v: CODEC_VERSION,
1933
- type: "patch",
1934
- seq,
1935
- baseSeq: this.prevSeq,
1936
- ops: diffStrings(this.prevContent, content)
1937
- };
1938
- this.framesSinceKey++;
1939
- }
1940
- this.prevContent = content;
1941
- this.prevSeq = seq;
1942
- return chunkFrame(frame, this.chunkBudgetBytes);
1943
- }
1944
- /** Reset to the initial state (e.g. a new draft on the same encoder). */
1945
- reset() {
1946
- this.seq = 0;
1947
- this.prevContent = null;
1948
- this.prevSeq = 0;
1949
- this.framesSinceKey = 0;
1950
- this.lastKeyAt = 0;
1951
- }
1952
- };
1953
-
1954
- // ../../packages/core/dist/integrations/oauth-providers.js
1955
- var OAUTH_PROVIDERS = {
1956
- "google-workspace": {
1957
- definitionId: "google-workspace",
1958
- authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
1959
- tokenUrl: "https://oauth2.googleapis.com/token",
1960
- revokeUrl: "https://oauth2.googleapis.com/revoke",
1961
- defaultScopes: [
1962
- "https://www.googleapis.com/auth/gmail.modify",
1963
- "https://www.googleapis.com/auth/calendar",
1964
- "https://www.googleapis.com/auth/drive",
1965
- "https://www.googleapis.com/auth/spreadsheets",
1966
- "https://www.googleapis.com/auth/documents",
1967
- "https://www.googleapis.com/auth/chat.messages",
1968
- "https://www.googleapis.com/auth/chat.spaces.readonly"
1969
- ],
1970
- supportsRefresh: true,
1971
- extraAuthorizeParams: {
1972
- access_type: "offline",
1973
- prompt: "consent"
1974
- },
1975
- clientAuthMethod: "body",
1976
- userInfoUrl: "https://www.googleapis.com/oauth2/v2/userinfo"
1977
- },
1978
- "github": {
1979
- definitionId: "github",
1980
- authorizeUrl: "https://github.com/login/oauth/authorize",
1981
- tokenUrl: "https://github.com/login/oauth/access_token",
1982
- // ENG-6187: revoke the existing grant on reconnect so GitHub re-prompts and
1983
- // the four scopes below are actually granted. Without this, a stale narrow
1984
- // grant (e.g. an old read:user-only authorization) is silently re-issued and
1985
- // the missing-scopes banner loops forever.
1986
- grantRevokeUrl: "https://api.github.com/applications/{client_id}/grant",
1987
- defaultScopes: ["repo", "read:org", "gist", "workflow"],
1988
- supportsRefresh: true,
1989
- extraAuthorizeParams: {},
1990
- clientAuthMethod: "body",
1991
- userInfoUrl: "https://api.github.com/user"
1992
- },
1993
- "granola": {
1994
- // Granola MCP — remote streamable-HTTP at https://mcp.granola.ai/mcp.
1995
- // The AS is at mcp-auth.granola.ai and exposes RFC 8414 metadata at
1996
- // /.well-known/oauth-authorization-server. Auth is OAuth 2.0 with
1997
- // mandatory PKCE (S256) and a public client (no client_secret) issued
1998
- // via Dynamic Client Registration (RFC 7591). The bootstrap script
1999
- // (`packages/api/scripts/dcr-register.ts`) registers a client once at
2000
- // deploy time; OAUTH_GRANOLA_CLIENT_ID is set from its output.
2001
- definitionId: "granola",
2002
- authorizeUrl: "https://mcp-auth.granola.ai/oauth2/authorize",
2003
- tokenUrl: "https://mcp-auth.granola.ai/oauth2/token",
2004
- // Minimal scope set: `offline_access` earns the refresh_token so the
2005
- // refresh cron can rotate the bearer without operator action; `openid`
2006
- // is required for the OIDC code flow even when we don't request an
2007
- // id_token. Profile/email are intentionally omitted — we have no
2008
- // userInfoUrl wired up here, so requesting them would over-ask consent
2009
- // for fields the callback can't read.
2010
- defaultScopes: ["openid", "offline_access"],
2011
- supportsRefresh: true,
2012
- extraAuthorizeParams: {},
2013
- clientAuthMethod: "body",
2014
- pkce: "S256",
2015
- publicClient: true,
2016
- mcpUrl: "https://mcp.granola.ai/mcp"
2017
- },
2018
- "notion-cli": {
2019
- // Notion's public OAuth app. Tokens are workspace-scoped and long-lived —
2020
- // Notion does not issue refresh_tokens, so `supportsRefresh: false` and
2021
- // the refresh cron skips this provider entirely. Scopes are not part of
2022
- // Notion's authorize URL contract; consent is governed by what the user
2023
- // grants in the OAuth screen, so `defaultScopes` stays empty.
2024
- // `owner=user` forces the user-OAuth variant (vs internal integration).
2025
- // Requires OAUTH_NOTION_CLI_CLIENT_ID and OAUTH_NOTION_CLI_CLIENT_SECRET.
2026
- definitionId: "notion-cli",
2027
- authorizeUrl: "https://api.notion.com/v1/oauth/authorize",
2028
- tokenUrl: "https://api.notion.com/v1/oauth/token",
2029
- defaultScopes: [],
2030
- supportsRefresh: false,
2031
- extraAuthorizeParams: {
2032
- owner: "user"
2033
- },
2034
- clientAuthMethod: "basic"
2035
- },
2036
- "xero": {
2037
- definitionId: "xero",
2038
- authorizeUrl: "https://login.xero.com/identity/connect/authorize",
2039
- tokenUrl: "https://identity.xero.com/connect/token",
2040
- revokeUrl: "https://identity.xero.com/connect/revocation",
2041
- defaultScopes: [
2042
- "openid",
2043
- "profile",
2044
- "email",
2045
- "offline_access",
2046
- // Granular scopes (required for apps created after March 2, 2026 —
2047
- // do NOT revert to the broad `accounting.transactions` /
2048
- // `accounting.contacts` scopes, Xero rejects the manifest).
2049
- // The variant *without* `.read` is the read+write granular scope.
2050
- "accounting.settings.read",
2051
- // contacts: write enables agent-driven supplier/customer creation
2052
- // (required for bill creation since a bill must reference a contact).
2053
- "accounting.contacts",
2054
- // invoices: write enables bill creation (Type=ACCPAY invoices) and
2055
- // updates to sales invoices alongside the existing read access.
2056
- "accounting.invoices",
2057
- // attachments: write enables agents to attach the source PDF to a
2058
- // bill at creation time. Read-only would force a follow-up manual
2059
- // upload in Xero; write closes the loop.
2060
- "accounting.attachments",
2061
- // accounting.transactions.read → granular read-only replacements
2062
- // for the surfaces we don't yet need write access on.
2063
- "accounting.payments.read",
2064
- "accounting.banktransactions.read",
2065
- "accounting.manualjournals.read",
2066
- // accounting.reports.read → granular read-only replacements
2067
- "accounting.reports.balancesheet.read",
2068
- "accounting.reports.profitandloss.read",
2069
- "accounting.reports.trialbalance.read",
2070
- "accounting.reports.budgetsummary.read",
2071
- "accounting.reports.banksummary.read",
2072
- "accounting.reports.executivesummary.read",
2073
- "accounting.reports.aged.read"
2074
- ],
2075
- // Read-only variant (ENG-6170): the `.read` granular scope for every
2076
- // surface, so a token granted under it cannot create bills/invoices or
2077
- // mutate contacts/attachments. Used when an install is (re)connected with
2078
- // `read_only: true` — e.g. to lock a production-books integration to reads
2079
- // until per-vendor broker mediation (ENG-4922) gates its writes.
2080
- readOnlyScopes: [
2081
- "openid",
2082
- "profile",
2083
- "email",
2084
- "offline_access",
2085
- "accounting.settings.read",
2086
- "accounting.contacts.read",
2087
- "accounting.invoices.read",
2088
- "accounting.attachments.read",
2089
- "accounting.payments.read",
2090
- "accounting.banktransactions.read",
2091
- "accounting.manualjournals.read",
2092
- "accounting.reports.balancesheet.read",
2093
- "accounting.reports.profitandloss.read",
2094
- "accounting.reports.trialbalance.read",
2095
- "accounting.reports.budgetsummary.read",
2096
- "accounting.reports.banksummary.read",
2097
- "accounting.reports.executivesummary.read",
2098
- "accounting.reports.aged.read"
2099
- ],
2100
- supportsRefresh: true,
2101
- extraAuthorizeParams: {},
2102
- clientAuthMethod: "basic",
2103
- userInfoUrl: "https://api.xero.com/connections"
2193
+ type: "object",
2194
+ required: ["type", "additionalProperties"],
2195
+ additionalProperties: false,
2196
+ properties: {
2197
+ type: { const: "object" },
2198
+ additionalProperties: {
2199
+ type: "object",
2200
+ required: ["type"],
2201
+ additionalProperties: false,
2202
+ properties: {
2203
+ type: { const: "string" }
2204
+ }
2205
+ },
2206
+ title: { type: "string" },
2207
+ description: { type: "string" },
2208
+ default: {
2209
+ type: "object",
2210
+ additionalProperties: { type: "string" }
2211
+ }
2212
+ }
2213
+ }
2104
2214
  }
2105
2215
  };
2106
- function getOAuthProvider(definitionId) {
2107
- return OAUTH_PROVIDERS[definitionId];
2108
- }
2109
2216
 
2110
- // ../../packages/core/dist/integrations/connectivity-probe.js
2111
- var CONNECTIVITY_SEVERITY = {
2112
- ok: 0,
2113
- transient_error: 1,
2114
- degraded: 2,
2115
- down: 3
2116
- };
2117
- function worseConnectivityOutcome(a, b) {
2118
- return CONNECTIVITY_SEVERITY[b.status] > CONNECTIVITY_SEVERITY[a.status] ? b : a;
2119
- }
2120
- var HTTP_PROBE_PROVIDERS = /* @__PURE__ */ new Set([
2121
- "linear",
2122
- "google-workspace",
2123
- "xero",
2124
- "v0"
2125
- // ENG-6100: GitHub is deliberately NOT here. This set drives the ASYNC
2126
- // connectivity monitor's routing, where github (source_type='native')
2127
- // stays host-side (cli_command — `gh`, the credential the agent actually
2128
- // executes with) rather than a central stored-token probe. The
2129
- // synchronous Test button DOES probe the centrally-stored token via
2130
- // `probeHttpProvider` (PROBE_DEFINITIONS in connectivity-http-probes.ts
2131
- // includes 'github') — a narrower, honest "the token we stored is valid"
2132
- // check. Unifying the monitor onto the central probe is sub-issue C's call.
2133
- ]);
2134
- var CLI_PROBE_ARGS = {
2135
- gcloud: ["version"],
2136
- // ENG-6206: `gh --version` only proves the binary exists, not that it's
2137
- // authenticated — so a missing/mis-named token read green (the false-green
2138
- // that hid the broken fleet). `gh auth status` exits non-zero when not
2139
- // logged in, the honest signal. Read-only. Requires the runner to pass the
2140
- // agent's GH_TOKEN/GITHUB_TOKEN env (see manager-worker runCli wiring).
2141
- github: ["auth", "status"]
2142
- // most CLIs respond to --version; override here only when they don't.
2143
- };
2144
- function cliArgsFor(definitionId, ct) {
2145
- if (Array.isArray(ct?.args) && ct.args.length > 0 && ct.args.every((a) => typeof a === "string")) {
2146
- return ct.args;
2147
- }
2148
- return CLI_PROBE_ARGS[definitionId] ?? ["--version"];
2217
+ // ../../packages/core/dist/integrations/context-validator.js
2218
+ var ajv = new Ajv2020({ allErrors: true, strict: false });
2219
+ addFormats(ajv);
2220
+ var compiledMetaSchema = ajv.compile(context_meta_schema_default);
2221
+
2222
+ // ../../packages/core/dist/integrations/augmented-live/codec.js
2223
+ var CODEC_VERSION = 1;
2224
+ var DEFAULT_KEYFRAME_INTERVAL = 10;
2225
+ var DEFAULT_KEYFRAME_INTERVAL_MS = 5e3;
2226
+ var DEFAULT_CHUNK_BUDGET_BYTES = 180 * 1024;
2227
+ var textEncoder = new TextEncoder();
2228
+ function byteLength(value) {
2229
+ return textEncoder.encode(value).length;
2149
2230
  }
2150
- function mcpOverrideFrom(ct) {
2151
- const tool = typeof ct?.tool === "string" && ct.tool.trim().length > 0 ? ct.tool.trim() : void 0;
2152
- if (!tool)
2153
- return {};
2154
- const args = ct?.args && typeof ct.args === "object" && !Array.isArray(ct.args) ? ct.args : void 0;
2155
- return { probeTool: tool, ...args ? { probeArgs: args } : {} };
2231
+ function frameByteLength(frame) {
2232
+ return byteLength(JSON.stringify(frame));
2156
2233
  }
2157
- function resolveConnectivityProbe(input) {
2158
- const { definitionId, sourceType, authType } = input;
2159
- if (authType === "managed" || sourceType === "managed") {
2160
- return {
2161
- kind: "managed_composite",
2162
- sourceType: "managed",
2163
- readOnly: true,
2164
- label: `${definitionId}: MCP tools/list + account binding (managed)`,
2165
- centralReachable: false,
2166
- // ENG-6212: carry the operator-stored override tool (if any) so both the
2167
- // host executor and the central Test path call the same specific tool.
2168
- ...mcpOverrideFrom(input.connectivityTest)
2169
- };
2234
+ function diffStrings(base, next) {
2235
+ const baseLen = base.length;
2236
+ const nextLen = next.length;
2237
+ let prefix = 0;
2238
+ const maxPrefix = Math.min(baseLen, nextLen);
2239
+ while (prefix < maxPrefix && base.charCodeAt(prefix) === next.charCodeAt(prefix)) {
2240
+ prefix++;
2170
2241
  }
2171
- if (HTTP_PROBE_PROVIDERS.has(definitionId)) {
2172
- return {
2173
- kind: "http_provider",
2174
- sourceType: sourceType ?? "mcp_server",
2175
- readOnly: true,
2176
- label: `${definitionId}: read-only API check`,
2177
- centralReachable: true,
2178
- httpProvider: definitionId
2179
- };
2242
+ let suffix = 0;
2243
+ const maxSuffix = Math.min(baseLen, nextLen) - prefix;
2244
+ while (suffix < maxSuffix && base.charCodeAt(baseLen - 1 - suffix) === next.charCodeAt(nextLen - 1 - suffix)) {
2245
+ suffix++;
2180
2246
  }
2181
- if (getOAuthProvider(definitionId)?.mcpUrl) {
2182
- return {
2183
- kind: "mcp_tools_list",
2184
- sourceType: sourceType ?? "mcp_server",
2185
- readOnly: true,
2186
- label: `${definitionId}: MCP tools/list`,
2187
- centralReachable: false
2247
+ const deleteCount = baseLen - prefix - suffix;
2248
+ const inserted = next.slice(prefix, nextLen - suffix);
2249
+ const ops = [];
2250
+ if (prefix > 0)
2251
+ ops.push({ retain: prefix });
2252
+ if (deleteCount > 0)
2253
+ ops.push({ delete: deleteCount });
2254
+ if (inserted.length > 0)
2255
+ ops.push({ insert: inserted });
2256
+ if (suffix > 0)
2257
+ ops.push({ retain: suffix });
2258
+ if (ops.length === 0)
2259
+ ops.push({ retain: baseLen });
2260
+ return ops;
2261
+ }
2262
+ function splitByBytes(payload, budgetBytes) {
2263
+ const parts = [];
2264
+ let current = "";
2265
+ let currentBytes = 0;
2266
+ for (const cp of payload) {
2267
+ const cpBytes = byteLength(cp);
2268
+ if (currentBytes + cpBytes > budgetBytes && current.length > 0) {
2269
+ parts.push(current);
2270
+ current = "";
2271
+ currentBytes = 0;
2272
+ }
2273
+ current += cp;
2274
+ currentBytes += cpBytes;
2275
+ }
2276
+ if (current.length > 0 || parts.length === 0)
2277
+ parts.push(current);
2278
+ return parts;
2279
+ }
2280
+ function chunkFrame(frame, budgetBytes = DEFAULT_CHUNK_BUDGET_BYTES) {
2281
+ if (frameByteLength(frame) <= budgetBytes)
2282
+ return [frame];
2283
+ const payload = frame.type === "key" ? frame.content : JSON.stringify(frame.ops);
2284
+ const dataBudget = Math.max(1, budgetBytes - 512);
2285
+ const pieces = splitByBytes(payload, dataBudget);
2286
+ return pieces.map((data, index) => {
2287
+ const chunk = {
2288
+ v: CODEC_VERSION,
2289
+ type: "chunk",
2290
+ seq: frame.seq,
2291
+ kind: frame.type,
2292
+ part: index,
2293
+ parts: pieces.length,
2294
+ data
2188
2295
  };
2296
+ if (frame.type === "patch")
2297
+ chunk.baseSeq = frame.baseSeq;
2298
+ return chunk;
2299
+ });
2300
+ }
2301
+ var StreamEncoder = class {
2302
+ keyframeInterval;
2303
+ keyframeIntervalMs;
2304
+ chunkBudgetBytes;
2305
+ now;
2306
+ seq = 0;
2307
+ prevContent = null;
2308
+ prevSeq = 0;
2309
+ framesSinceKey = 0;
2310
+ lastKeyAt = 0;
2311
+ constructor(options = {}) {
2312
+ this.keyframeInterval = options.keyframeInterval ?? DEFAULT_KEYFRAME_INTERVAL;
2313
+ this.keyframeIntervalMs = options.keyframeIntervalMs ?? DEFAULT_KEYFRAME_INTERVAL_MS;
2314
+ this.chunkBudgetBytes = options.chunkBudgetBytes ?? DEFAULT_CHUNK_BUDGET_BYTES;
2315
+ this.now = options.now ?? (() => Date.now());
2189
2316
  }
2190
- switch (sourceType) {
2191
- case "mcp_server":
2192
- return {
2193
- kind: "unsupported",
2194
- sourceType: "mcp_server",
2195
- readOnly: true,
2196
- label: `${definitionId}: local-stdio MCP \u2014 no host probe available`,
2197
- centralReachable: false
2198
- };
2199
- case "cli_tool":
2200
- return {
2201
- kind: "cli_command",
2202
- sourceType: "cli_tool",
2203
- readOnly: true,
2204
- label: `${definitionId}: CLI reachability`,
2205
- centralReachable: false,
2206
- cliArgs: cliArgsFor(definitionId, input.connectivityTest)
2207
- };
2208
- case "native":
2209
- return {
2210
- kind: "builtin",
2211
- sourceType: "native",
2212
- readOnly: true,
2213
- label: `${definitionId}: built-in check`,
2214
- centralReachable: false
2215
- };
2216
- default:
2217
- return {
2218
- kind: "unsupported",
2219
- sourceType: sourceType ?? "native",
2220
- readOnly: true,
2221
- label: `${definitionId}: no connectivity probe available`,
2222
- centralReachable: false
2317
+ /** Encode one snapshot of the artifact into wire frames. */
2318
+ encode(content) {
2319
+ const seq = ++this.seq;
2320
+ const now = this.now();
2321
+ const mustKeyframe = this.prevContent === null || this.framesSinceKey >= this.keyframeInterval || now - this.lastKeyAt >= this.keyframeIntervalMs;
2322
+ let frame;
2323
+ if (mustKeyframe) {
2324
+ frame = { v: CODEC_VERSION, type: "key", seq, content };
2325
+ this.framesSinceKey = 0;
2326
+ this.lastKeyAt = now;
2327
+ } else {
2328
+ frame = {
2329
+ v: CODEC_VERSION,
2330
+ type: "patch",
2331
+ seq,
2332
+ baseSeq: this.prevSeq,
2333
+ ops: diffStrings(this.prevContent, content)
2223
2334
  };
2335
+ this.framesSinceKey++;
2336
+ }
2337
+ this.prevContent = content;
2338
+ this.prevSeq = seq;
2339
+ return chunkFrame(frame, this.chunkBudgetBytes);
2224
2340
  }
2225
- }
2341
+ /** Reset to the initial state (e.g. a new draft on the same encoder). */
2342
+ reset() {
2343
+ this.seq = 0;
2344
+ this.prevContent = null;
2345
+ this.prevSeq = 0;
2346
+ this.framesSinceKey = 0;
2347
+ this.lastKeyAt = 0;
2348
+ }
2349
+ };
2226
2350
 
2227
2351
  // ../../packages/core/dist/integrations/connectivity-http-probes.js
2228
2352
  var PROBE_TIMEOUT_MS2 = 1e4;
@@ -4632,9 +4756,10 @@ function parseResetDateTime(humanDate, now) {
4632
4756
  const isPm = timeMatch[3].toLowerCase() === "pm";
4633
4757
  hour = rawHour % 12 + (isPm ? 12 : 0);
4634
4758
  }
4759
+ const SIX_DAYS_MS = 6 * 24 * 60 * 60 * 1e3;
4635
4760
  const year = now.getUTCFullYear();
4636
4761
  const candidate = new Date(Date.UTC(year, month, day, hour, minute));
4637
- if (candidate.getTime() < now.getTime() - 24 * 60 * 60 * 1e3) {
4762
+ if (candidate.getTime() < now.getTime() - SIX_DAYS_MS) {
4638
4763
  return new Date(Date.UTC(year + 1, month, day, hour, minute));
4639
4764
  }
4640
4765
  return candidate;
@@ -5160,6 +5285,7 @@ export {
5160
5285
  StreamEncoder,
5161
5286
  worseConnectivityOutcome,
5162
5287
  resolveConnectivityProbe,
5288
+ probeMcpHttp,
5163
5289
  probeComposioAccount,
5164
5290
  probeComposioMcpToolCall,
5165
5291
  probeHttpProvider,
@@ -5179,4 +5305,4 @@ export {
5179
5305
  coerceEnvValue,
5180
5306
  FLAGS_SCHEMA_VERSION
5181
5307
  };
5182
- //# sourceMappingURL=chunk-3HZSMDEW.js.map
5308
+ //# sourceMappingURL=chunk-SN2G4B2Z.js.map