@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.
- package/dist/bin/agt.js +4 -4
- package/dist/{chunk-BKO5PJZ7.js → chunk-IHPN6AX7.js} +2 -2
- package/dist/{chunk-NGZVHSI3.js → chunk-O2QKTUOE.js} +2 -2
- package/dist/{chunk-3HZSMDEW.js → chunk-SN2G4B2Z.js} +585 -459
- package/dist/chunk-SN2G4B2Z.js.map +1 -0
- package/dist/{claude-pair-runtime-LQJ5E4IF.js → claude-pair-runtime-UKOL6GWJ.js} +2 -2
- package/dist/lib/manager-worker.js +47 -128
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/{persistent-session-5BEMWOTM.js → persistent-session-34CY65FC.js} +3 -3
- package/dist/{responsiveness-probe-JP4HLFYU.js → responsiveness-probe-KKWPOZSX.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-3HZSMDEW.js.map +0 -1
- /package/dist/{chunk-BKO5PJZ7.js.map → chunk-IHPN6AX7.js.map} +0 -0
- /package/dist/{chunk-NGZVHSI3.js.map → chunk-O2QKTUOE.js.map} +0 -0
- /package/dist/{claude-pair-runtime-LQJ5E4IF.js.map → claude-pair-runtime-UKOL6GWJ.js.map} +0 -0
- /package/dist/{persistent-session-5BEMWOTM.js.map → persistent-session-34CY65FC.js.map} +0 -0
- /package/dist/{responsiveness-probe-JP4HLFYU.js.map → responsiveness-probe-KKWPOZSX.js.map} +0 -0
|
@@ -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/
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
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
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
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 (
|
|
1526
|
+
if (HTTP_PROBE_PROVIDERS.has(definitionId)) {
|
|
1325
1527
|
return {
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
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 (
|
|
1536
|
+
if (getOAuthProvider(definitionId)?.mcpUrl) {
|
|
1332
1537
|
return {
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
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
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
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
|
|
1474
|
-
var
|
|
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
|
|
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 ??
|
|
1989
|
+
const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
1593
1990
|
const baseHeaders = {
|
|
1594
1991
|
...config.headers ?? {},
|
|
1595
1992
|
"Content-Type": "application/json",
|
|
1596
|
-
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
|
|
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
|
|
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
|
|
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/
|
|
2111
|
-
var
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
var
|
|
2121
|
-
|
|
2122
|
-
|
|
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
|
|
2151
|
-
|
|
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
|
|
2158
|
-
const
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
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
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
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
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
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
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
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() -
|
|
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-
|
|
5308
|
+
//# sourceMappingURL=chunk-SN2G4B2Z.js.map
|