@integrity-labs/agt-cli 0.28.978 → 0.28.980

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.
@@ -15227,6 +15227,59 @@ function teamsInboundId(conversationId, activityId) {
15227
15227
  return hashInboundId(`${conversationId}|${activityId}`);
15228
15228
  }
15229
15229
 
15230
+ // src/impersonation.ts
15231
+ var ENV_VAR = "AGT_ACT_AS_AGENT_ID";
15232
+ var OVERRIDE_ENV_VAR = "ENABLE_IMPERSONATION_CHANNELS";
15233
+ function isImpersonating() {
15234
+ return impersonatedAgentId() !== null;
15235
+ }
15236
+ function impersonatedAgentId() {
15237
+ const raw = process.env[ENV_VAR];
15238
+ if (typeof raw !== "string") return null;
15239
+ const trimmed = raw.trim();
15240
+ return trimmed.length > 0 ? trimmed : null;
15241
+ }
15242
+ function channelsEnabledOverride() {
15243
+ const raw = process.env[OVERRIDE_ENV_VAR];
15244
+ if (typeof raw !== "string") return false;
15245
+ const trimmed = raw.trim().toLowerCase();
15246
+ return trimmed === "1" || trimmed === "true" || trimmed === "yes" || trimmed === "on";
15247
+ }
15248
+ var IMPERSONATION_REFUSAL_CODE = "CHANNEL.IMPERSONATION_DISABLED";
15249
+ var IMPERSONATION_REFUSAL_MESSAGE = "Posting as an agent under impersonation is disabled in v0 \u2014 quit impersonation with `agt impersonate exit` to send as yourself.";
15250
+ function buildImpersonationRefusal(toolName) {
15251
+ return {
15252
+ content: [
15253
+ {
15254
+ type: "text",
15255
+ text: JSON.stringify({
15256
+ error: {
15257
+ code: IMPERSONATION_REFUSAL_CODE,
15258
+ message: IMPERSONATION_REFUSAL_MESSAGE,
15259
+ tool: toolName
15260
+ }
15261
+ })
15262
+ }
15263
+ ],
15264
+ isError: true
15265
+ };
15266
+ }
15267
+ function shouldRefuseImpersonatedEgress(toolName, egressTools) {
15268
+ if (!isImpersonating()) return null;
15269
+ if (channelsEnabledOverride()) return null;
15270
+ if (!egressTools.has(toolName)) return null;
15271
+ return buildImpersonationRefusal(toolName);
15272
+ }
15273
+
15274
+ // src/channel-egress-tools.ts
15275
+ var TEAMS_EGRESS_TOOLS = /* @__PURE__ */ new Set([
15276
+ "teams.reply",
15277
+ "teams.react",
15278
+ "teams.send_structured",
15279
+ "teams.ask_user",
15280
+ "teams.upload_file"
15281
+ ]);
15282
+
15230
15283
  // src/teams-channel.ts
15231
15284
  var APP_ID = process.env.MSTEAMS_APP_ID ?? null;
15232
15285
  var CLIENT_SECRET = process.env.MSTEAMS_CLIENT_SECRET ?? null;
@@ -15907,6 +15960,13 @@ mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
15907
15960
  mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
15908
15961
  const { name, arguments: args } = req.params;
15909
15962
  const a = args ?? {};
15963
+ const impersonationRefusal = shouldRefuseImpersonatedEgress(
15964
+ name,
15965
+ TEAMS_EGRESS_TOOLS
15966
+ );
15967
+ if (impersonationRefusal) {
15968
+ return { ...impersonationRefusal };
15969
+ }
15910
15970
  if (name === "teams.reply") return handleReply(a);
15911
15971
  if (name === "teams.react") return handleReact(a);
15912
15972
  if (name === "teams.read_thread") return handleReadThread(a);
@@ -155882,6 +155882,56 @@ async function startBaileysSession(opts) {
155882
155882
  };
155883
155883
  }
155884
155884
 
