@integrity-labs/agt-cli 0.28.369 → 0.28.371
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-JJX2AH5K.js → chunk-D6BJJ334.js} +8 -190
- package/dist/chunk-D6BJJ334.js.map +1 -0
- package/dist/{chunk-RIWZIYJ7.js → chunk-NDF3YMP5.js} +384 -1
- package/dist/chunk-NDF3YMP5.js.map +1 -0
- package/dist/{claude-pair-runtime-NNGG572N.js → claude-pair-runtime-U2SO44TW.js} +2 -2
- package/dist/lib/manager-worker.js +116 -83
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/{persistent-session-3PAEXZHX.js → persistent-session-HXUYS63V.js} +2 -2
- package/dist/{responsiveness-probe-UEOKWHTD.js → responsiveness-probe-TVSASSZY.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-JJX2AH5K.js.map +0 -1
- package/dist/chunk-RIWZIYJ7.js.map +0 -1
- /package/dist/{claude-pair-runtime-NNGG572N.js.map → claude-pair-runtime-U2SO44TW.js.map} +0 -0
- /package/dist/{persistent-session-3PAEXZHX.js.map → persistent-session-HXUYS63V.js.map} +0 -0
- /package/dist/{responsiveness-probe-UEOKWHTD.js.map → responsiveness-probe-TVSASSZY.js.map} +0 -0
|
@@ -8922,6 +8922,282 @@ function generateAgentsMd(input) {
|
|
|
8922
8922
|
return out.join("\n");
|
|
8923
8923
|
}
|
|
8924
8924
|
|
|
8925
|
+
// ../../packages/core/dist/provisioning/remote-mcp.js
|
|
8926
|
+
function envVarForToken(definitionId) {
|
|
8927
|
+
return `${definitionId.replace(/-/g, "_").toUpperCase()}_ACCESS_TOKEN`;
|
|
8928
|
+
}
|
|
8929
|
+
function credentialEnvVar(definitionId, credentialRef) {
|
|
8930
|
+
const idPart = definitionId.replace(/-/g, "_").toUpperCase();
|
|
8931
|
+
const credPart = credentialRef.replace(/-/g, "_").toUpperCase();
|
|
8932
|
+
return `${idPart}_${credPart}`;
|
|
8933
|
+
}
|
|
8934
|
+
function assertSafeRemoteMcpUrl(url, definitionId) {
|
|
8935
|
+
let u;
|
|
8936
|
+
try {
|
|
8937
|
+
u = new URL(url);
|
|
8938
|
+
} catch {
|
|
8939
|
+
throw new Error(`remoteMcp.url for '${definitionId}' is not a valid URL: ${url}`);
|
|
8940
|
+
}
|
|
8941
|
+
if (u.protocol !== "https:") {
|
|
8942
|
+
throw new Error(`remoteMcp.url for '${definitionId}' must be https (got ${u.protocol}//): ${url}`);
|
|
8943
|
+
}
|
|
8944
|
+
const host = u.hostname.toLowerCase();
|
|
8945
|
+
const blocked = host === "localhost" || host === "169.254.169.254" || // AWS/GCP/Azure instance metadata
|
|
8946
|
+
host === "metadata.google.internal" || /^127\./.test(host) || /^10\./.test(host) || /^192\.168\./.test(host) || /^169\.254\./.test(host) || // link-local
|
|
8947
|
+
/^172\.(1[6-9]|2\d|3[01])\./.test(host) || // 172.16.0.0/12
|
|
8948
|
+
host.endsWith(".internal") || host.endsWith(".local");
|
|
8949
|
+
if (blocked) {
|
|
8950
|
+
throw new Error(`remoteMcp.url for '${definitionId}' resolves to a disallowed (internal/link-local/metadata) host: ${host}`);
|
|
8951
|
+
}
|
|
8952
|
+
}
|
|
8953
|
+
function renderRemoteMcpSpec(definitionId, spec) {
|
|
8954
|
+
assertSafeRemoteMcpUrl(spec.url, definitionId);
|
|
8955
|
+
const headers = {};
|
|
8956
|
+
if (spec.auth) {
|
|
8957
|
+
const envVar = credentialEnvVar(definitionId, spec.auth.credential_ref);
|
|
8958
|
+
const value = `\${${envVar}}`;
|
|
8959
|
+
if (spec.auth.scheme === "bearer") {
|
|
8960
|
+
headers["Authorization"] = `Bearer ${value}`;
|
|
8961
|
+
} else {
|
|
8962
|
+
if (!spec.auth.header_name) {
|
|
8963
|
+
throw new Error(`remoteMcp.auth for '${definitionId}' uses scheme 'header' but no header_name`);
|
|
8964
|
+
}
|
|
8965
|
+
headers[spec.auth.header_name] = value;
|
|
8966
|
+
}
|
|
8967
|
+
}
|
|
8968
|
+
Object.assign(headers, spec.headers ?? {});
|
|
8969
|
+
return {
|
|
8970
|
+
type: spec.type ?? "http",
|
|
8971
|
+
url: spec.url,
|
|
8972
|
+
...Object.keys(headers).length > 0 ? { headers } : {}
|
|
8973
|
+
};
|
|
8974
|
+
}
|
|
8975
|
+
function buildRemoteMcpEntry(definitionId, dbSpec) {
|
|
8976
|
+
const spec = dbSpec ?? INTEGRATION_REGISTRY.find((d) => d.id === definitionId)?.remoteMcp;
|
|
8977
|
+
if (spec) {
|
|
8978
|
+
return renderRemoteMcpSpec(definitionId, spec);
|
|
8979
|
+
}
|
|
8980
|
+
const provider = OAUTH_PROVIDERS[definitionId];
|
|
8981
|
+
if (!provider?.mcpUrl)
|
|
8982
|
+
return null;
|
|
8983
|
+
return {
|
|
8984
|
+
type: "http",
|
|
8985
|
+
url: provider.mcpUrl,
|
|
8986
|
+
headers: {
|
|
8987
|
+
Authorization: `Bearer \${${envVarForToken(definitionId)}}`
|
|
8988
|
+
}
|
|
8989
|
+
};
|
|
8990
|
+
}
|
|
8991
|
+
function buildHostBrokeredRemoteMcpEntry(url) {
|
|
8992
|
+
return { type: "http", url };
|
|
8993
|
+
}
|
|
8994
|
+
function extractHeaderVarName(value) {
|
|
8995
|
+
const m = /^\$\{([A-Za-z_][A-Za-z0-9_]*)\}$/.exec(value.trim());
|
|
8996
|
+
return m ? m[1] : null;
|
|
8997
|
+
}
|
|
8998
|
+
function buildLiveHeaderRemoteMcpProxyEntry(definitionId, dbSpec, paths) {
|
|
8999
|
+
const spec = dbSpec ?? INTEGRATION_REGISTRY.find((d) => d.id === definitionId)?.remoteMcp;
|
|
9000
|
+
if (!spec?.liveHeaderRefresh)
|
|
9001
|
+
return null;
|
|
9002
|
+
assertSafeRemoteMcpUrl(spec.url, definitionId);
|
|
9003
|
+
if (!spec.auth || spec.auth.scheme !== "header" || !spec.auth.header_name) {
|
|
9004
|
+
throw new Error(`remoteMcp.liveHeaderRefresh for '${definitionId}' requires a header-scheme 'auth' with a header_name`);
|
|
9005
|
+
}
|
|
9006
|
+
const extraPairs = [];
|
|
9007
|
+
for (const [header, value] of Object.entries(spec.headers ?? {})) {
|
|
9008
|
+
const varName = extractHeaderVarName(value);
|
|
9009
|
+
if (varName)
|
|
9010
|
+
extraPairs.push(`${header}:${varName}`);
|
|
9011
|
+
}
|
|
9012
|
+
return {
|
|
9013
|
+
command: "node",
|
|
9014
|
+
args: [paths.proxyPath],
|
|
9015
|
+
env: {
|
|
9016
|
+
AGT_REMOTE_MCP_URL: spec.url,
|
|
9017
|
+
AGT_REMOTE_MCP_TOKEN_FILE: paths.tokenFile,
|
|
9018
|
+
AGT_REMOTE_MCP_TOKEN_VAR: credentialEnvVar(definitionId, spec.auth.credential_ref),
|
|
9019
|
+
AGT_REMOTE_MCP_AUTH_HEADER: spec.auth.header_name,
|
|
9020
|
+
AGT_REMOTE_MCP_LABEL: definitionId,
|
|
9021
|
+
...extraPairs.length > 0 ? { AGT_REMOTE_MCP_EXTRA_HEADERS: extraPairs.join(",") } : {}
|
|
9022
|
+
}
|
|
9023
|
+
};
|
|
9024
|
+
}
|
|
9025
|
+
function buildOAuthRemoteMcpProxyEntry(definitionId, paths) {
|
|
9026
|
+
const def = INTEGRATION_REGISTRY.find((d) => d.id === definitionId);
|
|
9027
|
+
if (def?.remoteMcp)
|
|
9028
|
+
return null;
|
|
9029
|
+
const provider = OAUTH_PROVIDERS[definitionId];
|
|
9030
|
+
if (!provider?.mcpUrl)
|
|
9031
|
+
return null;
|
|
9032
|
+
return {
|
|
9033
|
+
command: "node",
|
|
9034
|
+
args: [paths.proxyPath],
|
|
9035
|
+
env: {
|
|
9036
|
+
AGT_REMOTE_MCP_URL: provider.mcpUrl,
|
|
9037
|
+
AGT_REMOTE_MCP_TOKEN_FILE: paths.tokenFile,
|
|
9038
|
+
AGT_REMOTE_MCP_TOKEN_VAR: envVarForToken(definitionId),
|
|
9039
|
+
AGT_REMOTE_MCP_LABEL: definitionId,
|
|
9040
|
+
// ENG-6948: cap the agent's exposed surface to the curated allowlist. The
|
|
9041
|
+
// proxy filters tools/list and gates tools/call against this set. Omitted
|
|
9042
|
+
// when the provider has no allowlist, leaving the proxy a pass-through.
|
|
9043
|
+
...provider.toolAllowlist && provider.toolAllowlist.length > 0 ? { AGT_REMOTE_MCP_TOOL_ALLOWLIST: provider.toolAllowlist.join(",") } : {},
|
|
9044
|
+
// CS-1446: toolsets to pre-activate at session start so gated tools are
|
|
9045
|
+
// advertised in the connect-time tools/list the harness freezes. Omitted
|
|
9046
|
+
// when the provider configures none (no pre-enable, the default).
|
|
9047
|
+
...provider.preEnableToolsets && provider.preEnableToolsets.length > 0 ? { AGT_REMOTE_MCP_PREENABLE_TOOLSETS: provider.preEnableToolsets.join(",") } : {}
|
|
9048
|
+
}
|
|
9049
|
+
};
|
|
9050
|
+
}
|
|
9051
|
+
|
|
9052
|
+
// ../../packages/core/dist/provisioning/native-mcp.js
|
|
9053
|
+
function buildNativeMcpEntry(spec, ctx) {
|
|
9054
|
+
const resolvedCommand = resolveTemplate(spec.command, ctx);
|
|
9055
|
+
if (resolvedCommand.omit) {
|
|
9056
|
+
throw new Error("NativeMcpSpec: empty_if_no_env is only valid in env values (not in `command`)");
|
|
9057
|
+
}
|
|
9058
|
+
const command = resolvedCommand.value;
|
|
9059
|
+
const args = spec.args.map((a, i) => {
|
|
9060
|
+
const resolved = resolveTemplate(a, ctx);
|
|
9061
|
+
if (resolved.omit) {
|
|
9062
|
+
throw new Error(`NativeMcpSpec: empty_if_no_env is only valid in env values (not in args[${i}])`);
|
|
9063
|
+
}
|
|
9064
|
+
return resolved.value;
|
|
9065
|
+
});
|
|
9066
|
+
if (spec.env === void 0) {
|
|
9067
|
+
return { command, args };
|
|
9068
|
+
}
|
|
9069
|
+
const env2 = {};
|
|
9070
|
+
for (const [k, raw] of Object.entries(spec.env)) {
|
|
9071
|
+
const { value, omit } = resolveTemplate(raw, ctx);
|
|
9072
|
+
if (omit)
|
|
9073
|
+
continue;
|
|
9074
|
+
env2[k] = value;
|
|
9075
|
+
}
|
|
9076
|
+
return { command, args, env: env2 };
|
|
9077
|
+
}
|
|
9078
|
+
function resolveTemplate(input, ctx) {
|
|
9079
|
+
const TOKEN = /\{\{([^}]+)\}\}/g;
|
|
9080
|
+
const hasEmptyIfNoEnv = /\{\{\s*empty_if_no_env\./.test(input);
|
|
9081
|
+
const isWholeValueEmptyIfNoEnv = /^\{\{\s*empty_if_no_env\.[^}]+\}\}$/.test(input);
|
|
9082
|
+
if (hasEmptyIfNoEnv && !isWholeValueEmptyIfNoEnv) {
|
|
9083
|
+
throw new Error(`NativeMcpSpec: empty_if_no_env must be the sole content of the value, never mixed with literal text or other tokens (value: ${JSON.stringify(input)})`);
|
|
9084
|
+
}
|
|
9085
|
+
let omit = false;
|
|
9086
|
+
const value = input.replace(TOKEN, (whole, expr) => {
|
|
9087
|
+
const trimmed = expr.trim();
|
|
9088
|
+
if (trimmed === "agent_id")
|
|
9089
|
+
return ctx.agentId;
|
|
9090
|
+
if (trimmed === "agent_code_name")
|
|
9091
|
+
return ctx.agentCodeName;
|
|
9092
|
+
if (trimmed === "integration_id")
|
|
9093
|
+
return ctx.integration?.id ?? "";
|
|
9094
|
+
if (trimmed.startsWith("process_env.")) {
|
|
9095
|
+
const name = trimmed.slice("process_env.".length);
|
|
9096
|
+
return process.env[name] ?? "";
|
|
9097
|
+
}
|
|
9098
|
+
if (trimmed.startsWith("empty_if_no_env.")) {
|
|
9099
|
+
const name = trimmed.slice("empty_if_no_env.".length);
|
|
9100
|
+
const v = process.env[name] ?? "";
|
|
9101
|
+
if (v.length === 0) {
|
|
9102
|
+
omit = true;
|
|
9103
|
+
return "";
|
|
9104
|
+
}
|
|
9105
|
+
return v;
|
|
9106
|
+
}
|
|
9107
|
+
return whole;
|
|
9108
|
+
});
|
|
9109
|
+
return { value, omit };
|
|
9110
|
+
}
|
|
9111
|
+
|
|
9112
|
+
// ../../packages/core/dist/provisioning/frameworks/opencode/integrations.js
|
|
9113
|
+
function toOpencodeEnvRefs(value) {
|
|
9114
|
+
return value.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g, (_m, name) => `{env:${name}}`);
|
|
9115
|
+
}
|
|
9116
|
+
function envPrefix(definitionId) {
|
|
9117
|
+
return definitionId.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
9118
|
+
}
|
|
9119
|
+
function remoteMcpCredentialEnvVar(definitionId, credentialRef) {
|
|
9120
|
+
return `${envPrefix(definitionId)}_${credentialRef.replace(/-/g, "_").toUpperCase()}`;
|
|
9121
|
+
}
|
|
9122
|
+
function toOpencodeRemoteEntry(entry) {
|
|
9123
|
+
const headers = entry.headers ? Object.fromEntries(Object.entries(entry.headers).map(([k, v]) => [k, toOpencodeEnvRefs(v)])) : void 0;
|
|
9124
|
+
return {
|
|
9125
|
+
type: "remote",
|
|
9126
|
+
url: entry.url,
|
|
9127
|
+
...headers && Object.keys(headers).length > 0 ? { headers } : {},
|
|
9128
|
+
enabled: true
|
|
9129
|
+
};
|
|
9130
|
+
}
|
|
9131
|
+
function toOpencodeLocalEntry(entry) {
|
|
9132
|
+
const environment = entry.env ? Object.fromEntries(Object.entries(entry.env).map(([k, v]) => [k, toOpencodeEnvRefs(v)])) : void 0;
|
|
9133
|
+
return {
|
|
9134
|
+
type: "local",
|
|
9135
|
+
command: [entry.command, ...entry.args],
|
|
9136
|
+
...environment && Object.keys(environment).length > 0 ? { environment } : {},
|
|
9137
|
+
enabled: true
|
|
9138
|
+
};
|
|
9139
|
+
}
|
|
9140
|
+
function buildOpencodeIntegrationServers(integrations, ctx) {
|
|
9141
|
+
const servers = {};
|
|
9142
|
+
const envUpdates = {};
|
|
9143
|
+
for (const integration of integrations) {
|
|
9144
|
+
const prefix = envPrefix(integration.definition_id);
|
|
9145
|
+
const creds = integration.credentials ?? {};
|
|
9146
|
+
if (integration.auth_type === "oauth2" || integration.auth_type === "github_app") {
|
|
9147
|
+
const token = creds.access_token;
|
|
9148
|
+
if (typeof token === "string" && token)
|
|
9149
|
+
envUpdates[`${prefix}_ACCESS_TOKEN`] = token;
|
|
9150
|
+
} else if (integration.auth_type === "api_key") {
|
|
9151
|
+
const token = creds.api_key;
|
|
9152
|
+
if (typeof token === "string" && token)
|
|
9153
|
+
envUpdates[`${prefix}_API_KEY`] = token;
|
|
9154
|
+
}
|
|
9155
|
+
const remoteSpec = integration.remoteMcp ?? INTEGRATION_REGISTRY.find((d) => d.id === integration.definition_id)?.remoteMcp;
|
|
9156
|
+
if (remoteSpec?.auth) {
|
|
9157
|
+
const ref = remoteSpec.auth.credential_ref;
|
|
9158
|
+
const value = creds[ref];
|
|
9159
|
+
if (typeof value === "string" && value) {
|
|
9160
|
+
envUpdates[remoteMcpCredentialEnvVar(integration.definition_id, ref)] = value;
|
|
9161
|
+
}
|
|
9162
|
+
}
|
|
9163
|
+
if (integration.config) {
|
|
9164
|
+
for (const [key, value] of Object.entries(integration.config)) {
|
|
9165
|
+
if (typeof value === "string" && value) {
|
|
9166
|
+
const upper = key.toUpperCase();
|
|
9167
|
+
const envKey = upper.startsWith(`${prefix}_`) ? upper : `${prefix}_${upper}`;
|
|
9168
|
+
envUpdates[envKey] = value;
|
|
9169
|
+
}
|
|
9170
|
+
}
|
|
9171
|
+
}
|
|
9172
|
+
}
|
|
9173
|
+
for (const integration of integrations) {
|
|
9174
|
+
const defaults = integration.remoteMcp?.envDefaults ?? INTEGRATION_REGISTRY.find((d) => d.id === integration.definition_id)?.remoteMcp?.envDefaults;
|
|
9175
|
+
if (!defaults)
|
|
9176
|
+
continue;
|
|
9177
|
+
for (const [key, value] of Object.entries(defaults)) {
|
|
9178
|
+
if (!(key in envUpdates))
|
|
9179
|
+
envUpdates[key] = value;
|
|
9180
|
+
}
|
|
9181
|
+
}
|
|
9182
|
+
for (const integration of integrations) {
|
|
9183
|
+
const def = INTEGRATION_REGISTRY.find((d) => d.id === integration.definition_id);
|
|
9184
|
+
const remote = buildRemoteMcpEntry(integration.definition_id, integration.remoteMcp ?? null);
|
|
9185
|
+
if (remote) {
|
|
9186
|
+
servers[integration.definition_id] = toOpencodeRemoteEntry(remote);
|
|
9187
|
+
continue;
|
|
9188
|
+
}
|
|
9189
|
+
if (def?.nativeMcp) {
|
|
9190
|
+
const key = def.nativeMcp.key ?? integration.definition_id;
|
|
9191
|
+
servers[key] = toOpencodeLocalEntry(buildNativeMcpEntry(def.nativeMcp, {
|
|
9192
|
+
agentId: ctx.agentId,
|
|
9193
|
+
agentCodeName: ctx.agentCodeName,
|
|
9194
|
+
integration
|
|
9195
|
+
}));
|
|
9196
|
+
}
|
|
9197
|
+
}
|
|
9198
|
+
return { servers, envUpdates };
|
|
9199
|
+
}
|
|
9200
|
+
|
|
8925
9201
|
// ../../packages/core/dist/provisioning/frameworks/opencode/opencode-client.js
|
|
8926
9202
|
var delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
8927
9203
|
var HttpOpencodeClient = class _HttpOpencodeClient {
|
|
@@ -9306,6 +9582,22 @@ function readEnvIntegrations(codeName) {
|
|
|
9306
9582
|
}
|
|
9307
9583
|
return out;
|
|
9308
9584
|
}
|
|
9585
|
+
var INTEGRATION_KEYS_FILE = "integration-mcp-keys.json";
|
|
9586
|
+
function readIntegrationServerKeys(codeName) {
|
|
9587
|
+
const p2 = join(agentDir(codeName), INTEGRATION_KEYS_FILE);
|
|
9588
|
+
if (!existsSync2(p2))
|
|
9589
|
+
return [];
|
|
9590
|
+
try {
|
|
9591
|
+
const parsed = JSON.parse(readFileSync3(p2, "utf8"));
|
|
9592
|
+
return Array.isArray(parsed) ? parsed.filter((k) => typeof k === "string") : [];
|
|
9593
|
+
} catch {
|
|
9594
|
+
return [];
|
|
9595
|
+
}
|
|
9596
|
+
}
|
|
9597
|
+
function writeIntegrationServerKeys(codeName, keys) {
|
|
9598
|
+
mkdirSync(agentDir(codeName), { recursive: true });
|
|
9599
|
+
writeFileSync2(join(agentDir(codeName), INTEGRATION_KEYS_FILE), JSON.stringify([...keys].sort(), null, 2));
|
|
9600
|
+
}
|
|
9309
9601
|
var ENV_SUBSTITUTION = /^\{env:([A-Za-z_][A-Za-z0-9_]*)\}$/;
|
|
9310
9602
|
function readChannelServerEnv(codeName, channelId) {
|
|
9311
9603
|
const mcp = readConfig(codeName)["mcp"];
|
|
@@ -9407,6 +9699,50 @@ var opencodeAdapter = {
|
|
|
9407
9699
|
cfg["mcp"] = mcp;
|
|
9408
9700
|
writeConfig(codeName, cfg);
|
|
9409
9701
|
},
|
|
9702
|
+
/**
|
|
9703
|
+
* ENG-7976: render org/team/agent-scoped integrations into opencode's `mcp`
|
|
9704
|
+
* block. Follow-up to ENG-7959 - the adapter previously implemented no
|
|
9705
|
+
* `writeIntegrations`, so the manager's `/host/agent-integrations` provisioning
|
|
9706
|
+
* path was silently skipped for opencode and every integration MCP server
|
|
9707
|
+
* (remote_mcp catalog + OAuth remotes + data-driven native) was dropped.
|
|
9708
|
+
*
|
|
9709
|
+
* The mapping is pure (`buildOpencodeIntegrationServers`, reusing the same
|
|
9710
|
+
* shared builders as the claude-code adapter). Secrets never enter the
|
|
9711
|
+
* drift-checked config: they are seeded into `.env.integrations` and referenced
|
|
9712
|
+
* as `{env:VAR}`, resolved by the runtime materializer at serve spawn - the same
|
|
9713
|
+
* contract `writeChannelCredentials` uses. Integration servers are merged INTO
|
|
9714
|
+
* the existing `mcp` map (never a wholesale replace) so the generator's
|
|
9715
|
+
* `augmented` entry and any channel servers already on disk survive.
|
|
9716
|
+
*
|
|
9717
|
+
* Stale integration servers (an integration disconnected since the last write)
|
|
9718
|
+
* are pruned: any entry previously written by this method that is not in the
|
|
9719
|
+
* fresh set is removed, while the `augmented` entry, channel servers and managed
|
|
9720
|
+
* toolkit servers are left untouched.
|
|
9721
|
+
*/
|
|
9722
|
+
writeIntegrations(codeName, integrations, agentId) {
|
|
9723
|
+
const { servers, envUpdates } = buildOpencodeIntegrationServers(integrations, {
|
|
9724
|
+
agentId: agentId ?? "",
|
|
9725
|
+
agentCodeName: codeName
|
|
9726
|
+
});
|
|
9727
|
+
upsertEnvIntegrations(codeName, envUpdates);
|
|
9728
|
+
const previous = readIntegrationServerKeys(codeName);
|
|
9729
|
+
if (Object.keys(servers).length === 0 && previous.length === 0 && !existsSync2(configPath(codeName))) {
|
|
9730
|
+
return;
|
|
9731
|
+
}
|
|
9732
|
+
const cfg = readConfig(codeName);
|
|
9733
|
+
const mcp = cfg["mcp"] ?? {};
|
|
9734
|
+
const fresh = new Set(Object.keys(servers));
|
|
9735
|
+
for (const key of previous) {
|
|
9736
|
+
if (!fresh.has(key))
|
|
9737
|
+
delete mcp[key];
|
|
9738
|
+
}
|
|
9739
|
+
for (const [serverId, entry] of Object.entries(servers)) {
|
|
9740
|
+
mcp[serverId] = entry;
|
|
9741
|
+
}
|
|
9742
|
+
cfg["mcp"] = mcp;
|
|
9743
|
+
writeConfig(codeName, cfg);
|
|
9744
|
+
writeIntegrationServerKeys(codeName, Object.keys(servers));
|
|
9745
|
+
},
|
|
9410
9746
|
removeMcpServer(codeName, serverId) {
|
|
9411
9747
|
const cfg = readConfig(codeName);
|
|
9412
9748
|
const mcp = cfg["mcp"];
|
|
@@ -9853,6 +10189,12 @@ async function spawnServe(config, session) {
|
|
|
9853
10189
|
mkdirSync3(join3(homedir3(), ".augmented", codeName), { recursive: true });
|
|
9854
10190
|
const serveEnv = {
|
|
9855
10191
|
...process.env,
|
|
10192
|
+
// ENG-7976: integration + channel credential secrets so the adapter's
|
|
10193
|
+
// `{env:VAR}` refs (remote MCP auth headers, native MCP env, channel tokens)
|
|
10194
|
+
// resolve at materialization. Layered after process.env (so the file supplies
|
|
10195
|
+
// creds absent from the host env) and before the per-agent provider key +
|
|
10196
|
+
// manager runtime env (which win for their own keys).
|
|
10197
|
+
...readAgentIntegrationsEnv(codeName),
|
|
9856
10198
|
...readAgentProviderEnv(codeName),
|
|
9857
10199
|
...stripUndefined(config.serveEnv ?? {}),
|
|
9858
10200
|
OPENCODE_SERVER_PASSWORD: password,
|
|
@@ -9991,6 +10333,42 @@ function readAgentProviderEnv(codeName, dir) {
|
|
|
9991
10333
|
}
|
|
9992
10334
|
return out;
|
|
9993
10335
|
}
|
|
10336
|
+
var INTEGRATIONS_ENV_BLOCKLIST = /* @__PURE__ */ new Set([
|
|
10337
|
+
"PATH",
|
|
10338
|
+
"HOME",
|
|
10339
|
+
"USER",
|
|
10340
|
+
"SHELL",
|
|
10341
|
+
"IFS",
|
|
10342
|
+
"ENV",
|
|
10343
|
+
"BASH_ENV",
|
|
10344
|
+
"NODE_OPTIONS",
|
|
10345
|
+
"LD_PRELOAD",
|
|
10346
|
+
"LD_LIBRARY_PATH",
|
|
10347
|
+
"DYLD_INSERT_LIBRARIES",
|
|
10348
|
+
"DYLD_LIBRARY_PATH"
|
|
10349
|
+
]);
|
|
10350
|
+
function readAgentIntegrationsEnv(codeName, dir) {
|
|
10351
|
+
const file = join3(dir ?? join3(homedir3(), ".augmented", codeName), ".env.integrations");
|
|
10352
|
+
const out = {};
|
|
10353
|
+
try {
|
|
10354
|
+
if (!existsSync4(file)) return out;
|
|
10355
|
+
for (const raw of readFileSync5(file, "utf-8").split("\n")) {
|
|
10356
|
+
const line2 = raw.trim();
|
|
10357
|
+
if (!line2 || line2.startsWith("#")) continue;
|
|
10358
|
+
const eq = line2.indexOf("=");
|
|
10359
|
+
if (eq <= 0) continue;
|
|
10360
|
+
const key = line2.slice(0, eq).trim();
|
|
10361
|
+
if (INTEGRATIONS_ENV_BLOCKLIST.has(key)) continue;
|
|
10362
|
+
let val = line2.slice(eq + 1).trim();
|
|
10363
|
+
if (val.startsWith('"') && val.endsWith('"') || val.startsWith("'") && val.endsWith("'")) {
|
|
10364
|
+
val = val.slice(1, -1);
|
|
10365
|
+
}
|
|
10366
|
+
out[key] = val;
|
|
10367
|
+
}
|
|
10368
|
+
} catch {
|
|
10369
|
+
}
|
|
10370
|
+
return out;
|
|
10371
|
+
}
|
|
9994
10372
|
|
|
9995
10373
|
// src/lib/persistent-session.ts
|
|
9996
10374
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
@@ -11620,6 +11998,11 @@ export {
|
|
|
11620
11998
|
INTEGRATION_REGISTRY,
|
|
11621
11999
|
getIntegration,
|
|
11622
12000
|
OAUTH_PROVIDERS,
|
|
12001
|
+
buildRemoteMcpEntry,
|
|
12002
|
+
buildHostBrokeredRemoteMcpEntry,
|
|
12003
|
+
buildLiveHeaderRemoteMcpProxyEntry,
|
|
12004
|
+
buildOAuthRemoteMcpProxyEntry,
|
|
12005
|
+
buildNativeMcpEntry,
|
|
11623
12006
|
toOpencodeModel,
|
|
11624
12007
|
mergeOpencodeConfigArtifact,
|
|
11625
12008
|
readChannelServerEnv,
|
|
@@ -11753,4 +12136,4 @@ export {
|
|
|
11753
12136
|
stopAllSessionsAndWait,
|
|
11754
12137
|
getProjectDir
|
|
11755
12138
|
};
|
|
11756
|
-
//# sourceMappingURL=chunk-
|
|
12139
|
+
//# sourceMappingURL=chunk-NDF3YMP5.js.map
|