@integrity-labs/agt-cli 0.27.7-test.6 → 0.27.8-test.10
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 +146 -37
- package/dist/bin/agt.js.map +1 -1
- package/dist/{chunk-AACMX6LE.js → chunk-2E5OABKX.js} +241 -61
- package/dist/chunk-2E5OABKX.js.map +1 -0
- package/dist/{chunk-YSBGIXJG.js → chunk-6HFXSNNY.js} +31 -18
- package/dist/chunk-6HFXSNNY.js.map +1 -0
- package/dist/{chunk-GN4XPQWJ.js → chunk-JIETOJQV.js} +37 -28
- package/dist/chunk-JIETOJQV.js.map +1 -0
- package/dist/{claude-pair-runtime-ZBQKBBMT.js → claude-pair-runtime-3UHTNKZ4.js} +2 -2
- package/dist/lib/manager-worker.js +536 -140
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/direct-chat-channel.js +9 -462
- package/dist/mcp/index.js +44 -25
- package/dist/mcp/slack-channel.js +691 -638
- package/dist/mcp/telegram-channel.js +257 -513
- package/dist/{persistent-session-ICYFLUAM.js → persistent-session-HSHIZC2Q.js} +3 -3
- package/dist/{responsiveness-probe-WZNQ2762.js → responsiveness-probe-RYKS5TRP.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-AACMX6LE.js.map +0 -1
- package/dist/chunk-GN4XPQWJ.js.map +0 -1
- package/dist/chunk-YSBGIXJG.js.map +0 -1
- /package/dist/{claude-pair-runtime-ZBQKBBMT.js.map → claude-pair-runtime-3UHTNKZ4.js.map} +0 -0
- /package/dist/{persistent-session-ICYFLUAM.js.map → persistent-session-HSHIZC2Q.js.map} +0 -0
- /package/dist/{responsiveness-probe-WZNQ2762.js.map → responsiveness-probe-RYKS5TRP.js.map} +0 -0
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
parseDeliveryTarget,
|
|
10
10
|
registerFramework,
|
|
11
11
|
wrapScheduledTaskPrompt
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-6HFXSNNY.js";
|
|
13
13
|
|
|
14
14
|
// ../../packages/core/dist/integrations/registry.js
|
|
15
15
|
var INTEGRATION_REGISTRY = [
|
|
@@ -174,7 +174,15 @@ var INTEGRATION_REGISTRY = [
|
|
|
174
174
|
{ id: "qmd:search", name: "Search Memory", description: "Semantic + keyword search over indexed memory files", access: "read" },
|
|
175
175
|
{ id: "qmd:get", name: "Get Memory", description: "Read memory files by path and line range", access: "read" }
|
|
176
176
|
],
|
|
177
|
-
beta: true
|
|
177
|
+
beta: true,
|
|
178
|
+
// ENG-5815: migrated from buildMcpJson's hardcoded if-block. qmd is
|
|
179
|
+
// the simplest of the four pre-data-driven entries — no env, no
|
|
180
|
+
// conditional logic, just `qmd mcp`. The byte-identical render is
|
|
181
|
+
// pinned by claudecode-qmd-data-driven.test.ts.
|
|
182
|
+
nativeMcp: {
|
|
183
|
+
command: "qmd",
|
|
184
|
+
args: ["mcp"]
|
|
185
|
+
}
|
|
178
186
|
},
|
|
179
187
|
{
|
|
180
188
|
id: "v0",
|
|
@@ -310,6 +318,35 @@ var INTEGRATION_REGISTRY = [
|
|
|
310
318
|
},
|
|
311
319
|
docs_url: "https://www.coderabbit.ai/cli"
|
|
312
320
|
},
|
|
321
|
+
{
|
|
322
|
+
id: "aws",
|
|
323
|
+
name: "AWS",
|
|
324
|
+
category: "infrastructure",
|
|
325
|
+
description: "Amazon Web Services \u2014 query AWS APIs (EC2, S3, IAM, Lambda, etc.) via AWS Labs' official AWS API MCP server",
|
|
326
|
+
supported_auth_types: ["api_key", "managed", "none"],
|
|
327
|
+
capabilities: [
|
|
328
|
+
{ id: "aws:read", name: "Read AWS Resources", description: "List and describe AWS resources across services (EC2, S3, IAM, Lambda, \u2026)", access: "read" },
|
|
329
|
+
{ id: "aws:write", name: "Write AWS Resources", description: "Create and update AWS resources. Pair with an aws-no-destructive-ops guardrail.", access: "write" }
|
|
330
|
+
],
|
|
331
|
+
docs_url: "https://github.com/awslabs/mcp/tree/main/src/aws-api-mcp-server",
|
|
332
|
+
beta: true,
|
|
333
|
+
// ENG-5815: first integration shipped purely via the data-driven
|
|
334
|
+
// path — buildMcpJson never grew an `aws` if-block. The AWS Labs
|
|
335
|
+
// AWS API MCP server runs through uvx (Python tooling), which the
|
|
336
|
+
// host bootstrap installs alongside python3. Credentials are
|
|
337
|
+
// resolved via the standard AWS_* env / shared credentials file
|
|
338
|
+
// chain on the host; the spec doesn't override them.
|
|
339
|
+
nativeMcp: {
|
|
340
|
+
command: "uvx",
|
|
341
|
+
args: ["awslabs.aws-api-mcp-server@latest"],
|
|
342
|
+
env: {
|
|
343
|
+
AWS_REGION: "{{empty_if_no_env.AWS_REGION}}",
|
|
344
|
+
AWS_PROFILE: "{{empty_if_no_env.AWS_PROFILE}}",
|
|
345
|
+
PATH: "{{process_env.PATH}}",
|
|
346
|
+
HOME: "{{process_env.HOME}}"
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
},
|
|
313
350
|
{
|
|
314
351
|
id: "custom",
|
|
315
352
|
name: "Custom Integration",
|
|
@@ -2644,42 +2681,6 @@ If your charter doesn't authorise team-scope skill writes
|
|
|
2644
2681
|
refused server-side \u2014 surface that error to the user rather than
|
|
2645
2682
|
falling back to a local-disk write.
|
|
2646
2683
|
|
|
2647
|
-
`;
|
|
2648
|
-
}
|
|
2649
|
-
function buildProgressHeartbeatSection(resolvedChannels) {
|
|
2650
|
-
const hasSlack = !!resolvedChannels?.includes("slack");
|
|
2651
|
-
const hasDirectChat = !!resolvedChannels?.includes("direct-chat");
|
|
2652
|
-
if (!hasSlack && !hasDirectChat)
|
|
2653
|
-
return "";
|
|
2654
|
-
const bullets = [];
|
|
2655
|
-
if (hasSlack) {
|
|
2656
|
-
bullets.push("- **Slack threads:** `slack_progress_start` (channel + thread_ts from the inbound `<channel>` tag, label = short task name) \u2192 `slack_progress_update` between steps (pass `step_label`, optional `step_current`/`step_total`) \u2192 `slack_progress_complete` (summary) or `slack_progress_fail` (one-sentence reason).");
|
|
2657
|
-
}
|
|
2658
|
-
if (hasDirectChat) {
|
|
2659
|
-
bullets.push("- **Direct Chat sessions:** `direct_chat_progress_start` (session_id from the inbound tag, label) \u2192 `direct_chat_progress_update` \u2192 `direct_chat_progress_complete` / `_fail`.");
|
|
2660
|
-
}
|
|
2661
|
-
return `
|
|
2662
|
-
## Progress heartbeats during multi-step work
|
|
2663
|
-
|
|
2664
|
-
When a task involves **\u22653 tool calls or is likely to take >5 seconds**
|
|
2665
|
-
of tool work, open an in-place progress anchor instead of streaming
|
|
2666
|
-
"working on\u2026" / "still working\u2026" / "done" messages. The operator sees
|
|
2667
|
-
one message that ticks forward as you advance, not a thread flooded
|
|
2668
|
-
with status pings.
|
|
2669
|
-
|
|
2670
|
-
${bullets.join("\n")}
|
|
2671
|
-
|
|
2672
|
-
The state machine debounces updates to roughly one API call per second
|
|
2673
|
-
per channel, so it's safe to call \`_update\` after every step rather
|
|
2674
|
-
than batching. Always end with \`_complete\` or \`_fail\` \u2014 leaving an
|
|
2675
|
-
anchor in the "working" state means a future stale-state sweep flips it
|
|
2676
|
-
to \u26A0\uFE0F "agent unresponsive" once the heartbeat goes cold.
|
|
2677
|
-
|
|
2678
|
-
**Skip the heartbeat for one-shot replies.** A single \`slack.reply\` /
|
|
2679
|
-
\`direct_chat.reply\` is still the right pattern when there's no
|
|
2680
|
-
multi-step work to surface. Heartbeats are for the case where you'd
|
|
2681
|
-
otherwise emit several intermediate messages.
|
|
2682
|
-
|
|
2683
2684
|
`;
|
|
2684
2685
|
}
|
|
2685
2686
|
function buildPersonalitySection(seed) {
|
|
@@ -2900,6 +2901,37 @@ function formatConfigLines(config) {
|
|
|
2900
2901
|
return ` - ${k}: ${rendered}`;
|
|
2901
2902
|
});
|
|
2902
2903
|
}
|
|
2904
|
+
var EMAIL_DOMAIN_RESTRICT_DEF = "email.domain_restrict";
|
|
2905
|
+
function stringList(value) {
|
|
2906
|
+
return Array.isArray(value) ? value.filter((d) => typeof d === "string") : [];
|
|
2907
|
+
}
|
|
2908
|
+
function formatEmailDomainConfigLines(config) {
|
|
2909
|
+
const mode = typeof config.mode === "string" ? config.mode : void 0;
|
|
2910
|
+
const lines = [];
|
|
2911
|
+
if (mode)
|
|
2912
|
+
lines.push(` - mode: ${mode}`);
|
|
2913
|
+
if (mode === "allowlist") {
|
|
2914
|
+
const allowed = stringList(config.allowed_domains);
|
|
2915
|
+
lines.push(` - allowed_domains: ${allowed.length ? allowed.join(", ") : "(none \u2014 no external email permitted)"}`);
|
|
2916
|
+
} else if (mode === "blocklist") {
|
|
2917
|
+
const blocked = stringList(config.blocked_domains);
|
|
2918
|
+
lines.push(` - blocked_domains: ${blocked.length ? blocked.join(", ") : "(none)"}`);
|
|
2919
|
+
} else if (mode === "internal_only") {
|
|
2920
|
+
lines.push(` - only your organization's own email domain is permitted`);
|
|
2921
|
+
}
|
|
2922
|
+
lines.push(` *Advisory: honor this restriction \u2014 it is guidance in your instructions, not a hard block at send time.*`);
|
|
2923
|
+
return lines;
|
|
2924
|
+
}
|
|
2925
|
+
var CALENDAR_CONFIDENTIALITY_DEF = "calendar.confidentiality";
|
|
2926
|
+
function formatCalendarConfidentialityLines(config) {
|
|
2927
|
+
const stage = typeof config.stage === "string" ? config.stage : "shadow";
|
|
2928
|
+
const lines = [` - stage: ${stage}`];
|
|
2929
|
+
lines.push(` *Cross-turn re-query: when answering a different person about your principal's calendar, ALWAYS re-query the calendar tool \u2014 never reuse meeting details remembered from an earlier turn that involved a different recipient. The tool's response is filtered per-recipient at the API layer; relying on memory bypasses the filter.*`);
|
|
2930
|
+
if (stage !== "enforce") {
|
|
2931
|
+
lines.push(` *Currently observe-only \u2014 the API records redaction decisions to guardrail_audit_log but returns calendar responses unchanged. Treat the policy as authoritative anyway; the runtime flip is operator-side.*`);
|
|
2932
|
+
}
|
|
2933
|
+
return lines;
|
|
2934
|
+
}
|
|
2903
2935
|
function renderGuardrailBullet(g) {
|
|
2904
2936
|
const lines = [];
|
|
2905
2937
|
const header = `- **${g.displayName}** (${g.category}, from ${g.source})`;
|
|
@@ -2907,16 +2939,26 @@ function renderGuardrailBullet(g) {
|
|
|
2907
2939
|
if (g.description?.trim()) {
|
|
2908
2940
|
lines.push(` ${g.description.trim()}`);
|
|
2909
2941
|
}
|
|
2910
|
-
lines.push(...formatConfigLines(g.config));
|
|
2942
|
+
lines.push(...g.definitionId === EMAIL_DOMAIN_RESTRICT_DEF ? formatEmailDomainConfigLines(g.config) : g.definitionId === CALENDAR_CONFIDENTIALITY_DEF ? formatCalendarConfidentialityLines(g.config) : formatConfigLines(g.config));
|
|
2911
2943
|
if (g.overrideApplied && g.overrideReason?.trim()) {
|
|
2912
2944
|
lines.push(` *Override applied: ${g.overrideReason.trim()}*`);
|
|
2913
2945
|
}
|
|
2914
2946
|
return lines.join("\n");
|
|
2915
2947
|
}
|
|
2948
|
+
function effectiveCalendarEnforcement(g) {
|
|
2949
|
+
if (g.definitionId !== CALENDAR_CONFIDENTIALITY_DEF)
|
|
2950
|
+
return g.enforcement;
|
|
2951
|
+
const stage = typeof g.config?.["stage"] === "string" ? g.config["stage"] : "shadow";
|
|
2952
|
+
if (stage === "enforce")
|
|
2953
|
+
return "enforce";
|
|
2954
|
+
if (stage === "warn" && g.enforcement !== "enforce")
|
|
2955
|
+
return "warn";
|
|
2956
|
+
return g.enforcement;
|
|
2957
|
+
}
|
|
2916
2958
|
function buildGuardrailsSection(guardrails) {
|
|
2917
2959
|
if (!guardrails || guardrails.length === 0)
|
|
2918
2960
|
return "";
|
|
2919
|
-
const active = guardrails.filter((g) => g.enforcement !== "disabled");
|
|
2961
|
+
const active = guardrails.map((g) => ({ ...g, enforcement: effectiveCalendarEnforcement(g) })).filter((g) => g.enforcement !== "disabled");
|
|
2920
2962
|
if (active.length === 0)
|
|
2921
2963
|
return "";
|
|
2922
2964
|
const enforce = active.filter((g) => g.enforcement === "enforce");
|
|
@@ -3019,7 +3061,7 @@ inline replies \u2014 they do NOT replace this dispatch decision.
|
|
|
3019
3061
|
If the work turns out to be unexpectedly slow after you started inline,
|
|
3020
3062
|
finish the current sub-step, then dispatch the rest. Don't apologise for
|
|
3021
3063
|
mid-task switching \u2014 operators care about responsiveness, not consistency.
|
|
3022
|
-
|
|
3064
|
+
|
|
3023
3065
|
${activeTasksSection}${personalitySection}## Identity
|
|
3024
3066
|
|
|
3025
3067
|
- Code Name: ${frontmatter.code_name}
|
|
@@ -3028,6 +3070,21 @@ ${activeTasksSection}${personalitySection}## Identity
|
|
|
3028
3070
|
- Risk Tier: ${frontmatter.risk_tier}
|
|
3029
3071
|
- Timezone: ${timezone?.trim() || "UTC"}
|
|
3030
3072
|
- Channels: ${channelList}
|
|
3073
|
+
|
|
3074
|
+
> **What the Channels list above means** (ENG-5851): \`Channels:\`
|
|
3075
|
+
> enumerates the messaging **protocols** you may use \u2014 \`slack\`,
|
|
3076
|
+
> \`telegram\`, \`msteams\`, etc. It is **not** a list of specific
|
|
3077
|
+
> Slack channels / Telegram chats / Teams threads you're approved to
|
|
3078
|
+
> post in. There is no per-recipient "approved channels" allowlist
|
|
3079
|
+
> anywhere in this platform; you decide where to post based on the
|
|
3080
|
+
> task and the conversation context. If you call a send tool and the
|
|
3081
|
+
> target channel rejects it (e.g. Slack returns \`not_in_channel\` /
|
|
3082
|
+
> \`channel_not_found\`, or Teams returns \`team_not_allowed\`), surface
|
|
3083
|
+
> the error to the user with the recovery action \u2014 typically asking
|
|
3084
|
+
> them to run \`/invite @<your bot handle>\` in the channel so you can
|
|
3085
|
+
> post there next time. Do **not** refuse a posting request on the
|
|
3086
|
+
> grounds that the channel "isn't on the allowlist" \u2014 that conflation
|
|
3087
|
+
> is the bug ENG-5851 was filed to fix.
|
|
3031
3088
|
${resolvedChannels?.includes("slack") ? `
|
|
3032
3089
|
## Slack
|
|
3033
3090
|
|
|
@@ -3494,6 +3551,66 @@ function buildRemoteMcpEntry(definitionId) {
|
|
|
3494
3551
|
};
|
|
3495
3552
|
}
|
|
3496
3553
|
|
|
3554
|
+
// ../../packages/core/dist/provisioning/native-mcp.js
|
|
3555
|
+
function buildNativeMcpEntry(spec, ctx) {
|
|
3556
|
+
const resolvedCommand = resolveTemplate(spec.command, ctx);
|
|
3557
|
+
if (resolvedCommand.omit) {
|
|
3558
|
+
throw new Error("NativeMcpSpec: empty_if_no_env is only valid in env values (not in `command`)");
|
|
3559
|
+
}
|
|
3560
|
+
const command = resolvedCommand.value;
|
|
3561
|
+
const args = spec.args.map((a, i) => {
|
|
3562
|
+
const resolved = resolveTemplate(a, ctx);
|
|
3563
|
+
if (resolved.omit) {
|
|
3564
|
+
throw new Error(`NativeMcpSpec: empty_if_no_env is only valid in env values (not in args[${i}])`);
|
|
3565
|
+
}
|
|
3566
|
+
return resolved.value;
|
|
3567
|
+
});
|
|
3568
|
+
if (spec.env === void 0) {
|
|
3569
|
+
return { command, args };
|
|
3570
|
+
}
|
|
3571
|
+
const env = {};
|
|
3572
|
+
for (const [k, raw] of Object.entries(spec.env)) {
|
|
3573
|
+
const { value, omit } = resolveTemplate(raw, ctx);
|
|
3574
|
+
if (omit)
|
|
3575
|
+
continue;
|
|
3576
|
+
env[k] = value;
|
|
3577
|
+
}
|
|
3578
|
+
return { command, args, env };
|
|
3579
|
+
}
|
|
3580
|
+
function resolveTemplate(input, ctx) {
|
|
3581
|
+
const TOKEN = /\{\{([^}]+)\}\}/g;
|
|
3582
|
+
const hasEmptyIfNoEnv = /\{\{\s*empty_if_no_env\./.test(input);
|
|
3583
|
+
const isWholeValueEmptyIfNoEnv = /^\{\{\s*empty_if_no_env\.[^}]+\}\}$/.test(input);
|
|
3584
|
+
if (hasEmptyIfNoEnv && !isWholeValueEmptyIfNoEnv) {
|
|
3585
|
+
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)})`);
|
|
3586
|
+
}
|
|
3587
|
+
let omit = false;
|
|
3588
|
+
const value = input.replace(TOKEN, (whole, expr) => {
|
|
3589
|
+
const trimmed = expr.trim();
|
|
3590
|
+
if (trimmed === "agent_id")
|
|
3591
|
+
return ctx.agentId;
|
|
3592
|
+
if (trimmed === "agent_code_name")
|
|
3593
|
+
return ctx.agentCodeName;
|
|
3594
|
+
if (trimmed === "integration_id")
|
|
3595
|
+
return ctx.integration?.id ?? "";
|
|
3596
|
+
if (trimmed.startsWith("process_env.")) {
|
|
3597
|
+
const name = trimmed.slice("process_env.".length);
|
|
3598
|
+
return process.env[name] ?? "";
|
|
3599
|
+
}
|
|
3600
|
+
if (trimmed.startsWith("empty_if_no_env.")) {
|
|
3601
|
+
const name = trimmed.slice("empty_if_no_env.".length);
|
|
3602
|
+
const v = process.env[name] ?? "";
|
|
3603
|
+
if (v.length === 0) {
|
|
3604
|
+
omit = true;
|
|
3605
|
+
return "";
|
|
3606
|
+
}
|
|
3607
|
+
return v;
|
|
3608
|
+
}
|
|
3609
|
+
return whole;
|
|
3610
|
+
});
|
|
3611
|
+
return { value, omit };
|
|
3612
|
+
}
|
|
3613
|
+
|
|
3497
3614
|
// ../../packages/core/dist/provisioning/frameworks/claudecode/index.js
|
|
3498
3615
|
var VALID_CODE_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
3499
3616
|
var SECRET_FILE_MODE = 384;
|
|
@@ -4353,7 +4470,7 @@ The parent passes you in the task description:
|
|
|
4353
4470
|
Your job:
|
|
4354
4471
|
|
|
4355
4472
|
1. Do the work the message asks for (Xero pull, research, multi-step skill, etc.). Use whichever tools you need.
|
|
4356
|
-
2. Post the reply yourself via the matching channel tool \u2014 slack.reply for Slack, telegram.reply for Telegram, teams.reply for Microsoft Teams,
|
|
4473
|
+
2. Post the reply yourself via the matching channel tool \u2014 slack.reply for Slack, telegram.reply for Telegram, teams.reply for Microsoft Teams, direct_chat.reply for Direct Chat. Use the metadata the parent gave you to address the right thread/conversation.
|
|
4357
4474
|
3. End. Do not do additional follow-up work; if more is needed, the user will send another message.
|
|
4358
4475
|
|
|
4359
4476
|
Do NOT post intermediate progress updates unless the work spans 5+ minutes \u2014 keep noise low. The parent already sent a single-line acknowledgement before dispatching you.
|
|
@@ -4405,12 +4522,16 @@ function buildMcpJson(input) {
|
|
|
4405
4522
|
HOME: process.env["HOME"] ?? ""
|
|
4406
4523
|
}
|
|
4407
4524
|
};
|
|
4408
|
-
const
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4525
|
+
for (const integration of input.integrations ?? []) {
|
|
4526
|
+
const def = INTEGRATION_REGISTRY.find((d) => d.id === integration.definition_id);
|
|
4527
|
+
if (!def?.nativeMcp)
|
|
4528
|
+
continue;
|
|
4529
|
+
const key = def.nativeMcp.key ?? integration.definition_id;
|
|
4530
|
+
mcpServers[key] = buildNativeMcpEntry(def.nativeMcp, {
|
|
4531
|
+
agentId: input.agent.agent_id,
|
|
4532
|
+
agentCodeName: input.agent.code_name,
|
|
4533
|
+
integration
|
|
4534
|
+
});
|
|
4414
4535
|
}
|
|
4415
4536
|
const xeroIntegration = input.integrations?.find((i) => i.definition_id === "xero");
|
|
4416
4537
|
if (xeroIntegration) {
|
|
@@ -4750,6 +4871,12 @@ ${sections}`
|
|
|
4750
4871
|
},
|
|
4751
4872
|
writeChannelCredentials(codeName, channelId, config, options) {
|
|
4752
4873
|
const tzEnv = options?.agentTimezone && options.agentTimezone.trim() !== "" ? { TZ: options.agentTimezone.trim() } : {};
|
|
4874
|
+
const senderPolicyMode = options?.senderPolicy?.mode;
|
|
4875
|
+
const senderPolicyTeamId = options?.senderPolicy?.mode === "team_agents_only" || options?.senderPolicy?.mode === "manager_only" ? options.senderPolicy.team_id : void 0;
|
|
4876
|
+
const slackPrincipalId = options?.senderPolicy?.mode === "manager_only" ? options.senderPolicy.principal?.slack_user_id : void 0;
|
|
4877
|
+
const teamsPrincipalId = options?.senderPolicy?.mode === "manager_only" ? options.senderPolicy.principal?.teams_aad_object_id : void 0;
|
|
4878
|
+
const senderPolicyInternalOnly = options?.senderPolicy?.internal_only === true;
|
|
4879
|
+
const senderPolicyEnv = senderPolicyTeamId ? { AGT_TEAM_ID: senderPolicyTeamId } : {};
|
|
4753
4880
|
const agentDir = getAgentDir(codeName);
|
|
4754
4881
|
mkdirSync4(agentDir, { recursive: true });
|
|
4755
4882
|
const isPersistent = options?.sessionMode === "persistent";
|
|
@@ -4901,7 +5028,30 @@ ${sections}`
|
|
|
4901
5028
|
// (ENG-4936) honours PEER_DISABLED with identical
|
|
4902
5029
|
// semantics. Only emit when non-default so the env block
|
|
4903
5030
|
// stays clean for the common case.
|
|
4904
|
-
...peerDisabledMode !== "off" ? { PEER_DISABLED: peerDisabledMode } : {}
|
|
5031
|
+
...peerDisabledMode !== "off" ? { PEER_DISABLED: peerDisabledMode } : {},
|
|
5032
|
+
// ENG-5841: SLACK_SENDER_POLICY drives slack-inbound-filter.ts.
|
|
5033
|
+
// Only emitted when the effective mode is restrictive (default
|
|
5034
|
+
// 'all' is the absence of the env var — same convention the
|
|
5035
|
+
// MCP filter uses on its own end).
|
|
5036
|
+
...senderPolicyMode ? { SLACK_SENDER_POLICY: senderPolicyMode } : {},
|
|
5037
|
+
...senderPolicyEnv,
|
|
5038
|
+
// AGT_TEAM_ID when team_agents_only
|
|
5039
|
+
// ENG-5842: principal ID for manager_only — Slack user_id from
|
|
5040
|
+
// people.contact_preferences.slack_user_id. Omitted when the
|
|
5041
|
+
// principal has no Slack ID; MCP filter fails closed on the
|
|
5042
|
+
// missing env var by dropping all human inbound.
|
|
5043
|
+
...slackPrincipalId ? { SLACK_SENDER_POLICY_PRINCIPAL_ID: slackPrincipalId } : {},
|
|
5044
|
+
// ENG-5843: org-boundary gate. SLACK_INTERNAL_ONLY signals the
|
|
5045
|
+
// filter to check sender's workspace against SLACK_HOME_TEAM_ID
|
|
5046
|
+
// (sourced from the bot install's team_id, populated by
|
|
5047
|
+
// auth.test at install / first-run). Omitted unless explicitly
|
|
5048
|
+
// enabled — the consumer's env-absent default is "no gate".
|
|
5049
|
+
// When INTERNAL_ONLY is true but home team_id can't be
|
|
5050
|
+
// resolved (config['team_id'] not set on the install), the
|
|
5051
|
+
// MCP boot guard fails closed at startup rather than admitting
|
|
5052
|
+
// every sender as "internal".
|
|
5053
|
+
...senderPolicyInternalOnly ? { SLACK_INTERNAL_ONLY: "true" } : {},
|
|
5054
|
+
...senderPolicyInternalOnly && typeof config["team_id"] === "string" && config["team_id"].length > 0 ? { SLACK_HOME_TEAM_ID: config["team_id"] } : {}
|
|
4905
5055
|
}
|
|
4906
5056
|
};
|
|
4907
5057
|
const provisionMcpPath = join4(agentDir, "provision", ".mcp.json");
|
|
@@ -5077,7 +5227,24 @@ ${sections}`
|
|
|
5077
5227
|
...peerTeamIds.length > 0 ? { MSTEAMS_PEER_TEAM_IDS: peerTeamIds.join(",") } : {},
|
|
5078
5228
|
...knownPeerBotIds.length > 0 ? { MSTEAMS_KNOWN_PEER_BOT_IDS: knownPeerBotIds.join(",") } : {},
|
|
5079
5229
|
...msteamsAgtAuthEnv,
|
|
5080
|
-
...tzEnv
|
|
5230
|
+
...tzEnv,
|
|
5231
|
+
// ENG-5841: MSTEAMS_SENDER_POLICY drives teams-inbound-filter.ts.
|
|
5232
|
+
// Mirrors the Slack branch above — only emitted when restrictive.
|
|
5233
|
+
...senderPolicyMode ? { MSTEAMS_SENDER_POLICY: senderPolicyMode } : {},
|
|
5234
|
+
...senderPolicyEnv,
|
|
5235
|
+
// AGT_TEAM_ID when team_agents_only
|
|
5236
|
+
// ENG-5842: principal ID for manager_only — Teams AAD object id from
|
|
5237
|
+
// people.contact_preferences.teams_aad_object_id. Same fail-closed
|
|
5238
|
+
// contract as the Slack branch above.
|
|
5239
|
+
...teamsPrincipalId ? { MSTEAMS_SENDER_POLICY_PRINCIPAL_ID: teamsPrincipalId } : {},
|
|
5240
|
+
// ENG-5843: org-boundary gate. MSTEAMS_INTERNAL_ONLY + MSTEAMS_HOME_TENANT_ID
|
|
5241
|
+
// mirror the Slack pair. Source is the same tenantId the existing
|
|
5242
|
+
// MSTEAMS_TENANT_ID env var already carries — defaulting to "common"
|
|
5243
|
+
// would be wrong here (it'd admit any tenant), so we skip the
|
|
5244
|
+
// SLACK_HOME_TEAM_ID-equivalent emission when the install hasn't
|
|
5245
|
+
// pinned a real tenant. MCP boot guard fails closed.
|
|
5246
|
+
...senderPolicyInternalOnly ? { MSTEAMS_INTERNAL_ONLY: "true" } : {},
|
|
5247
|
+
...senderPolicyInternalOnly && tenantId !== "common" ? { MSTEAMS_HOME_TENANT_ID: tenantId } : {}
|
|
5081
5248
|
};
|
|
5082
5249
|
if (isPersistent && existsSync5(localTeamsChannel)) {
|
|
5083
5250
|
mcpServers["msteams"] = {
|
|
@@ -5194,9 +5361,16 @@ ${sections}`
|
|
|
5194
5361
|
chmodSync4(envPath, SECRET_FILE_MODE);
|
|
5195
5362
|
}
|
|
5196
5363
|
writeXurlStoreForIntegrations(decryptedIntegrations);
|
|
5197
|
-
const
|
|
5198
|
-
|
|
5199
|
-
|
|
5364
|
+
for (const integration of decryptedIntegrations) {
|
|
5365
|
+
const def = INTEGRATION_REGISTRY.find((d) => d.id === integration.definition_id);
|
|
5366
|
+
if (!def?.nativeMcp)
|
|
5367
|
+
continue;
|
|
5368
|
+
const key = def.nativeMcp.key ?? integration.definition_id;
|
|
5369
|
+
this.writeMcpServer(codeName, key, buildNativeMcpEntry(def.nativeMcp, {
|
|
5370
|
+
agentId: agentId ?? "",
|
|
5371
|
+
agentCodeName: codeName,
|
|
5372
|
+
integration
|
|
5373
|
+
}));
|
|
5200
5374
|
}
|
|
5201
5375
|
const xeroIntegration = integrations.find((i) => i.definition_id === "xero");
|
|
5202
5376
|
if (xeroIntegration) {
|
|
@@ -5255,16 +5429,15 @@ ${sections}`
|
|
|
5255
5429
|
}
|
|
5256
5430
|
}
|
|
5257
5431
|
if (this.removeMcpServer) {
|
|
5432
|
+
const nativeMcpKeys = INTEGRATION_REGISTRY.filter((d) => d.nativeMcp !== void 0).map((d) => d.nativeMcp.key ?? d.id);
|
|
5258
5433
|
const integrationDerivedKeys = /* @__PURE__ */ new Set([
|
|
5259
|
-
"qmd",
|
|
5260
5434
|
"xero",
|
|
5261
5435
|
"postiz",
|
|
5262
5436
|
"cloud-broker",
|
|
5437
|
+
...nativeMcpKeys,
|
|
5263
5438
|
...Object.entries(OAUTH_PROVIDERS).filter(([, provider]) => Boolean(provider.mcpUrl)).map(([id]) => id)
|
|
5264
5439
|
]);
|
|
5265
5440
|
const expectedKeys = /* @__PURE__ */ new Set();
|
|
5266
|
-
if (hasQmd)
|
|
5267
|
-
expectedKeys.add("qmd");
|
|
5268
5441
|
if (xeroIntegration)
|
|
5269
5442
|
expectedKeys.add("xero");
|
|
5270
5443
|
if (postizIntegration)
|
|
@@ -5272,6 +5445,10 @@ ${sections}`
|
|
|
5272
5445
|
if (hasCloudBroker)
|
|
5273
5446
|
expectedKeys.add("cloud-broker");
|
|
5274
5447
|
for (const integration of integrations) {
|
|
5448
|
+
const def = INTEGRATION_REGISTRY.find((d) => d.id === integration.definition_id);
|
|
5449
|
+
if (def?.nativeMcp) {
|
|
5450
|
+
expectedKeys.add(def.nativeMcp.key ?? integration.definition_id);
|
|
5451
|
+
}
|
|
5275
5452
|
if (buildRemoteMcpEntry(integration.definition_id)) {
|
|
5276
5453
|
expectedKeys.add(integration.definition_id);
|
|
5277
5454
|
}
|
|
@@ -5933,12 +6110,15 @@ function setActiveTeam(slug) {
|
|
|
5933
6110
|
config.active_team = slug;
|
|
5934
6111
|
saveConfig(config);
|
|
5935
6112
|
}
|
|
5936
|
-
var
|
|
6113
|
+
var PROD_AGT_HOST = "https://api.augmented.team";
|
|
6114
|
+
var AGT_HOST_UNSET_MESSAGE = "AGT_HOST is not set. Set it to the API URL for your stage before running this command:\n Production: export AGT_HOST=https://api.augmented.team\n Non-prod stage: export AGT_HOST=https://<stage>.api.staging.augmented.team\n Local development: export AGT_HOST=http://api.agt.localhost:1355\n\nFor first-time host setup, pass --api-host <url> to `agt setup` instead \u2014 the setup command does NOT silently default to prod (ENG-5831).";
|
|
5937
6115
|
function getHost() {
|
|
5938
6116
|
const envHost = process.env["AGT_HOST"]?.trim();
|
|
5939
|
-
|
|
6117
|
+
if (!envHost) {
|
|
6118
|
+
throw new Error(AGT_HOST_UNSET_MESSAGE);
|
|
6119
|
+
}
|
|
6120
|
+
return envHost;
|
|
5940
6121
|
}
|
|
5941
|
-
var AGT_HOST = getHost();
|
|
5942
6122
|
function requireHost() {
|
|
5943
6123
|
return getHost();
|
|
5944
6124
|
}
|
|
@@ -6761,7 +6941,7 @@ export {
|
|
|
6761
6941
|
getApiKey,
|
|
6762
6942
|
getActiveTeam,
|
|
6763
6943
|
setActiveTeam,
|
|
6764
|
-
|
|
6944
|
+
PROD_AGT_HOST,
|
|
6765
6945
|
getHost,
|
|
6766
6946
|
requireHost,
|
|
6767
6947
|
exchangeApiKey,
|
|
@@ -6785,4 +6965,4 @@ export {
|
|
|
6785
6965
|
managerInstallSystemUnitCommand,
|
|
6786
6966
|
managerUninstallSystemUnitCommand
|
|
6787
6967
|
};
|
|
6788
|
-
//# sourceMappingURL=chunk-
|
|
6968
|
+
//# sourceMappingURL=chunk-2E5OABKX.js.map
|