@sentry/junior 0.63.0 → 0.65.0

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.
@@ -5,7 +5,7 @@ import {
5
5
  discoverInstalledPluginPackageContent,
6
6
  normalizePluginPackageNames,
7
7
  pluginRoots
8
- } from "./chunk-5LUISFEY.js";
8
+ } from "./chunk-KVZL5NZS.js";
9
9
 
10
10
  // src/chat/coerce.ts
11
11
  function toOptionalString(value) {
@@ -119,6 +119,16 @@ var CONSOLE_PREVIEW_KEYS = /* @__PURE__ */ new Set([
119
119
  "gen_ai.tool.call.arguments",
120
120
  "gen_ai.tool.call.result"
121
121
  ]);
122
+ var SENTRY_TAG_ATTRIBUTE_KEYS = /* @__PURE__ */ new Set([
123
+ "app.platform",
124
+ "messaging.system",
125
+ "app.actor.type",
126
+ "gen_ai.agent.name",
127
+ "gen_ai.request.model",
128
+ "app.skill.name",
129
+ "http.request.method",
130
+ "url.path"
131
+ ]);
122
132
  function getSentryEnvironment() {
123
133
  return (process.env.SENTRY_ENVIRONMENT ?? process.env.VERCEL_ENV ?? process.env.NODE_ENV ?? "").trim().toLowerCase();
124
134
  }
@@ -857,7 +867,7 @@ var log = {
857
867
  error(eventName, attrs = {}, body) {
858
868
  emit("error", eventName, attrs, body);
859
869
  },
860
- exception(eventName, error, attrs = {}, body) {
870
+ exception(eventName, error, attrs = {}, body, context) {
861
871
  const normalizedError = error instanceof Error ? error : new Error(String(error));
862
872
  emit(
863
873
  "error",
@@ -876,6 +886,9 @@ var log = {
876
886
  const sentryCaptureException = sentry_exports.captureException;
877
887
  if (typeof sentryWithScope === "function" && typeof sentryCaptureException === "function") {
878
888
  sentryWithScope((scope) => {
889
+ if (context) {
890
+ setSentryScopeContext(scope, context);
891
+ }
879
892
  for (const [key, value] of Object.entries(
880
893
  mergeAttributes(contextStorage.getStore(), attrs)
881
894
  )) {
@@ -886,6 +899,9 @@ var log = {
886
899
  return eventId;
887
900
  }
888
901
  if (typeof sentryCaptureException === "function") {
902
+ if (context) {
903
+ setSentryUser(sentryUserIdentityFromContext(context));
904
+ }
889
905
  eventId = sentryCaptureException(normalizedError);
890
906
  }
891
907
  return eventId;
@@ -1007,16 +1023,51 @@ function toSpanAttributes(context) {
1007
1023
  function setSentryTagsFromContext(context) {
1008
1024
  const attrs = contextToAttributes(context);
1009
1025
  for (const [key, value] of Object.entries(attrs)) {
1026
+ if (!SENTRY_TAG_ATTRIBUTE_KEYS.has(key)) {
1027
+ continue;
1028
+ }
1010
1029
  if (typeof value === "string" && value.length > 0) {
1011
1030
  sentry_exports.setTag(key, value);
1012
1031
  }
1013
1032
  }
1033
+ }
1034
+ function sentryUserIdentityFromContext(context) {
1014
1035
  if (context.slackUserId) {
1015
- sentry_exports.setUser({
1036
+ return {
1016
1037
  id: context.slackUserId,
1017
- username: context.slackUserName
1018
- });
1038
+ ...context.slackUserName ? { username: context.slackUserName } : {},
1039
+ ...context.slackUserEmail ? { email: context.slackUserEmail } : {}
1040
+ };
1041
+ }
1042
+ return void 0;
1043
+ }
1044
+ function sentryUserFromIdentity(identity) {
1045
+ return {
1046
+ id: identity.id,
1047
+ ip_address: null,
1048
+ ...identity.username ? { username: identity.username } : {},
1049
+ ...identity.email ? { email: identity.email } : {}
1050
+ };
1051
+ }
1052
+ function setSentryUser(identity) {
1053
+ if (!identity) return;
1054
+ sentry_exports.setUser(sentryUserFromIdentity(identity));
1055
+ }
1056
+ function setSentryScopeContext(scope, context) {
1057
+ const attrs = contextToAttributes(context);
1058
+ for (const [key, value] of Object.entries(attrs)) {
1059
+ if (!SENTRY_TAG_ATTRIBUTE_KEYS.has(key)) {
1060
+ continue;
1061
+ }
1062
+ if (typeof value === "string" && value.length > 0) {
1063
+ scope.setTag(key, value);
1064
+ }
1065
+ }
1066
+ const identity = sentryUserIdentityFromContext(context);
1067
+ if (identity) {
1068
+ scope.setUser(sentryUserFromIdentity(identity));
1019
1069
  }
1070
+ scope.setContext("app", attrs);
1020
1071
  }
1021
1072
  function toSpanAttributeValue(value) {
1022
1073
  if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
@@ -1058,12 +1109,14 @@ function logException(error, eventName, context = {}, attributes = {}, body) {
1058
1109
  eventName,
1059
1110
  normalizedError,
1060
1111
  { ...toSpanAttributes(context), ...attributes },
1061
- body
1112
+ body,
1113
+ context
1062
1114
  );
1063
1115
  }
1064
1116
  function setTags(context = {}) {
1065
1117
  setLogContext(context);
1066
1118
  setSentryTagsFromContext(context);
1119
+ setSentryUser(sentryUserIdentityFromContext(context));
1067
1120
  }
1068
1121
  function createRequestContext(request, context = {}) {
1069
1122
  return createLogContextFromRequest(request, context);
@@ -1151,7 +1204,7 @@ function sanitizeGenAiValue(value, seen, depth, keyName) {
1151
1204
  if (shouldTreatAsBlob) {
1152
1205
  return `[omitted:${value.length}]`;
1153
1206
  }
1154
- return truncateGenAiString(value, GEN_AI_MAX_STRING_CHARS);
1207
+ return truncateGenAiString(redactSecrets(value), GEN_AI_MAX_STRING_CHARS);
1155
1208
  }
1156
1209
  if (typeof value === "number") {
1157
1210
  return Number.isFinite(value) ? value : void 0;
@@ -1166,7 +1219,7 @@ function sanitizeGenAiValue(value, seen, depth, keyName) {
1166
1219
  return value.slice(0, GEN_AI_MAX_ARRAY_ITEMS).map((entry) => sanitizeGenAiValue(entry, seen, depth + 1)).filter((entry) => entry !== void 0);
1167
1220
  }
1168
1221
  if (typeof value !== "object") {
1169
- return String(value);
1222
+ return redactSecrets(String(value));
1170
1223
  }
1171
1224
  if (seen.has(value)) {
1172
1225
  return "[circular]";
@@ -1194,7 +1247,7 @@ function serializeGenAiAttribute(value, maxChars = GEN_AI_DEFAULT_MAX_ATTRIBUTE_
1194
1247
  if (!serialized) {
1195
1248
  return void 0;
1196
1249
  }
1197
- return truncateGenAiString(serialized, maxChars);
1250
+ return truncateGenAiString(redactSecrets(serialized), maxChars);
1198
1251
  }
1199
1252
  function asRecord(value) {
1200
1253
  return value && typeof value === "object" ? value : void 0;
@@ -1270,6 +1323,125 @@ function extractGenAiUsageAttributes(...sources) {
1270
1323
  // src/chat/plugins/manifest.ts
1271
1324
  import { z } from "zod";
1272
1325
  import { parse as parseYaml } from "yaml";
1326
+
1327
+ // src/chat/plugins/inline-manifest-source.ts
1328
+ function setDefined(target, key, value) {
1329
+ if (value !== void 0) {
1330
+ target[key] = value;
1331
+ }
1332
+ }
1333
+ function isRecord2(value) {
1334
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
1335
+ }
1336
+ function unqualifyManifestToken(name, value) {
1337
+ if (typeof name === "string" && typeof value === "string" && value.startsWith(`${name}.`)) {
1338
+ return value.slice(name.length + 1);
1339
+ }
1340
+ return value;
1341
+ }
1342
+ function inlineTokenListSource(name, values) {
1343
+ if (values === void 0 || !Array.isArray(values)) {
1344
+ return values;
1345
+ }
1346
+ return values.map((value) => unqualifyManifestToken(name, value));
1347
+ }
1348
+ function inlineCredentialsSource(credentials) {
1349
+ if (credentials === void 0 || !isRecord2(credentials)) {
1350
+ return credentials;
1351
+ }
1352
+ const result = {};
1353
+ setDefined(result, "type", credentials.type);
1354
+ setDefined(result, "domains", credentials.domains);
1355
+ setDefined(result, "api-headers", credentials.apiHeaders);
1356
+ setDefined(result, "auth-token-env", credentials.authTokenEnv);
1357
+ setDefined(
1358
+ result,
1359
+ "auth-token-placeholder",
1360
+ credentials.authTokenPlaceholder
1361
+ );
1362
+ if (credentials.type === "github-app") {
1363
+ setDefined(result, "app-id-env", credentials.appIdEnv);
1364
+ setDefined(result, "private-key-env", credentials.privateKeyEnv);
1365
+ setDefined(result, "installation-id-env", credentials.installationIdEnv);
1366
+ }
1367
+ return result;
1368
+ }
1369
+ function inlineMcpSource(mcp) {
1370
+ if (mcp === void 0 || !isRecord2(mcp)) {
1371
+ return mcp;
1372
+ }
1373
+ const result = {};
1374
+ setDefined(result, "transport", mcp.transport);
1375
+ setDefined(result, "url", mcp.url);
1376
+ setDefined(result, "headers", mcp.headers);
1377
+ setDefined(result, "allowed-tools", mcp.allowedTools);
1378
+ return result;
1379
+ }
1380
+ function inlineOauthSource(oauth) {
1381
+ if (oauth === void 0 || !isRecord2(oauth)) {
1382
+ return oauth;
1383
+ }
1384
+ const result = {};
1385
+ setDefined(result, "client-id-env", oauth.clientIdEnv);
1386
+ setDefined(result, "client-secret-env", oauth.clientSecretEnv);
1387
+ setDefined(result, "authorize-endpoint", oauth.authorizeEndpoint);
1388
+ setDefined(result, "token-endpoint", oauth.tokenEndpoint);
1389
+ setDefined(result, "scope", oauth.scope);
1390
+ setDefined(result, "authorize-params", oauth.authorizeParams);
1391
+ setDefined(result, "token-auth-method", oauth.tokenAuthMethod);
1392
+ setDefined(result, "token-extra-headers", oauth.tokenExtraHeaders);
1393
+ return result;
1394
+ }
1395
+ function inlineTargetSource(name, target) {
1396
+ if (target === void 0 || !isRecord2(target)) {
1397
+ return target;
1398
+ }
1399
+ const result = {};
1400
+ setDefined(result, "type", target.type);
1401
+ setDefined(
1402
+ result,
1403
+ "config-key",
1404
+ unqualifyManifestToken(name, target.configKey)
1405
+ );
1406
+ setDefined(result, "command-flags", target.commandFlags);
1407
+ return result;
1408
+ }
1409
+ function inlineManifestSource(manifest) {
1410
+ const result = {};
1411
+ setDefined(result, "name", manifest.name);
1412
+ setDefined(result, "description", manifest.description);
1413
+ setDefined(
1414
+ result,
1415
+ "capabilities",
1416
+ inlineTokenListSource(manifest.name, manifest.capabilities)
1417
+ );
1418
+ setDefined(
1419
+ result,
1420
+ "config-keys",
1421
+ inlineTokenListSource(manifest.name, manifest.configKeys)
1422
+ );
1423
+ setDefined(result, "domains", manifest.domains);
1424
+ setDefined(result, "api-headers", manifest.apiHeaders);
1425
+ setDefined(result, "command-env", manifest.commandEnv);
1426
+ setDefined(result, "env-vars", manifest.envVars);
1427
+ setDefined(
1428
+ result,
1429
+ "credentials",
1430
+ inlineCredentialsSource(manifest.credentials)
1431
+ );
1432
+ setDefined(result, "runtime-dependencies", manifest.runtimeDependencies);
1433
+ setDefined(result, "runtime-postinstall", manifest.runtimePostinstall);
1434
+ setDefined(result, "mcp", inlineMcpSource(manifest.mcp));
1435
+ setDefined(result, "oauth", inlineOauthSource(manifest.oauth));
1436
+ setDefined(
1437
+ result,
1438
+ "target",
1439
+ inlineTargetSource(manifest.name, manifest.target)
1440
+ );
1441
+ return result;
1442
+ }
1443
+
1444
+ // src/chat/plugins/manifest.ts
1273
1445
  var PLUGIN_NAME_RE = /^[a-z][a-z0-9-]*$/;
1274
1446
  var SHORT_CAPABILITY_RE = /^[a-z0-9-]+(\.[a-z0-9-]+)*$/;
1275
1447
  var SHORT_CONFIG_KEY_RE = /^[a-z0-9]+(\.[a-z0-9-]+)*$/;
@@ -1489,45 +1661,45 @@ var manifestSourceSchema = z.object({
1489
1661
  error: "must be an object"
1490
1662
  }).optional()
1491
1663
  }).passthrough();
1492
- function setDefined(target, key, value) {
1664
+ function setDefined2(target, key, value) {
1493
1665
  if (value !== void 0) {
1494
1666
  target[key] = value;
1495
1667
  }
1496
1668
  }
1497
1669
  function manifestConfigPatch(config) {
1498
1670
  const result = {};
1499
- setDefined(result, "description", config.description);
1500
- setDefined(result, "capabilities", config.capabilities);
1501
- setDefined(result, "config-keys", config.configKeys);
1502
- setDefined(result, "domains", config.domains);
1503
- setDefined(result, "api-headers", config.apiHeaders);
1504
- setDefined(result, "command-env", config.commandEnv);
1505
- setDefined(result, "env-vars", config.envVars);
1671
+ setDefined2(result, "description", config.description);
1672
+ setDefined2(result, "capabilities", config.capabilities);
1673
+ setDefined2(result, "config-keys", config.configKeys);
1674
+ setDefined2(result, "domains", config.domains);
1675
+ setDefined2(result, "api-headers", config.apiHeaders);
1676
+ setDefined2(result, "command-env", config.commandEnv);
1677
+ setDefined2(result, "env-vars", config.envVars);
1506
1678
  if (config.credentials !== void 0) {
1507
1679
  if (!config.credentials) {
1508
1680
  result.credentials = null;
1509
1681
  } else {
1510
1682
  const credentials = {};
1511
- setDefined(credentials, "type", config.credentials.type);
1512
- setDefined(credentials, "domains", config.credentials.domains);
1513
- setDefined(credentials, "api-headers", config.credentials.apiHeaders);
1514
- setDefined(
1683
+ setDefined2(credentials, "type", config.credentials.type);
1684
+ setDefined2(credentials, "domains", config.credentials.domains);
1685
+ setDefined2(credentials, "api-headers", config.credentials.apiHeaders);
1686
+ setDefined2(
1515
1687
  credentials,
1516
1688
  "auth-token-env",
1517
1689
  config.credentials.authTokenEnv
1518
1690
  );
1519
- setDefined(
1691
+ setDefined2(
1520
1692
  credentials,
1521
1693
  "auth-token-placeholder",
1522
1694
  config.credentials.authTokenPlaceholder
1523
1695
  );
1524
- setDefined(credentials, "app-id-env", config.credentials.appIdEnv);
1525
- setDefined(
1696
+ setDefined2(credentials, "app-id-env", config.credentials.appIdEnv);
1697
+ setDefined2(
1526
1698
  credentials,
1527
1699
  "private-key-env",
1528
1700
  config.credentials.privateKeyEnv
1529
1701
  );
1530
- setDefined(
1702
+ setDefined2(
1531
1703
  credentials,
1532
1704
  "installation-id-env",
1533
1705
  config.credentials.installationIdEnv
@@ -1535,17 +1707,17 @@ function manifestConfigPatch(config) {
1535
1707
  result.credentials = credentials;
1536
1708
  }
1537
1709
  }
1538
- setDefined(result, "runtime-dependencies", config.runtimeDependencies);
1539
- setDefined(result, "runtime-postinstall", config.runtimePostinstall);
1710
+ setDefined2(result, "runtime-dependencies", config.runtimeDependencies);
1711
+ setDefined2(result, "runtime-postinstall", config.runtimePostinstall);
1540
1712
  if (config.mcp !== void 0) {
1541
1713
  if (!config.mcp) {
1542
1714
  result.mcp = null;
1543
1715
  } else {
1544
1716
  const mcp = {};
1545
- setDefined(mcp, "transport", config.mcp.transport);
1546
- setDefined(mcp, "url", config.mcp.url);
1547
- setDefined(mcp, "headers", config.mcp.headers);
1548
- setDefined(mcp, "allowed-tools", config.mcp.allowedTools);
1717
+ setDefined2(mcp, "transport", config.mcp.transport);
1718
+ setDefined2(mcp, "url", config.mcp.url);
1719
+ setDefined2(mcp, "headers", config.mcp.headers);
1720
+ setDefined2(mcp, "allowed-tools", config.mcp.allowedTools);
1549
1721
  result.mcp = mcp;
1550
1722
  }
1551
1723
  }
@@ -1554,14 +1726,14 @@ function manifestConfigPatch(config) {
1554
1726
  result.oauth = null;
1555
1727
  } else {
1556
1728
  const oauth = {};
1557
- setDefined(oauth, "client-id-env", config.oauth.clientIdEnv);
1558
- setDefined(oauth, "client-secret-env", config.oauth.clientSecretEnv);
1559
- setDefined(oauth, "authorize-endpoint", config.oauth.authorizeEndpoint);
1560
- setDefined(oauth, "token-endpoint", config.oauth.tokenEndpoint);
1561
- setDefined(oauth, "scope", config.oauth.scope);
1562
- setDefined(oauth, "authorize-params", config.oauth.authorizeParams);
1563
- setDefined(oauth, "token-auth-method", config.oauth.tokenAuthMethod);
1564
- setDefined(oauth, "token-extra-headers", config.oauth.tokenExtraHeaders);
1729
+ setDefined2(oauth, "client-id-env", config.oauth.clientIdEnv);
1730
+ setDefined2(oauth, "client-secret-env", config.oauth.clientSecretEnv);
1731
+ setDefined2(oauth, "authorize-endpoint", config.oauth.authorizeEndpoint);
1732
+ setDefined2(oauth, "token-endpoint", config.oauth.tokenEndpoint);
1733
+ setDefined2(oauth, "scope", config.oauth.scope);
1734
+ setDefined2(oauth, "authorize-params", config.oauth.authorizeParams);
1735
+ setDefined2(oauth, "token-auth-method", config.oauth.tokenAuthMethod);
1736
+ setDefined2(oauth, "token-extra-headers", config.oauth.tokenExtraHeaders);
1565
1737
  result.oauth = oauth;
1566
1738
  }
1567
1739
  }
@@ -1570,9 +1742,9 @@ function manifestConfigPatch(config) {
1570
1742
  result.target = null;
1571
1743
  } else {
1572
1744
  const target = {};
1573
- setDefined(target, "type", config.target.type);
1574
- setDefined(target, "config-key", config.target.configKey);
1575
- setDefined(target, "command-flags", config.target.commandFlags);
1745
+ setDefined2(target, "type", config.target.type);
1746
+ setDefined2(target, "config-key", config.target.configKey);
1747
+ setDefined2(target, "command-flags", config.target.commandFlags);
1576
1748
  result.target = target;
1577
1749
  }
1578
1750
  }
@@ -1741,6 +1913,21 @@ function assertCommandEnvDoesNotExposeHostSecretRefs(commandEnv, apiHeaders, cre
1741
1913
  }
1742
1914
  }
1743
1915
  }
1916
+ function assertCommandEnvHostRefsAreExplicitlyExposed(commandEnv, envVars, pluginName) {
1917
+ if (!commandEnv) {
1918
+ return;
1919
+ }
1920
+ for (const [key, value] of Object.entries(commandEnv)) {
1921
+ for (const name of envReferences(value)) {
1922
+ const declaration = envVars[name];
1923
+ if (declaration && declaration.default === void 0 && declaration.exposeToCommandEnv !== true) {
1924
+ throw new Error(
1925
+ `Plugin ${pluginName} command-env.${key} references env var ${name}, but env-vars.${name} must set expose-to-command-env: true before host env can be exposed to sandbox`
1926
+ );
1927
+ }
1928
+ }
1929
+ }
1930
+ }
1744
1931
  function normalizeCredentials(data, name) {
1745
1932
  const schema = data.type === "oauth-bearer" ? oauthBearerCredentialsSchema : data.type === "github-app" ? githubAppCredentialsSchema : void 0;
1746
1933
  if (!schema) {
@@ -1915,7 +2102,9 @@ function normalizeRuntimePostinstall(commands, name) {
1915
2102
  var envVarDeclarationSchema = z.preprocess(
1916
2103
  (value) => value === null || value === void 0 ? {} : value,
1917
2104
  z.object({
1918
- default: z.string().optional()
2105
+ default: z.string().optional(),
2106
+ "expose-to-command-env": z.boolean().optional(),
2107
+ exposeToCommandEnv: z.boolean().optional()
1919
2108
  }).strict()
1920
2109
  );
1921
2110
  function normalizeEnvVars(data, pluginName) {
@@ -1937,6 +2126,9 @@ function normalizeEnvVars(data, pluginName) {
1937
2126
  if (parsed.data.default !== void 0) {
1938
2127
  decl.default = parsed.data.default;
1939
2128
  }
2129
+ if (parsed.data["expose-to-command-env"] === true || parsed.data.exposeToCommandEnv === true) {
2130
+ decl.exposeToCommandEnv = true;
2131
+ }
1940
2132
  normalized[name] = decl;
1941
2133
  }
1942
2134
  return normalized;
@@ -1985,89 +2177,76 @@ function normalizeMcp(data, envVars, name) {
1985
2177
  ...result.data["allowed-tools"] ? { allowedTools: result.data["allowed-tools"] } : {}
1986
2178
  };
1987
2179
  }
1988
- function parsePluginManifest(raw, dir, config) {
1989
- let parsedYaml;
1990
- try {
1991
- parsedYaml = parseYaml(raw);
1992
- } catch (error) {
1993
- throw new Error(
1994
- `Invalid plugin manifest in ${dir}: ${error instanceof Error ? error.message : String(error)}`
1995
- );
1996
- }
1997
- if (!parsedYaml || typeof parsedYaml !== "object" || Array.isArray(parsedYaml)) {
1998
- throw new Error(`Invalid plugin manifest in ${dir}: expected an object`);
1999
- }
2000
- const source = applyManifestConfig(parsedYaml, config);
2180
+ function parseManifestSource(parsedSource, dir, config) {
2181
+ const source = applyManifestConfig(parsedSource, config);
2001
2182
  const sourceResult = manifestSourceSchema.safeParse(source);
2002
2183
  if (!sourceResult.success) {
2003
2184
  const issue = sourceResult.error.issues[0];
2004
2185
  const path3 = formatPath(issue?.path ?? []);
2005
2186
  if (path3 === "name") {
2006
- throw new Error(
2007
- `Invalid plugin name in ${dir}: "${parsedYaml.name}"`
2008
- );
2187
+ throw new Error(`Invalid plugin name in ${dir}: "${parsedSource.name}"`);
2009
2188
  }
2010
2189
  if (path3 === "description") {
2011
2190
  throw new Error(`Invalid plugin description in ${dir}`);
2012
2191
  }
2013
2192
  if (path3 === "capabilities") {
2014
2193
  throw new Error(
2015
- `Plugin ${parsedYaml.name ?? "unknown"} capabilities must be an array when provided`
2194
+ `Plugin ${String(parsedSource.name ?? "unknown")} capabilities must be an array when provided`
2016
2195
  );
2017
2196
  }
2018
2197
  if (path3 === "config-keys") {
2019
2198
  throw new Error(
2020
- `Plugin ${parsedYaml.name ?? "unknown"} config-keys must be an array when provided`
2199
+ `Plugin ${String(parsedSource.name ?? "unknown")} config-keys must be an array when provided`
2021
2200
  );
2022
2201
  }
2023
2202
  if (path3 === "domains") {
2024
2203
  throw new Error(
2025
- `Plugin ${parsedYaml.name ?? "unknown"} ${path3} must be a non-empty array of domains`
2204
+ `Plugin ${String(parsedSource.name ?? "unknown")} ${path3} must be a non-empty array of domains`
2026
2205
  );
2027
2206
  }
2028
2207
  if (path3 === "api-headers") {
2029
2208
  throw new Error(
2030
- `Plugin ${parsedYaml.name ?? "unknown"} api-headers must be an object when provided`
2209
+ `Plugin ${String(parsedSource.name ?? "unknown")} api-headers must be an object when provided`
2031
2210
  );
2032
2211
  }
2033
2212
  if (path3 === "command-env") {
2034
2213
  throw new Error(
2035
- `Plugin ${parsedYaml.name ?? "unknown"} command-env must be an object when provided`
2214
+ `Plugin ${String(parsedSource.name ?? "unknown")} command-env must be an object when provided`
2036
2215
  );
2037
2216
  }
2038
2217
  if (path3 === "credentials") {
2039
2218
  throw new Error(
2040
- `Plugin ${parsedYaml.name ?? "unknown"} credentials must be an object when provided`
2219
+ `Plugin ${String(parsedSource.name ?? "unknown")} credentials must be an object when provided`
2041
2220
  );
2042
2221
  }
2043
2222
  if (path3 === "runtime-dependencies") {
2044
2223
  throw new Error(
2045
- `Plugin ${parsedYaml.name ?? "unknown"} runtime-dependencies must be an array`
2224
+ `Plugin ${String(parsedSource.name ?? "unknown")} runtime-dependencies must be an array`
2046
2225
  );
2047
2226
  }
2048
2227
  if (path3 === "runtime-postinstall") {
2049
2228
  throw new Error(
2050
- `Plugin ${parsedYaml.name ?? "unknown"} runtime-postinstall must be an array`
2229
+ `Plugin ${String(parsedSource.name ?? "unknown")} runtime-postinstall must be an array`
2051
2230
  );
2052
2231
  }
2053
2232
  if (path3 === "env-vars") {
2054
2233
  throw new Error(
2055
- `Plugin ${parsedYaml.name ?? "unknown"} env-vars must be an object`
2234
+ `Plugin ${String(parsedSource.name ?? "unknown")} env-vars must be an object`
2056
2235
  );
2057
2236
  }
2058
2237
  if (path3 === "mcp") {
2059
2238
  throw new Error(
2060
- `Plugin ${parsedYaml.name ?? "unknown"} mcp must be an object`
2239
+ `Plugin ${String(parsedSource.name ?? "unknown")} mcp must be an object`
2061
2240
  );
2062
2241
  }
2063
2242
  if (path3 === "oauth") {
2064
2243
  throw new Error(
2065
- `Plugin ${parsedYaml.name ?? "unknown"} oauth must be an object`
2244
+ `Plugin ${String(parsedSource.name ?? "unknown")} oauth must be an object`
2066
2245
  );
2067
2246
  }
2068
2247
  if (path3 === "target") {
2069
2248
  throw new Error(
2070
- `Plugin ${parsedYaml.name ?? "unknown"} target must be an object`
2249
+ `Plugin ${String(parsedSource.name ?? "unknown")} target must be an object`
2071
2250
  );
2072
2251
  }
2073
2252
  throw new Error(issue?.message ?? `Invalid plugin manifest in ${dir}`);
@@ -2108,11 +2287,6 @@ function parsePluginManifest(raw, dir, config) {
2108
2287
  envVars
2109
2288
  ) : void 0;
2110
2289
  const credentials = data.credentials ? normalizeCredentials(data.credentials, data.name) : void 0;
2111
- if (commandEnv && !credentials && !apiHeaders) {
2112
- throw new Error(
2113
- `Plugin ${data.name} command-env requires credentials or api-headers`
2114
- );
2115
- }
2116
2290
  const runtimeDependencies = data["runtime-dependencies"] ? normalizeRuntimeDependencies(data["runtime-dependencies"], data.name) : void 0;
2117
2291
  const runtimePostinstall = data["runtime-postinstall"] ? normalizeRuntimePostinstall(data["runtime-postinstall"], data.name) : void 0;
2118
2292
  const mcp = data.mcp ? normalizeMcp(data.mcp, envVars, data.name) : void 0;
@@ -2175,6 +2349,11 @@ function parsePluginManifest(raw, dir, config) {
2175
2349
  manifest.oauth,
2176
2350
  data.name
2177
2351
  );
2352
+ assertCommandEnvHostRefsAreExplicitlyExposed(
2353
+ data["command-env"],
2354
+ envVars,
2355
+ data.name
2356
+ );
2178
2357
  if (data.target) {
2179
2358
  const result = targetSourceSchema.safeParse(data.target);
2180
2359
  if (!result.success) {
@@ -2205,6 +2384,23 @@ function parsePluginManifest(raw, dir, config) {
2205
2384
  }
2206
2385
  return manifest;
2207
2386
  }
2387
+ function parsePluginManifest(raw, dir, config) {
2388
+ let parsedYaml;
2389
+ try {
2390
+ parsedYaml = parseYaml(raw);
2391
+ } catch (error) {
2392
+ throw new Error(
2393
+ `Invalid plugin manifest in ${dir}: ${error instanceof Error ? error.message : String(error)}`
2394
+ );
2395
+ }
2396
+ if (!parsedYaml || typeof parsedYaml !== "object" || Array.isArray(parsedYaml)) {
2397
+ throw new Error(`Invalid plugin manifest in ${dir}: expected an object`);
2398
+ }
2399
+ return parseManifestSource(parsedYaml, dir, config);
2400
+ }
2401
+ function parseInlinePluginManifest(manifest, dir, config) {
2402
+ return parseManifestSource(inlineManifestSource(manifest), dir, config);
2403
+ }
2208
2404
 
2209
2405
  // src/chat/plugins/registry.ts
2210
2406
  import { readFileSync, readdirSync, statSync } from "fs";
@@ -2852,8 +3048,7 @@ function providerDomains(manifest) {
2852
3048
  ])
2853
3049
  ].sort((left, right) => left.localeCompare(right));
2854
3050
  }
2855
- function registerPluginManifest(state, raw, pluginDir) {
2856
- const manifest = parsePluginManifest(raw, pluginDir, pluginConfig);
3051
+ function registerPluginManifest(state, manifest, pluginDir, skillsDir) {
2857
3052
  if (state.pluginsByName.has(manifest.name)) {
2858
3053
  throw new Error(`Duplicate plugin name "${manifest.name}"`);
2859
3054
  }
@@ -2868,14 +3063,14 @@ function registerPluginManifest(state, raw, pluginDir) {
2868
3063
  const owner = state.domainToPlugin.get(domain);
2869
3064
  if (owner) {
2870
3065
  throw new Error(
2871
- `Duplicate provider domain "${domain}" in plugin "${manifest.name}" already declared by plugin "${owner}". Use plugins.manifests in PluginConfig to change one plugin's domains or credentials.`
3066
+ `Duplicate provider domain "${domain}" in plugin "${manifest.name}" already declared by plugin "${owner}". Use plugins.manifests in PluginCatalogConfig to change one plugin's domains or credentials.`
2872
3067
  );
2873
3068
  }
2874
3069
  }
2875
3070
  const definition = {
2876
3071
  manifest,
2877
3072
  dir: pluginDir,
2878
- skillsDir: path2.join(pluginDir, "skills")
3073
+ ...skillsDir ? { skillsDir } : {}
2879
3074
  };
2880
3075
  state.pluginDefinitions.push(definition);
2881
3076
  state.pluginsByName.set(manifest.name, definition);
@@ -2889,6 +3084,15 @@ function registerPluginManifest(state, raw, pluginDir) {
2889
3084
  state.domainToPlugin.set(domain, manifest.name);
2890
3085
  }
2891
3086
  }
3087
+ function registerYamlPluginManifest(state, raw, pluginDir) {
3088
+ const manifest = parsePluginManifest(raw, pluginDir, pluginConfig);
3089
+ registerPluginManifest(
3090
+ state,
3091
+ manifest,
3092
+ pluginDir,
3093
+ path2.join(pluginDir, "skills")
3094
+ );
3095
+ }
2892
3096
  function normalizePluginRoots(roots) {
2893
3097
  const resolved = [];
2894
3098
  const seen = /* @__PURE__ */ new Set();
@@ -2910,10 +3114,14 @@ function getPluginCatalogSource() {
2910
3114
  ...packagedContent.manifestRoots
2911
3115
  ]);
2912
3116
  const packagedSkillRoots = normalizePluginRoots(packagedContent.skillRoots);
3117
+ const inlineManifests = pluginConfig?.inlineManifests ?? [];
2913
3118
  return {
3119
+ inlineManifests,
2914
3120
  manifestRoots,
2915
3121
  packagedSkillRoots,
3122
+ packagedContent,
2916
3123
  signature: JSON.stringify({
3124
+ inlineManifests,
2917
3125
  manifestRoots,
2918
3126
  packagedSkillRoots,
2919
3127
  packageNames: [...packagedContent.packageNames].sort(),
@@ -2921,24 +3129,42 @@ function getPluginCatalogSource() {
2921
3129
  })
2922
3130
  };
2923
3131
  }
2924
- function normalizePluginConfig(config) {
3132
+ function normalizePluginCatalogConfig(config) {
2925
3133
  if (!config) {
2926
3134
  return void 0;
2927
3135
  }
2928
3136
  return {
3137
+ inlineManifests: config.inlineManifests ? structuredClone(config.inlineManifests) : void 0,
2929
3138
  packages: normalizePluginPackageNames(config.packages),
2930
3139
  ...config.manifests ? { manifests: structuredClone(config.manifests) } : {}
2931
3140
  };
2932
3141
  }
2933
- function clonePluginConfig(config) {
3142
+ function clonePluginCatalogConfig(config) {
2934
3143
  if (!config) {
2935
3144
  return void 0;
2936
3145
  }
2937
3146
  return {
3147
+ ...config.inlineManifests ? { inlineManifests: structuredClone(config.inlineManifests) } : {},
2938
3148
  packages: [...config.packages ?? []],
2939
3149
  ...config.manifests ? { manifests: structuredClone(config.manifests) } : {}
2940
3150
  };
2941
3151
  }
3152
+ function packageContentByName(packagedContent, packageName) {
3153
+ return packagedContent.packages.find((pkg) => pkg.name === packageName);
3154
+ }
3155
+ function registerInlineManifests(state, source) {
3156
+ for (const definition of source.inlineManifests) {
3157
+ const pkg = definition.packageName ? packageContentByName(source.packagedContent, definition.packageName) : void 0;
3158
+ const dir = pkg?.dir ?? process.cwd();
3159
+ const skillsDir = pkg?.hasSkillsDir ? path2.join(pkg.dir, "skills") : void 0;
3160
+ const manifest = parseInlinePluginManifest(
3161
+ definition.manifest,
3162
+ dir,
3163
+ pluginConfig
3164
+ );
3165
+ registerPluginManifest(state, manifest, dir, skillsDir);
3166
+ }
3167
+ }
2942
3168
  function discoverConfiguredPluginPackageContent() {
2943
3169
  return discoverInstalledPluginPackageContent(process.cwd(), {
2944
3170
  packageNames: pluginConfig?.packages
@@ -2949,6 +3175,7 @@ function buildLoadedPluginState(source) {
2949
3175
  for (const skillRoot of source.packagedSkillRoots) {
2950
3176
  state.packageSkillRoots.add(skillRoot);
2951
3177
  }
3178
+ registerInlineManifests(state, source);
2952
3179
  const roots = source.manifestRoots;
2953
3180
  for (const pluginsRoot of roots) {
2954
3181
  let entries;
@@ -2977,7 +3204,7 @@ function buildLoadedPluginState(source) {
2977
3204
  }
2978
3205
  if (hasRootManifest) {
2979
3206
  const rawRootManifest = readFileSync(manifestPath, "utf8");
2980
- registerPluginManifest(state, rawRootManifest, pluginsRoot);
3207
+ registerYamlPluginManifest(state, rawRootManifest, pluginsRoot);
2981
3208
  continue;
2982
3209
  }
2983
3210
  }
@@ -3010,7 +3237,7 @@ function buildLoadedPluginState(source) {
3010
3237
  } catch {
3011
3238
  continue;
3012
3239
  }
3013
- registerPluginManifest(state, raw, pluginDir);
3240
+ registerYamlPluginManifest(state, raw, pluginDir);
3014
3241
  }
3015
3242
  }
3016
3243
  for (const name of Object.keys(pluginConfig?.manifests ?? {})) {
@@ -3040,7 +3267,7 @@ function logLoadedPlugins(state) {
3040
3267
  "app.plugin.config_key_count": plugin.manifest.configKeys.length,
3041
3268
  "app.plugin.has_mcp": Boolean(plugin.manifest.mcp),
3042
3269
  "file.directory": plugin.dir,
3043
- "app.file.skill_directory": plugin.skillsDir
3270
+ ...plugin.skillsDir ? { "app.file.skill_directory": plugin.skillsDir } : {}
3044
3271
  },
3045
3272
  "Loaded plugin"
3046
3273
  );
@@ -3056,9 +3283,9 @@ function ensurePluginsLoaded() {
3056
3283
  logLoadedPlugins(state);
3057
3284
  return state;
3058
3285
  }
3059
- function setPluginConfig(config) {
3060
- const previousConfig = clonePluginConfig(pluginConfig);
3061
- pluginConfig = normalizePluginConfig(config);
3286
+ function setPluginCatalogConfig(config) {
3287
+ const previousConfig = clonePluginCatalogConfig(pluginConfig);
3288
+ pluginConfig = normalizePluginCatalogConfig(config);
3062
3289
  return previousConfig;
3063
3290
  }
3064
3291
  function getPluginPackageContent() {
@@ -3152,7 +3379,9 @@ function getPluginSkillRoots() {
3152
3379
  const state = ensurePluginsLoaded();
3153
3380
  return [
3154
3381
  .../* @__PURE__ */ new Set([
3155
- ...state.pluginDefinitions.map((plugin) => plugin.skillsDir),
3382
+ ...state.pluginDefinitions.flatMap(
3383
+ (plugin) => plugin.skillsDir ? [plugin.skillsDir] : []
3384
+ ),
3156
3385
  ...state.packageSkillRoots
3157
3386
  ])
3158
3387
  ];
@@ -3161,6 +3390,9 @@ function getPluginForSkillPath(skillPath) {
3161
3390
  const state = ensurePluginsLoaded();
3162
3391
  const resolvedSkillPath = path2.resolve(skillPath);
3163
3392
  return state.pluginDefinitions.find((plugin) => {
3393
+ if (!plugin.skillsDir) {
3394
+ return false;
3395
+ }
3164
3396
  const resolvedSkillsDir = path2.resolve(plugin.skillsDir);
3165
3397
  return resolvedSkillPath === resolvedSkillsDir || resolvedSkillPath.startsWith(`${resolvedSkillsDir}${path2.sep}`);
3166
3398
  });
@@ -3210,6 +3442,7 @@ export {
3210
3442
  normalizeGenAiFinishReason,
3211
3443
  createChatSdkLogger,
3212
3444
  getLogContextAttributes,
3445
+ setSentryUser,
3213
3446
  logInfo,
3214
3447
  logWarn,
3215
3448
  logError,
@@ -3232,7 +3465,7 @@ export {
3232
3465
  hasRequiredOAuthScope,
3233
3466
  buildOAuthTokenRequest,
3234
3467
  parseOAuthTokenResponse,
3235
- setPluginConfig,
3468
+ setPluginCatalogConfig,
3236
3469
  getPluginPackageContent,
3237
3470
  getPluginCatalogSignature,
3238
3471
  getPluginCapabilityProviders,