@sentry/junior 0.33.0 → 0.35.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.
@@ -7,7 +7,7 @@ import {
7
7
  serializeGenAiAttribute,
8
8
  setSpanAttributes,
9
9
  withSpan
10
- } from "./chunk-XARRBRQV.js";
10
+ } from "./chunk-QZRPUFO6.js";
11
11
 
12
12
  // src/chat/state/adapter.ts
13
13
  import { createMemoryState } from "@chat-adapter/state-memory";
@@ -128,68 +128,73 @@ async function completeText(params) {
128
128
  const apiKey = getPiGatewayApiKeyOverride();
129
129
  const requestMessagesAttribute = serializeGenAiAttribute(params.messages);
130
130
  const systemInstructionsAttribute = params.system ? serializeGenAiAttribute([{ type: "text", content: params.system }]) : void 0;
131
- const startAttributes = {
131
+ const baseAttributes = {
132
132
  "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
133
133
  "gen_ai.operation.name": GEN_AI_OPERATION_CHAT,
134
134
  "gen_ai.request.model": params.modelId,
135
+ ...params.thinkingLevel ? { "app.ai.reasoning_effort": params.thinkingLevel } : {}
136
+ };
137
+ const startAttributes = {
138
+ ...baseAttributes,
135
139
  ...systemInstructionsAttribute ? { "gen_ai.system_instructions": systemInstructionsAttribute } : {},
136
140
  ...requestMessagesAttribute ? { "gen_ai.input.messages": requestMessagesAttribute } : {},
137
- "app.ai.auth_mode": apiKey ? "oidc" : "api_key",
138
- ...params.thinkingLevel ? { "app.ai.reasoning_effort": params.thinkingLevel } : {}
141
+ "app.ai.auth_mode": apiKey ? "oidc" : "api_key"
139
142
  };
140
- setSpanAttributes(startAttributes);
141
- const message = await completeSimple(
142
- model,
143
- {
144
- systemPrompt: params.system,
145
- messages: params.messages
143
+ return withSpan(
144
+ "ai.chat_completion",
145
+ "gen_ai.chat",
146
+ { modelId: params.modelId },
147
+ async () => {
148
+ const message = await completeSimple(
149
+ model,
150
+ {
151
+ systemPrompt: params.system,
152
+ messages: params.messages
153
+ },
154
+ {
155
+ ...apiKey ? { apiKey } : {},
156
+ temperature: params.temperature,
157
+ maxTokens: params.maxTokens,
158
+ reasoning: params.thinkingLevel,
159
+ signal: params.signal,
160
+ metadata: params.metadata
161
+ }
162
+ );
163
+ const outputText = extractText(message);
164
+ const outputMessagesAttribute = serializeGenAiAttribute([
165
+ {
166
+ role: "assistant",
167
+ content: outputText ? [{ type: "text", text: outputText }] : []
168
+ }
169
+ ]);
170
+ const usageAttributes = extractGenAiUsageAttributes(message);
171
+ const endAttributes = {
172
+ ...baseAttributes,
173
+ ...outputMessagesAttribute ? { "gen_ai.output.messages": outputMessagesAttribute } : {},
174
+ ...usageAttributes,
175
+ ...message.stopReason ? { "gen_ai.response.finish_reasons": [message.stopReason] } : {}
176
+ };
177
+ setSpanAttributes(endAttributes);
178
+ if (message.stopReason === "error") {
179
+ const providerMessage = message.errorMessage?.trim() || "Unknown provider error";
180
+ logWarn(
181
+ "ai_completion_provider_error",
182
+ {},
183
+ {
184
+ ...baseAttributes,
185
+ "error.message": providerMessage
186
+ },
187
+ "AI completion returned provider error"
188
+ );
189
+ throw new Error(`AI provider error: ${providerMessage}`);
190
+ }
191
+ return {
192
+ message,
193
+ text: outputText
194
+ };
146
195
  },
147
- {
148
- ...apiKey ? { apiKey } : {},
149
- temperature: params.temperature,
150
- maxTokens: params.maxTokens,
151
- reasoning: params.thinkingLevel,
152
- signal: params.signal,
153
- metadata: params.metadata
154
- }
196
+ startAttributes
155
197
  );
156
- const outputText = extractText(message);
157
- const outputMessagesAttribute = serializeGenAiAttribute([
158
- {
159
- role: "assistant",
160
- content: outputText ? [{ type: "text", text: outputText }] : []
161
- }
162
- ]);
163
- const usageAttributes = extractGenAiUsageAttributes(message);
164
- const endAttributes = {
165
- "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
166
- "gen_ai.operation.name": GEN_AI_OPERATION_CHAT,
167
- "gen_ai.request.model": params.modelId,
168
- ...outputMessagesAttribute ? { "gen_ai.output.messages": outputMessagesAttribute } : {},
169
- ...usageAttributes,
170
- ...message.stopReason ? { "gen_ai.response.finish_reasons": [message.stopReason] } : {},
171
- ...params.thinkingLevel ? { "app.ai.reasoning_effort": params.thinkingLevel } : {}
172
- };
173
- setSpanAttributes(endAttributes);
174
- if (message.stopReason === "error") {
175
- const providerMessage = message.errorMessage?.trim() || "Unknown provider error";
176
- logWarn(
177
- "ai_completion_provider_error",
178
- {},
179
- {
180
- "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
181
- "gen_ai.operation.name": GEN_AI_OPERATION_CHAT,
182
- "gen_ai.request.model": params.modelId,
183
- "error.message": providerMessage
184
- },
185
- "AI completion returned provider error"
186
- );
187
- throw new Error(`AI provider error: ${providerMessage}`);
188
- }
189
- return {
190
- message,
191
- text: outputText
192
- };
193
198
  }
194
199
  async function completeObject(params) {
195
200
  const startedAt = Date.now();
@@ -256,6 +261,14 @@ async function completeObject(params) {
256
261
  var MIN_AGENT_TURN_TIMEOUT_MS = 10 * 1e3;
257
262
  var DEFAULT_AGENT_TURN_TIMEOUT_MS = 12 * 60 * 1e3;
258
263
  var DEFAULT_FUNCTION_MAX_DURATION_SECONDS = 800;
264
+ var ADVISOR_THINKING_LEVELS = [
265
+ "minimal",
266
+ "low",
267
+ "medium",
268
+ "high",
269
+ "xhigh"
270
+ ];
271
+ var DEFAULT_ADVISOR_THINKING_LEVEL = "xhigh";
259
272
  var FUNCTION_TIMEOUT_BUFFER_SECONDS = 20;
260
273
  var DEFAULT_ASSISTANT_LOADING_MESSAGES = [
261
274
  "Consulting the orb",
@@ -314,17 +327,39 @@ function parseLoadingMessages(rawValue) {
314
327
  return value.trim();
315
328
  });
316
329
  }
330
+ function parseAdvisorThinkingLevel(rawValue) {
331
+ const value = toOptionalTrimmed(rawValue);
332
+ if (!value) {
333
+ return DEFAULT_ADVISOR_THINKING_LEVEL;
334
+ }
335
+ if (ADVISOR_THINKING_LEVELS.includes(value)) {
336
+ return value;
337
+ }
338
+ throw new Error(
339
+ `AI_ADVISOR_THINKING_LEVEL must be one of: minimal, low, medium, high, xhigh`
340
+ );
341
+ }
317
342
  var DEFAULT_MODEL_ID = getModel("vercel-ai-gateway", "openai/gpt-5.4").id;
318
343
  var DEFAULT_FAST_MODEL_ID = getModel(
319
344
  "vercel-ai-gateway",
320
345
  "openai/gpt-5.4-mini"
321
346
  ).id;
347
+ var DEFAULT_ADVISOR_MODEL_ID = getModel(
348
+ "vercel-ai-gateway",
349
+ "openai/gpt-5.5"
350
+ ).id;
322
351
  function validateGatewayModelId(raw) {
323
352
  const trimmed = toOptionalTrimmed(raw);
324
353
  if (trimmed === void 0) return void 0;
325
354
  resolveGatewayModel(trimmed);
326
355
  return trimmed;
327
356
  }
357
+ function readAdvisorConfig(env) {
358
+ return {
359
+ modelId: validateGatewayModelId(env.AI_ADVISOR_MODEL) ?? DEFAULT_ADVISOR_MODEL_ID,
360
+ thinkingLevel: parseAdvisorThinkingLevel(env.AI_ADVISOR_THINKING_LEVEL)
361
+ };
362
+ }
328
363
  function readBotConfig(env) {
329
364
  const functionMaxDurationSeconds = resolveFunctionMaxDurationSeconds(env);
330
365
  const maxTurnTimeoutMs = resolveMaxTurnTimeoutMs(functionMaxDurationSeconds);
@@ -337,7 +372,8 @@ function readBotConfig(env) {
337
372
  turnTimeoutMs: parseAgentTurnTimeoutMs(
338
373
  env.AGENT_TURN_TIMEOUT_MS,
339
374
  maxTurnTimeoutMs
340
- )
375
+ ),
376
+ advisor: readAdvisorConfig(env)
341
377
  };
342
378
  }
343
379
  function readChatConfig(env = process.env) {
@@ -2,7 +2,7 @@ import {
2
2
  getPluginForSkillPath,
3
3
  getPluginSkillRoots,
4
4
  logWarn
5
- } from "./chunk-XARRBRQV.js";
5
+ } from "./chunk-QZRPUFO6.js";
6
6
  import {
7
7
  skillRoots
8
8
  } from "./chunk-XPXD3FCE.js";
@@ -971,6 +971,9 @@ function setLogContext(context) {
971
971
  );
972
972
  contextStorage.enterWith(merged);
973
973
  }
974
+ function getLogContextAttributes() {
975
+ return contextStorage.getStore() ?? {};
976
+ }
974
977
  function createLogContextFromRequest(request, context = {}) {
975
978
  const url = new URL(request.url);
976
979
  return {
@@ -1052,20 +1055,20 @@ async function withSpan(name, op, context, callback, attributes = {}) {
1052
1055
  normalizedAttributes[key] = normalizedValue;
1053
1056
  }
1054
1057
  }
1055
- return withLogContext(
1056
- context,
1057
- () => sentry_exports.startSpan(
1058
+ return withLogContext(context, () => {
1059
+ const inheritedAttributes = getLogContextAttributes();
1060
+ return sentry_exports.startSpan(
1058
1061
  {
1059
1062
  name,
1060
1063
  op,
1061
1064
  attributes: {
1062
- ...toSpanAttributes(context),
1065
+ ...inheritedAttributes,
1063
1066
  ...normalizedAttributes
1064
1067
  }
1065
1068
  },
1066
1069
  callback
1067
- )
1068
- );
1070
+ );
1071
+ });
1069
1072
  }
1070
1073
  function setSpanAttributes(attributes) {
1071
1074
  const sentry = sentry_exports;
@@ -1246,6 +1249,7 @@ var SHORT_CONFIG_KEY_RE = /^[a-z0-9]+(\.[a-z0-9-]+)*$/;
1246
1249
  var TARGET_FLAG_RE = /^-{1,2}[A-Za-z0-9][A-Za-z0-9-]*$/;
1247
1250
  var AUTH_TOKEN_ENV_RE = /^[A-Z][A-Z0-9_]*$/;
1248
1251
  var ENV_VAR_NAME_RE = /^[A-Z_][A-Z0-9_]*$/;
1252
+ var ENV_PLACEHOLDER_RE = /\$\{([A-Z_][A-Z0-9_]*)\}/g;
1249
1253
  var API_DOMAIN_RE = /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
1250
1254
  var RUNTIME_POSTINSTALL_CMD_RE = /^[A-Za-z0-9._/-]+$/;
1251
1255
  var RESERVED_AUTHORIZE_PARAM_KEYS = /* @__PURE__ */ new Set([
@@ -1340,7 +1344,7 @@ var stringMapSchema = z.record(z.string(), z.unknown()).transform((record, ctx)
1340
1344
  seen.add(normalizedKey);
1341
1345
  result[key] = rawValue.trim();
1342
1346
  }
1343
- return Object.keys(result).length > 0 ? result : void 0;
1347
+ return result;
1344
1348
  });
1345
1349
  var apiDomainsSchema = z.array(z.unknown()).min(1, {
1346
1350
  error: "must be a non-empty array of strings"
@@ -1433,6 +1437,8 @@ var manifestSourceSchema = z.object({
1433
1437
  "config-keys": z.array(z.string(), {
1434
1438
  error: "must be an array when provided"
1435
1439
  }).optional(),
1440
+ "api-domains": apiDomainsSchema.optional(),
1441
+ "api-headers": stringMapSchema.optional(),
1436
1442
  credentials: z.record(z.string(), z.unknown(), {
1437
1443
  error: "must be an object when provided"
1438
1444
  }).optional(),
@@ -1470,7 +1476,11 @@ function normalizeStringMap(value, prefix, options = {}) {
1470
1476
  if (!value) {
1471
1477
  return void 0;
1472
1478
  }
1473
- for (const key of Object.keys(value)) {
1479
+ const keys = Object.keys(value);
1480
+ if (keys.length === 0) {
1481
+ return void 0;
1482
+ }
1483
+ for (const key of keys) {
1474
1484
  const normalizedKey = key.toLowerCase();
1475
1485
  if (options.reservedKeys?.has(normalizedKey)) {
1476
1486
  throw new Error(`${prefix}.${key} is reserved by the runtime`);
@@ -1481,6 +1491,31 @@ function normalizeStringMap(value, prefix, options = {}) {
1481
1491
  }
1482
1492
  return value;
1483
1493
  }
1494
+ function assertDeclaredEnvReferences(value, envVars, context) {
1495
+ for (const match of value.matchAll(ENV_PLACEHOLDER_RE)) {
1496
+ const name = match[1];
1497
+ if (!Object.prototype.hasOwnProperty.call(envVars, name)) {
1498
+ throw new Error(
1499
+ `${context} references env var ${name} which is not declared in env-vars`
1500
+ );
1501
+ }
1502
+ if (envVars[name]?.default !== void 0) {
1503
+ throw new Error(
1504
+ `${context} references env var ${name}, but API header env vars must not declare defaults`
1505
+ );
1506
+ }
1507
+ }
1508
+ }
1509
+ function normalizeRequiredApiHeaders(value, prefix, envVars) {
1510
+ const apiHeaders = normalizeStringMap(value, prefix);
1511
+ if (!apiHeaders) {
1512
+ throw new Error(`${prefix} must contain at least one header`);
1513
+ }
1514
+ for (const [key, headerValue] of Object.entries(apiHeaders)) {
1515
+ assertDeclaredEnvReferences(headerValue, envVars, `${prefix}.${key}`);
1516
+ }
1517
+ return apiHeaders;
1518
+ }
1484
1519
  function normalizeCredentials(data, name) {
1485
1520
  const schema = data.type === "oauth-bearer" ? oauthBearerCredentialsSchema : data.type === "github-app" ? githubAppCredentialsSchema : void 0;
1486
1521
  if (!schema) {
@@ -1493,30 +1528,28 @@ function normalizeCredentials(data, name) {
1493
1528
  throw new Error(issueMessage(result.error, `Plugin ${name} credentials`));
1494
1529
  }
1495
1530
  if (result.data.type === "oauth-bearer") {
1531
+ const apiHeaders2 = result.data["api-headers"] ? normalizeStringMap(
1532
+ result.data["api-headers"],
1533
+ `Plugin ${name} credentials.api-headers`,
1534
+ { forbiddenKeys: FORBIDDEN_API_HEADER_NAMES }
1535
+ ) : void 0;
1496
1536
  return {
1497
1537
  type: "oauth-bearer",
1498
1538
  apiDomains: result.data["api-domains"],
1499
- ...result.data["api-headers"] ? {
1500
- apiHeaders: normalizeStringMap(
1501
- result.data["api-headers"],
1502
- `Plugin ${name} credentials.api-headers`,
1503
- { forbiddenKeys: FORBIDDEN_API_HEADER_NAMES }
1504
- )
1505
- } : {},
1539
+ ...apiHeaders2 ? { apiHeaders: apiHeaders2 } : {},
1506
1540
  authTokenEnv: result.data["auth-token-env"],
1507
1541
  ...result.data["auth-token-placeholder"] ? { authTokenPlaceholder: result.data["auth-token-placeholder"] } : {}
1508
1542
  };
1509
1543
  }
1544
+ const apiHeaders = result.data["api-headers"] ? normalizeStringMap(
1545
+ result.data["api-headers"],
1546
+ `Plugin ${name} credentials.api-headers`,
1547
+ { forbiddenKeys: FORBIDDEN_API_HEADER_NAMES }
1548
+ ) : void 0;
1510
1549
  return {
1511
1550
  type: "github-app",
1512
1551
  apiDomains: result.data["api-domains"],
1513
- ...result.data["api-headers"] ? {
1514
- apiHeaders: normalizeStringMap(
1515
- result.data["api-headers"],
1516
- `Plugin ${name} credentials.api-headers`,
1517
- { forbiddenKeys: FORBIDDEN_API_HEADER_NAMES }
1518
- )
1519
- } : {},
1552
+ ...apiHeaders ? { apiHeaders } : {},
1520
1553
  authTokenEnv: result.data["auth-token-env"],
1521
1554
  ...result.data["auth-token-placeholder"] ? { authTokenPlaceholder: result.data["auth-token-placeholder"] } : {},
1522
1555
  appIdEnv: result.data["app-id-env"],
@@ -1650,7 +1683,6 @@ function normalizeRuntimePostinstall(commands, name) {
1650
1683
  }
1651
1684
  return parsed.length > 0 ? parsed : void 0;
1652
1685
  }
1653
- var ENV_PLACEHOLDER_RE = /\$\{([A-Z_][A-Z0-9_]*)\}/g;
1654
1686
  var envVarDeclarationSchema = z.preprocess(
1655
1687
  (value) => value === null || value === void 0 ? {} : value,
1656
1688
  z.object({
@@ -1714,16 +1746,13 @@ function normalizeMcp(data, envVars, name) {
1714
1746
  if (!result.success) {
1715
1747
  throw new Error(issueMessage(result.error, `Plugin ${name} mcp`));
1716
1748
  }
1749
+ const headers = result.data.headers ? normalizeStringMap(result.data.headers, `Plugin ${name} mcp.headers`, {
1750
+ forbiddenKeys: FORBIDDEN_API_HEADER_NAMES
1751
+ }) : void 0;
1717
1752
  return {
1718
1753
  transport: "http",
1719
1754
  url: result.data.url,
1720
- ...result.data.headers ? {
1721
- headers: normalizeStringMap(
1722
- result.data.headers,
1723
- `Plugin ${name} mcp.headers`,
1724
- { forbiddenKeys: FORBIDDEN_API_HEADER_NAMES }
1725
- )
1726
- } : {},
1755
+ ...headers ? { headers } : {},
1727
1756
  ...result.data["allowed-tools"] ? { allowedTools: result.data["allowed-tools"] } : {}
1728
1757
  };
1729
1758
  }
@@ -1761,6 +1790,16 @@ function parsePluginManifest(raw, dir) {
1761
1790
  `Plugin ${parsedYaml.name ?? "unknown"} config-keys must be an array when provided`
1762
1791
  );
1763
1792
  }
1793
+ if (path3 === "api-domains") {
1794
+ throw new Error(
1795
+ `Plugin ${parsedYaml.name ?? "unknown"} api-domains must be a non-empty array of domains`
1796
+ );
1797
+ }
1798
+ if (path3 === "api-headers") {
1799
+ throw new Error(
1800
+ `Plugin ${parsedYaml.name ?? "unknown"} api-headers must be an object when provided`
1801
+ );
1802
+ }
1764
1803
  if (path3 === "credentials") {
1765
1804
  throw new Error(
1766
1805
  `Plugin ${parsedYaml.name ?? "unknown"} credentials must be an object when provided`
@@ -1813,16 +1852,29 @@ function parsePluginManifest(raw, dir) {
1813
1852
  }
1814
1853
  return `${data.name}.${key}`;
1815
1854
  });
1855
+ const envVars = data["env-vars"] ? normalizeEnvVars(data["env-vars"], data.name) : {};
1856
+ const apiHeaders = data["api-headers"] ? normalizeRequiredApiHeaders(
1857
+ data["api-headers"],
1858
+ `Plugin ${data.name} api-headers`,
1859
+ envVars
1860
+ ) : void 0;
1861
+ if (apiHeaders && !data["api-domains"]) {
1862
+ throw new Error(`Plugin ${data.name} api-headers requires api-domains`);
1863
+ }
1864
+ if (data["api-domains"] && !apiHeaders) {
1865
+ throw new Error(`Plugin ${data.name} api-domains requires api-headers`);
1866
+ }
1816
1867
  const credentials = data.credentials ? normalizeCredentials(data.credentials, data.name) : void 0;
1817
1868
  const runtimeDependencies = data["runtime-dependencies"] ? normalizeRuntimeDependencies(data["runtime-dependencies"], data.name) : void 0;
1818
1869
  const runtimePostinstall = data["runtime-postinstall"] ? normalizeRuntimePostinstall(data["runtime-postinstall"], data.name) : void 0;
1819
- const envVars = data["env-vars"] ? normalizeEnvVars(data["env-vars"], data.name) : {};
1820
1870
  const mcp = data.mcp ? normalizeMcp(data.mcp, envVars, data.name) : void 0;
1821
1871
  const manifest = {
1822
1872
  name: data.name,
1823
1873
  description: data.description,
1824
1874
  capabilities,
1825
1875
  configKeys,
1876
+ ...data["api-domains"] ? { apiDomains: data["api-domains"] } : {},
1877
+ ...apiHeaders ? { apiHeaders } : {},
1826
1878
  ...Object.keys(envVars).length > 0 ? { envVars } : {},
1827
1879
  ...credentials ? { credentials } : {},
1828
1880
  ...runtimeDependencies ? { runtimeDependencies } : {},
@@ -1903,7 +1955,76 @@ import { readFileSync, readdirSync, statSync } from "fs";
1903
1955
  import path2 from "path";
1904
1956
 
1905
1957
  // src/chat/plugins/auth/github-app-broker.ts
1906
- import { createPrivateKey, createSign, randomUUID } from "crypto";
1958
+ import { createPrivateKey, createSign, randomUUID as randomUUID2 } from "crypto";
1959
+
1960
+ // src/chat/credentials/header-transforms.ts
1961
+ function mergeHeaderTransforms(transforms) {
1962
+ const byDomain = /* @__PURE__ */ new Map();
1963
+ for (const transform of transforms) {
1964
+ byDomain.set(transform.domain, {
1965
+ ...byDomain.get(transform.domain) ?? {},
1966
+ ...transform.headers
1967
+ });
1968
+ }
1969
+ return [...byDomain.entries()].map(([domain, headers]) => ({
1970
+ domain,
1971
+ headers
1972
+ }));
1973
+ }
1974
+
1975
+ // src/chat/plugins/auth/api-headers-broker.ts
1976
+ import { randomUUID } from "crypto";
1977
+ var MAX_LEASE_MS = 60 * 60 * 1e3;
1978
+ var ENV_PLACEHOLDER_RE2 = /\$\{([A-Z_][A-Z0-9_]*)\}/g;
1979
+ function resolveHeaders(provider, headers) {
1980
+ return Object.fromEntries(
1981
+ Object.entries(headers).map(([key, value]) => {
1982
+ const resolved = value.replace(ENV_PLACEHOLDER_RE2, (_match, name) => {
1983
+ const envName = name;
1984
+ const envValue = process.env[envName]?.trim();
1985
+ if (!envValue) {
1986
+ throw new Error(
1987
+ `Missing ${envName} for API header provider "${provider}"`
1988
+ );
1989
+ }
1990
+ return envValue;
1991
+ });
1992
+ return [key, resolved];
1993
+ })
1994
+ );
1995
+ }
1996
+ function resolveApiHeaderTransforms(manifest) {
1997
+ const { apiDomains, apiHeaders } = manifest;
1998
+ if (!apiDomains || !apiHeaders) {
1999
+ return [];
2000
+ }
2001
+ const resolvedHeaders = resolveHeaders(manifest.name, apiHeaders);
2002
+ return apiDomains.map((domain) => ({
2003
+ domain,
2004
+ headers: resolvedHeaders
2005
+ }));
2006
+ }
2007
+ function createApiHeadersBroker(manifest) {
2008
+ const provider = manifest.name;
2009
+ return {
2010
+ async issue(input) {
2011
+ const headerTransforms = resolveApiHeaderTransforms(manifest);
2012
+ if (headerTransforms.length === 0) {
2013
+ throw new Error(`No API headers configured for plugin "${provider}"`);
2014
+ }
2015
+ return {
2016
+ id: randomUUID(),
2017
+ provider,
2018
+ env: {},
2019
+ headerTransforms,
2020
+ expiresAt: new Date(Date.now() + MAX_LEASE_MS).toISOString(),
2021
+ metadata: {
2022
+ reason: input.reason
2023
+ }
2024
+ };
2025
+ }
2026
+ };
2027
+ }
1907
2028
 
1908
2029
  // src/chat/plugins/auth/auth-token-placeholder.ts
1909
2030
  var DEFAULT_PLACEHOLDERS = {
@@ -1915,7 +2036,7 @@ function resolveAuthTokenPlaceholder(credentials) {
1915
2036
  }
1916
2037
 
1917
2038
  // src/chat/plugins/auth/github-app-broker.ts
1918
- var MAX_LEASE_MS = 60 * 60 * 1e3;
2039
+ var MAX_LEASE_MS2 = 60 * 60 * 1e3;
1919
2040
  function base64Url(input) {
1920
2041
  return Buffer.from(input).toString("base64").replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
1921
2042
  }
@@ -2060,6 +2181,7 @@ function createGitHubAppBroker(manifest, credentials) {
2060
2181
  } = credentials;
2061
2182
  const apiBase = `https://${apiDomains[0]}`;
2062
2183
  const placeholder = resolveAuthTokenPlaceholder(credentials);
2184
+ const pluginHeaderTransforms = () => resolveApiHeaderTransforms(manifest);
2063
2185
  const GIT_DOMAIN = "github.com";
2064
2186
  const GIT_CAPABILITIES = /* @__PURE__ */ new Set([
2065
2187
  `${provider}.contents.read`,
@@ -2097,16 +2219,19 @@ function createGitHubAppBroker(manifest, credentials) {
2097
2219
  const now = Date.now();
2098
2220
  if (cached && cached.expiresAt - now > 2 * 60 * 1e3) {
2099
2221
  return {
2100
- id: randomUUID(),
2222
+ id: randomUUID2(),
2101
2223
  provider,
2102
2224
  env: { [authTokenEnv]: placeholder },
2103
- headerTransforms: leaseDomains.map((domain) => ({
2104
- domain,
2105
- headers: {
2106
- ...apiHeaders ?? {},
2107
- Authorization: authorizationFor(domain, cached.token)
2108
- }
2109
- })),
2225
+ headerTransforms: mergeHeaderTransforms([
2226
+ ...pluginHeaderTransforms(),
2227
+ ...leaseDomains.map((domain) => ({
2228
+ domain,
2229
+ headers: {
2230
+ ...apiHeaders ?? {},
2231
+ Authorization: authorizationFor(domain, cached.token)
2232
+ }
2233
+ }))
2234
+ ]),
2110
2235
  expiresAt: new Date(cached.expiresAt).toISOString(),
2111
2236
  metadata: {
2112
2237
  installationId: String(cached.installationId),
@@ -2130,7 +2255,7 @@ function createGitHubAppBroker(manifest, credentials) {
2130
2255
  const providerExpiresAtMs = Date.parse(accessTokenResponse.expires_at);
2131
2256
  const expiresAtMs = Math.min(
2132
2257
  providerExpiresAtMs,
2133
- Date.now() + MAX_LEASE_MS
2258
+ Date.now() + MAX_LEASE_MS2
2134
2259
  );
2135
2260
  tokenCache.set(cacheKey, {
2136
2261
  installationId,
@@ -2138,16 +2263,22 @@ function createGitHubAppBroker(manifest, credentials) {
2138
2263
  expiresAt: expiresAtMs
2139
2264
  });
2140
2265
  return {
2141
- id: randomUUID(),
2266
+ id: randomUUID2(),
2142
2267
  provider,
2143
2268
  env: { [authTokenEnv]: placeholder },
2144
- headerTransforms: leaseDomains.map((domain) => ({
2145
- domain,
2146
- headers: {
2147
- ...apiHeaders ?? {},
2148
- Authorization: authorizationFor(domain, accessTokenResponse.token)
2149
- }
2150
- })),
2269
+ headerTransforms: mergeHeaderTransforms([
2270
+ ...pluginHeaderTransforms(),
2271
+ ...leaseDomains.map((domain) => ({
2272
+ domain,
2273
+ headers: {
2274
+ ...apiHeaders ?? {},
2275
+ Authorization: authorizationFor(
2276
+ domain,
2277
+ accessTokenResponse.token
2278
+ )
2279
+ }
2280
+ }))
2281
+ ]),
2151
2282
  expiresAt: new Date(expiresAtMs).toISOString(),
2152
2283
  metadata: {
2153
2284
  installationId: String(installationId),
@@ -2159,7 +2290,7 @@ function createGitHubAppBroker(manifest, credentials) {
2159
2290
  }
2160
2291
 
2161
2292
  // src/chat/plugins/auth/oauth-bearer-broker.ts
2162
- import { randomUUID as randomUUID2 } from "crypto";
2293
+ import { randomUUID as randomUUID3 } from "crypto";
2163
2294
 
2164
2295
  // src/chat/credentials/broker.ts
2165
2296
  var CredentialUnavailableError = class extends Error {
@@ -2270,7 +2401,7 @@ function parseOAuthTokenResponse(data, fallbackScope) {
2270
2401
  }
2271
2402
 
2272
2403
  // src/chat/plugins/auth/oauth-bearer-broker.ts
2273
- var MAX_LEASE_MS2 = 60 * 60 * 1e3;
2404
+ var MAX_LEASE_MS3 = 60 * 60 * 1e3;
2274
2405
  var REFRESH_BUFFER_MS = 5 * 60 * 1e3;
2275
2406
  async function refreshAccessToken(refreshToken, oauth, fallbackScope) {
2276
2407
  const clientId = process.env[oauth.clientIdEnv]?.trim();
@@ -2302,21 +2433,25 @@ async function refreshAccessToken(refreshToken, oauth, fallbackScope) {
2302
2433
  return parseOAuthTokenResponse(data, fallbackScope);
2303
2434
  }
2304
2435
  function getLeaseExpiry(expiresAt) {
2305
- return expiresAt ? Math.min(expiresAt, Date.now() + MAX_LEASE_MS2) : Date.now() + MAX_LEASE_MS2;
2436
+ return expiresAt ? Math.min(expiresAt, Date.now() + MAX_LEASE_MS3) : Date.now() + MAX_LEASE_MS3;
2306
2437
  }
2307
2438
  function createOAuthBearerBroker(manifest, credentials, deps) {
2308
2439
  const provider = manifest.name;
2309
2440
  const { apiDomains, apiHeaders, authTokenEnv } = credentials;
2310
2441
  const authTokenPlaceholder = resolveAuthTokenPlaceholder(credentials);
2442
+ const pluginHeaderTransforms = () => resolveApiHeaderTransforms(manifest);
2311
2443
  function buildLease(token, expiresAtMs, reason) {
2312
2444
  return {
2313
- id: randomUUID2(),
2445
+ id: randomUUID3(),
2314
2446
  provider,
2315
2447
  env: { [authTokenEnv]: authTokenPlaceholder },
2316
- headerTransforms: apiDomains.map((domain) => ({
2317
- domain,
2318
- headers: { ...apiHeaders ?? {}, Authorization: `Bearer ${token}` }
2319
- })),
2448
+ headerTransforms: mergeHeaderTransforms([
2449
+ ...pluginHeaderTransforms(),
2450
+ ...apiDomains.map((domain) => ({
2451
+ domain,
2452
+ headers: { ...apiHeaders ?? {}, Authorization: `Bearer ${token}` }
2453
+ }))
2454
+ ]),
2320
2455
  expiresAt: new Date(expiresAtMs).toISOString(),
2321
2456
  metadata: { reason }
2322
2457
  };
@@ -2327,7 +2462,7 @@ function createOAuthBearerBroker(manifest, credentials, deps) {
2327
2462
  const oauth = manifest.oauth;
2328
2463
  if (!oauth) {
2329
2464
  if (envToken) {
2330
- return buildLease(envToken, Date.now() + MAX_LEASE_MS2, input.reason);
2465
+ return buildLease(envToken, Date.now() + MAX_LEASE_MS3, input.reason);
2331
2466
  }
2332
2467
  throw new CredentialUnavailableError(
2333
2468
  provider,
@@ -2734,11 +2869,15 @@ function createPluginBroker(provider, deps) {
2734
2869
  throw new Error(`Unknown plugin provider: "${provider}"`);
2735
2870
  }
2736
2871
  const { credentials, name } = plugin.manifest;
2737
- if (!credentials) {
2738
- throw new Error(`Provider "${name}" has no credentials configured`);
2872
+ if (!credentials && !plugin.manifest.apiHeaders) {
2873
+ throw new Error(
2874
+ `Provider "${name}" has no credentials or API headers configured`
2875
+ );
2739
2876
  }
2740
2877
  let broker;
2741
- if (credentials.type === "oauth-bearer") {
2878
+ if (!credentials) {
2879
+ broker = createApiHeadersBroker(plugin.manifest);
2880
+ } else if (credentials.type === "oauth-bearer") {
2742
2881
  broker = createOAuthBearerBroker(plugin.manifest, credentials, deps);
2743
2882
  } else if (credentials.type === "github-app") {
2744
2883
  broker = createGitHubAppBroker(plugin.manifest, credentials);
@@ -2773,6 +2912,7 @@ export {
2773
2912
  serializeGenAiAttribute,
2774
2913
  extractGenAiUsageSummary,
2775
2914
  extractGenAiUsageAttributes,
2915
+ mergeHeaderTransforms,
2776
2916
  resolveAuthTokenPlaceholder,
2777
2917
  parsePluginManifest,
2778
2918
  CredentialUnavailableError,
package/dist/cli/check.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  parseSkillFile
3
- } from "../chunk-EHXMTKBA.js";
3
+ } from "../chunk-LAD5O3RX.js";
4
4
  import {
5
5
  parsePluginManifest
6
- } from "../chunk-XARRBRQV.js";
6
+ } from "../chunk-QZRPUFO6.js";
7
7
  import "../chunk-Z3YD6NHK.js";
8
8
  import "../chunk-XPXD3FCE.js";
9
9
  import "../chunk-2KG3PWR4.js";