@integrity-labs/agt-cli 0.28.551 → 0.28.553
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 +3 -3
- package/dist/{chunk-KODUPAXH.js → chunk-YCN2PS63.js} +2 -2
- package/dist/lib/manager-worker.js +12 -2
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/index.js +17 -3
- package/dist/mcp/slack-channel.js +101 -1
- package/package.json +1 -1
- /package/dist/{chunk-KODUPAXH.js.map → chunk-YCN2PS63.js.map} +0 -0
package/dist/mcp/index.js
CHANGED
|
@@ -22456,7 +22456,7 @@ server.tool(
|
|
|
22456
22456
|
);
|
|
22457
22457
|
server.tool(
|
|
22458
22458
|
"kanban_assign",
|
|
22459
|
-
|
|
22459
|
+
'Delegate a task to ANOTHER agent by placing a new card on THEIR board. Use this to hand off or route work to a teammate agent (e.g. you triage a request and route the fix to a specialist agent). This is different from kanban_add, which adds a card to YOUR OWN board. By default the target must be an agent on your OWN team. To assign across teams within your organization, also pass `target_team` (the other team\'s slug) \u2014 this only works if your org has enabled cross-team assignment and a peer grant links the two teams; otherwise it reads as not-found. When the target finishes, you get a completion notice back on your board. Delegating a ticket? Pass `source_integration` + `source_external_id` (e.g. "composio/linear" / "ENG-123") so the card is linked to it and completing the card pushes status back to the issue \u2014 putting the URL in the description only leaves the link in prose. Don\'t know the agent\'s code_name or team slug? Call directory_lookup first to find them.',
|
|
22460
22460
|
{
|
|
22461
22461
|
target_agent: external_exports.string().describe(
|
|
22462
22462
|
"The teammate to assign to: their agent code_name (kebab-case) or agent UUID. On your own team unless target_team is also set."
|
|
@@ -22473,7 +22473,16 @@ server.tool(
|
|
|
22473
22473
|
deliverable: external_exports.string().optional().describe("Expected output/deliverable from the target"),
|
|
22474
22474
|
deliver_to: external_exports.string().trim().regex(/^[UW][A-Z0-9]{6,}$/, "deliver_to must be a Slack user id (e.g. U01234567)").optional().describe(
|
|
22475
22475
|
"Optional: a Slack user id (e.g. U01234567) to DM the completion notice to directly when the target finishes, in ADDITION to the notice landing on your board. Use this to deliver the result straight to the person who wanted it (e.g. the requester's Slack id from the originating message) instead of hand-forwarding it yourself. Must be a Slack user id, not a @handle or display name."
|
|
22476
|
-
)
|
|
22476
|
+
),
|
|
22477
|
+
// ENG-8649: the source linkage kanban_add has always had. Pass BOTH or
|
|
22478
|
+
// neither — one alone is rejected.
|
|
22479
|
+
source_integration: external_exports.string().optional().describe(
|
|
22480
|
+
'Integration the work came from \u2014 the toolkit slug, e.g. "composio/linear" or "composio/jira". A bare name ("linear") is accepted and normalised. Pass together with source_external_id when you are delegating a ticket, so completing the card pushes the status back to the issue instead of the link living only in prose. Status write-back only happens for integrations with an import adapter (linear, jira, asana, trello, notion); for anything else the linkage is recorded but nothing is pushed upstream.'
|
|
22481
|
+
),
|
|
22482
|
+
source_external_id: external_exports.string().optional().describe(
|
|
22483
|
+
'ID in the external system (e.g. "ENG-123"). Required alongside source_integration.'
|
|
22484
|
+
),
|
|
22485
|
+
source_url: external_exports.string().optional().describe("Deep link to the external source (e.g. the Linear issue URL).")
|
|
22477
22486
|
},
|
|
22478
22487
|
async (params) => {
|
|
22479
22488
|
try {
|
|
@@ -22493,7 +22502,12 @@ server.tool(
|
|
|
22493
22502
|
...params.status !== void 0 ? { status: params.status } : {},
|
|
22494
22503
|
deliverable: params.deliverable,
|
|
22495
22504
|
// CS-1438: only sent when set; the route treats absence as board-ack-only.
|
|
22496
|
-
...params.deliver_to !== void 0 ? { deliver_to: params.deliver_to } : {}
|
|
22505
|
+
...params.deliver_to !== void 0 ? { deliver_to: params.deliver_to } : {},
|
|
22506
|
+
// ENG-8649: only sent when set, so an existing caller's request body is
|
|
22507
|
+
// byte-for-byte unchanged and the route keeps its channel-origin path.
|
|
22508
|
+
...params.source_integration !== void 0 ? { source_integration: params.source_integration } : {},
|
|
22509
|
+
...params.source_external_id !== void 0 ? { source_external_id: params.source_external_id } : {},
|
|
22510
|
+
...params.source_url !== void 0 ? { source_url: params.source_url } : {}
|
|
22497
22511
|
});
|
|
22498
22512
|
const where = data.cross_team ? ` on team ${data.target_team ?? params.target_team}` : "";
|
|
22499
22513
|
const inOrg = data.organization_name ? ` in ${data.organization_name}` : "";
|
|
@@ -37442,6 +37442,47 @@ var SLACK_EGRESS_TOOLS = /* @__PURE__ */ new Set([
|
|
|
37442
37442
|
"slack.update"
|
|
37443
37443
|
]);
|
|
37444
37444
|
|
|
37445
|
+
// ../core/dist/channels/governance/slack-ingress-only-threads.js
|
|
37446
|
+
function buildIngressThreadKey(channel, threadTs) {
|
|
37447
|
+
if (!channel || !threadTs)
|
|
37448
|
+
return null;
|
|
37449
|
+
return `${channel}:${threadTs}`;
|
|
37450
|
+
}
|
|
37451
|
+
function createIngressOnlyThreadRegistry(maxEntries = 500) {
|
|
37452
|
+
const marked = /* @__PURE__ */ new Set();
|
|
37453
|
+
return {
|
|
37454
|
+
mark(channel, threadTs) {
|
|
37455
|
+
const key2 = buildIngressThreadKey(channel, threadTs);
|
|
37456
|
+
if (!key2)
|
|
37457
|
+
return;
|
|
37458
|
+
marked.delete(key2);
|
|
37459
|
+
marked.add(key2);
|
|
37460
|
+
while (marked.size > maxEntries) {
|
|
37461
|
+
const oldest = marked.values().next();
|
|
37462
|
+
if (oldest.done)
|
|
37463
|
+
break;
|
|
37464
|
+
marked.delete(oldest.value);
|
|
37465
|
+
}
|
|
37466
|
+
},
|
|
37467
|
+
clear(channel, threadTs) {
|
|
37468
|
+
const key2 = buildIngressThreadKey(channel, threadTs);
|
|
37469
|
+
if (!key2)
|
|
37470
|
+
return;
|
|
37471
|
+
marked.delete(key2);
|
|
37472
|
+
},
|
|
37473
|
+
isIngressOnly(channel, threadTs) {
|
|
37474
|
+
const key2 = buildIngressThreadKey(channel, threadTs);
|
|
37475
|
+
if (!key2)
|
|
37476
|
+
return false;
|
|
37477
|
+
return marked.has(key2);
|
|
37478
|
+
},
|
|
37479
|
+
size() {
|
|
37480
|
+
return marked.size;
|
|
37481
|
+
}
|
|
37482
|
+
};
|
|
37483
|
+
}
|
|
37484
|
+
var INGRESS_ONLY_REFUSAL = "This thread was opened by a third-party bot (an alert or issue card), which can wake you but is not someone you can talk to - replying would start a bot-to-bot exchange in a shared channel. Act on the content instead: work the issue, or raise it with a person in a thread they are in. If a human posts here, this thread becomes repliable.";
|
|
37485
|
+
|
|
37445
37486
|
// src/strip-repost-preamble.ts
|
|
37446
37487
|
var PRIOR_ATTEMPT_CUE = /\b(a moment ago|just now|a second ago|earlier|moments ago|previously|last (?:time|attempt)|drafted|dialled|dialed|typed|composed|wrote|sent) (?:this|that|it)?\b|\b(?:drafted|dialled|dialed|typed|composed)\b/i;
|
|
37447
37488
|
var FAILURE_CUE = /\b(?:did(?:n['’]t| not)|could(?:n['’]t| not)|would(?:n['’]t| not)|wasn['’]t|fail(?:ed)?|never)\b[^.!?\n]*?\b(?:parse[d]?|send|sent|go through|went through|land|deliver(?:ed)?|post(?:ed)?|come through|came through)\b/i;
|
|
@@ -39956,6 +39997,16 @@ function classifyPeerMessage(msg, cfg, self) {
|
|
|
39956
39997
|
}
|
|
39957
39998
|
const peer = cfg.peers.find((p2) => p2.bot_user_id === msg.user);
|
|
39958
39999
|
if (!peer) {
|
|
40000
|
+
const thirdParty = cfg.third_party_bots?.find((b) => b.bot_user_id === msg.user);
|
|
40001
|
+
if (thirdParty) {
|
|
40002
|
+
if (cfg.peer_disabled_mode === "cross_team_only") {
|
|
40003
|
+
return { kind: "drop", reason: "peer_disabled_cross_team" };
|
|
40004
|
+
}
|
|
40005
|
+
if (thirdParty.channel_ids.includes(msg.channel)) {
|
|
40006
|
+
return { kind: "bot-ingress", bot: thirdParty };
|
|
40007
|
+
}
|
|
40008
|
+
return { kind: "drop", reason: "third_party_channel_not_allowlisted" };
|
|
40009
|
+
}
|
|
39959
40010
|
return { kind: "drop", reason: "unknown_peer" };
|
|
39960
40011
|
}
|
|
39961
40012
|
if (peer.gate_path === null) {
|
|
@@ -40063,6 +40114,33 @@ function parsePeerGroupIdsEnv(raw) {
|
|
|
40063
40114
|
return [];
|
|
40064
40115
|
return raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
40065
40116
|
}
|
|
40117
|
+
function parseThirdPartyBotsEnv(raw) {
|
|
40118
|
+
if (!raw || !raw.trim())
|
|
40119
|
+
return [];
|
|
40120
|
+
let parsed;
|
|
40121
|
+
try {
|
|
40122
|
+
parsed = JSON.parse(raw);
|
|
40123
|
+
} catch {
|
|
40124
|
+
return [];
|
|
40125
|
+
}
|
|
40126
|
+
if (!Array.isArray(parsed))
|
|
40127
|
+
return [];
|
|
40128
|
+
const out = [];
|
|
40129
|
+
for (const item of parsed) {
|
|
40130
|
+
if (!item || typeof item !== "object")
|
|
40131
|
+
continue;
|
|
40132
|
+
const rec = item;
|
|
40133
|
+
const botUserId2 = typeof rec["bot_user_id"] === "string" ? rec["bot_user_id"].trim() : "";
|
|
40134
|
+
if (!botUserId2)
|
|
40135
|
+
continue;
|
|
40136
|
+
if (!Array.isArray(rec["channel_ids"]))
|
|
40137
|
+
continue;
|
|
40138
|
+
const channels = rec["channel_ids"].filter((c) => typeof c === "string" && c.trim() !== "").map((c) => c.trim());
|
|
40139
|
+
const label = typeof rec["label"] === "string" && rec["label"].trim() ? rec["label"].trim() : void 0;
|
|
40140
|
+
out.push({ bot_user_id: botUserId2, channel_ids: channels, ...label ? { label } : {} });
|
|
40141
|
+
}
|
|
40142
|
+
return out;
|
|
40143
|
+
}
|
|
40066
40144
|
function parsePeerAgentModeEnv(raw) {
|
|
40067
40145
|
if (raw === "listen" || raw === "respond")
|
|
40068
40146
|
return raw;
|
|
@@ -41074,8 +41152,14 @@ var SLACK_PEER_CLASSIFIER_CONFIG = {
|
|
|
41074
41152
|
peer_agent_mode: parsePeerAgentModeEnv(process.env.SLACK_PEER_AGENT_MODE),
|
|
41075
41153
|
peer_group_ids: parsePeerGroupIdsEnv(process.env.SLACK_PEER_GROUP_IDS),
|
|
41076
41154
|
peers: parsePeersEnv(process.env.SLACK_PEERS, process.env.SLACK_PEERS_GATE),
|
|
41077
|
-
peer_disabled_mode: SLACK_PEER_DISABLED_MODE
|
|
41155
|
+
peer_disabled_mode: SLACK_PEER_DISABLED_MODE,
|
|
41156
|
+
// ENG-8669: third-party bots (Linear, Amazon Q, CloudWatch, PagerDuty) that
|
|
41157
|
+
// may WAKE this agent, per channel. Absent env = empty = the pre-ENG-8669
|
|
41158
|
+
// behaviour exactly, so this ships inert for every agent that has not opted
|
|
41159
|
+
// in. Ingress-only by construction - see isReplyEligible in the classifier.
|
|
41160
|
+
third_party_bots: parseThirdPartyBotsEnv(process.env.SLACK_THIRD_PARTY_BOTS)
|
|
41078
41161
|
};
|
|
41162
|
+
var ingressOnlyThreads = createIngressOnlyThreadRegistry();
|
|
41079
41163
|
var SLACK_TEAM_PEER_USER_IDS = parseTeamPeerUserIdsEnv(
|
|
41080
41164
|
process.env.SLACK_TEAM_PEER_USER_IDS
|
|
41081
41165
|
);
|
|
@@ -43815,6 +43899,16 @@ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
43815
43899
|
if (isImpersonating() && !channelsEnabledOverride() && SLACK_EGRESS_TOOLS.has(name)) {
|
|
43816
43900
|
return buildImpersonationRefusal(name);
|
|
43817
43901
|
}
|
|
43902
|
+
if (SLACK_EGRESS_TOOLS.has(name)) {
|
|
43903
|
+
const egressArgs = args ?? {};
|
|
43904
|
+
const targetThread = egressArgs.thread_ts ?? egressArgs.message_ts;
|
|
43905
|
+
if (ingressOnlyThreads.isIngressOnly(egressArgs.channel, targetThread)) {
|
|
43906
|
+
return {
|
|
43907
|
+
content: [{ type: "text", text: INGRESS_ONLY_REFUSAL }],
|
|
43908
|
+
isError: true
|
|
43909
|
+
};
|
|
43910
|
+
}
|
|
43911
|
+
}
|
|
43818
43912
|
if (name === "slack.reply") {
|
|
43819
43913
|
const { channel, text, thread_ts, message_ts, interim, inbound_id, proactive, to_channel_root } = args;
|
|
43820
43914
|
const bindingMode = slackReplyBindingMode();
|
|
@@ -45491,6 +45585,12 @@ async function connectSocketMode() {
|
|
|
45491
45585
|
});
|
|
45492
45586
|
const passedIdentity = access.kind !== "drop" || access.reason.startsWith("peer:");
|
|
45493
45587
|
if (passedIdentity) recordActivity("inbound");
|
|
45588
|
+
const ingressThreadTs = evt.thread_ts ?? evt.ts;
|
|
45589
|
+
if (peerClassification?.kind === "bot-ingress" && access.kind !== "drop") {
|
|
45590
|
+
ingressOnlyThreads.mark(evt.channel, ingressThreadTs);
|
|
45591
|
+
} else if (!isBot) {
|
|
45592
|
+
ingressOnlyThreads.clear(evt.channel, ingressThreadTs);
|
|
45593
|
+
}
|
|
45494
45594
|
if (access.kind === "drop") {
|
|
45495
45595
|
const channelHash = createHash3("sha256").update(evt.channel ?? "").digest("hex").slice(0, 8);
|
|
45496
45596
|
const subtypeSuffix = access.reason === "content:subtype" ? ` subtype=${evt.subtype ?? "none"}` : "";
|
package/package.json
CHANGED
|
File without changes
|