155885
+ // src/impersonation.ts
155886
+ var ENV_VAR = "AGT_ACT_AS_AGENT_ID";
155887
+ var OVERRIDE_ENV_VAR = "ENABLE_IMPERSONATION_CHANNELS";
155888
+ function isImpersonating() {
155889
+ return impersonatedAgentId() !== null;
155890
+ }
155891
+ function impersonatedAgentId() {
155892
+ const raw = process.env[ENV_VAR];
155893
+ if (typeof raw !== "string") return null;
155894
+ const trimmed = raw.trim();
155895
+ return trimmed.length > 0 ? trimmed : null;
155896
+ }
155897
+ function channelsEnabledOverride() {
155898
+ const raw = process.env[OVERRIDE_ENV_VAR];
155899
+ if (typeof raw !== "string") return false;
155900
+ const trimmed = raw.trim().toLowerCase();
155901
+ return trimmed === "1" || trimmed === "true" || trimmed === "yes" || trimmed === "on";
155902
+ }
155903
+ var IMPERSONATION_REFUSAL_CODE = "CHANNEL.IMPERSONATION_DISABLED";
155904
+ var IMPERSONATION_REFUSAL_MESSAGE = "Posting as an agent under impersonation is disabled in v0 \u2014 quit impersonation with `agt impersonate exit` to send as yourself.";
155905
+ function buildImpersonationRefusal(toolName) {
155906
+ return {
155907
+ content: [
155908
+ {
155909
+ type: "text",
155910
+ text: JSON.stringify({
155911
+ error: {
155912
+ code: IMPERSONATION_REFUSAL_CODE,
155913
+ message: IMPERSONATION_REFUSAL_MESSAGE,
155914
+ tool: toolName
155915
+ }
155916
+ })
155917
+ }
155918
+ ],
155919
+ isError: true
155920
+ };
155921
+ }
155922
+ function shouldRefuseImpersonatedEgress(toolName, egressTools) {
155923
+ if (!isImpersonating()) return null;
155924
+ if (channelsEnabledOverride()) return null;
155925
+ if (!egressTools.has(toolName)) return null;
155926
+ return buildImpersonationRefusal(toolName);
155927
+ }
155928
+
155929
+ // src/channel-egress-tools.ts
155930
+ var WHATSAPP_EGRESS_TOOLS = /* @__PURE__ */ new Set([
155931
+ "whatsapp.reply",
155932
+ "whatsapp.send_template"
155933
+ ]);
155934
+
155885
155935
  // src/whatsapp-channel.ts
155886
155936
  var CODE_NAME = process.env["AGT_AGENT_CODE_NAME"] ?? "";
155887
155937
  var PENDING_INBOUND_DIR = CODE_NAME ? join4(homedir(), ".augmented", CODE_NAME, "whatsapp-pending-inbound") : null;
@@ -156091,13 +156141,30 @@ var sendTemplateTool = {
156091
156141
  };
156092
156142
  mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
156093
156143
  // Templates are a Cloud-API (kapso) concept — not exposed in baileys mode.
156094
- tools: IS_BAILEYS ? [replyTool] : [replyTool, sendTemplateTool]
156144
+ //
156145
+ // ENG-10753 — written as one array with a conditional tail rather than
156146
+ // `IS_BAILEYS ? [replyTool] : [replyTool, sendTemplateTool]`, which is the
156147
+ // same registration and was not readable. The egress test enumerates each
156148
+ // server's tools from this AST to assert every one is classified as egress
156149
+ // or read-only; the ternary form made that walk THROW, and a server whose
156150
+ // registration cannot be read is a server the classification test cannot
156151
+ // cover — which is how this file came to have no impersonation gate while
156152
+ // three of its siblings did. Keep both branches enumerable: a tool behind a
156153
+ // provider flag is still a tool, and still needs gating.
156154
+ tools: [replyTool, ...IS_BAILEYS ? [] : [sendTemplateTool]]
156095
156155
  }));
156096
156156
  var errResult = (text) => ({ content: [{ type: "text", text }], isError: true });
156097
156157
  var stringArg = (a, k) => typeof a[k] === "string" && a[k].length > 0 ? a[k] : null;
156098
156158
  mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
156099
156159
  const { name, arguments: args } = req.params;
156100
156160
  const a = args ?? {};
156161
+ const impersonationRefusal = shouldRefuseImpersonatedEgress(
156162
+ name,
156163
+ WHATSAPP_EGRESS_TOOLS
156164
+ );
156165
+ if (impersonationRefusal) {
156166
+ return { ...impersonationRefusal };
156167
+ }
156101
156168
  if (name === "whatsapp.reply") return handleReply(a);
156102
156169
  if (name === "whatsapp.send_template") return handleSendTemplate(a);
156103
156170
  return errResult(`Unknown tool: ${name}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.28.978",
3
+ "version": "0.28.980",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {