@integrity-labs/agt-cli 0.17.0 → 0.17.4

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 CHANGED
@@ -48,7 +48,7 @@ import {
48
48
  success,
49
49
  table,
50
50
  warn
51
- } from "../chunk-P52H3XS6.js";
51
+ } from "../chunk-HMN7YJOD.js";
52
52
 
53
53
  // src/bin/agt.ts
54
54
  import { join as join10 } from "path";
@@ -3732,7 +3732,7 @@ import { execFileSync, execSync } from "child_process";
3732
3732
  import { existsSync as existsSync5, realpathSync } from "fs";
3733
3733
  import chalk17 from "chalk";
3734
3734
  import ora15 from "ora";
3735
- var cliVersion = true ? "0.17.0" : "dev";
3735
+ var cliVersion = true ? "0.17.4" : "dev";
3736
3736
  async function fetchLatestVersion() {
3737
3737
  const host2 = getHost();
3738
3738
  if (!host2) return null;
@@ -4190,7 +4190,7 @@ function handleError(err) {
4190
4190
  }
4191
4191
 
4192
4192
  // src/bin/agt.ts
4193
- var cliVersion2 = true ? "0.17.0" : "dev";
4193
+ var cliVersion2 = true ? "0.17.4" : "dev";
4194
4194
  var program = new Command();
4195
4195
  program.name("agt").description("Augmented CLI \u2014 agent provisioning and management").version(cliVersion2).option("--json", "Emit machine-readable JSON output (suppress spinners and colors)").option("--skip-update-check", "Skip the automatic update check on startup");
4196
4196
  program.hook("preAction", (thisCommand) => {
@@ -429,6 +429,27 @@ var INTEGRATION_REGISTRY = [
429
429
  { id: "xero:manage-settings", name: "Manage Settings", description: "Manage org settings and chart of accounts", access: "admin" }
430
430
  ]
431
431
  },
432
+ {
433
+ id: "granola",
434
+ name: "Granola",
435
+ category: "knowledge",
436
+ description: "Meeting notes search \u2014 query transcripts, summaries, and folders from Granola",
437
+ // Granola uses a remote streamable-HTTP MCP with PKCE + Dynamic Client
438
+ // Registration. End-user OAuth is brokered by the webapp (ENG-4693)
439
+ // through the shared /integrations/oauth/authorize → /callback path
440
+ // (ENG-4694), and the access_token is injected into .mcp.json via the
441
+ // generic bearer-header path. No host-side action required from the
442
+ // operator beyond running the one-time DCR registration script at
443
+ // deploy time.
444
+ supported_auth_types: ["oauth2"],
445
+ capabilities: [
446
+ { id: "granola:search-meetings", name: "Search Meetings", description: "Browse meetings, search content, and chat with notes (query_granola_meetings, list_meetings, get_meetings)", access: "read" },
447
+ { id: "granola:read-transcripts", name: "Read Transcripts", description: "Access raw meeting transcripts (paid plans only \u2014 get_meeting_transcript)", access: "read" },
448
+ { id: "granola:list-folders", name: "List Folders", description: "View accessible meeting folders (paid plans only \u2014 list_meeting_folders)", access: "read" }
449
+ ],
450
+ docs_url: "https://docs.granola.ai/docs/api/mcp",
451
+ beta: true
452
+ },
432
453
  {
433
454
  id: "qmd",
434
455
  name: "QMD Memory Search",
@@ -2802,6 +2823,50 @@ You are **${frontmatter.display_name}**, **${roleDisplay}**${team ? ` at **${tea
2802
2823
  ${desc ? `
2803
2824
  ${desc}
2804
2825
  ` : ""}
2826
+
2827
+ ## \u26A0\uFE0F FIRST ACTION on every channel message: triage
2828
+
2829
+ This is the highest-priority instruction in this document. Before anything
2830
+ else when you receive an inbound \`<channel>\` tag (Slack/Telegram/Direct
2831
+ Chat), decide:
2832
+
2833
+ **Will completing this request take longer than ~60 seconds of tool work?**
2834
+ Treat as SLOW if it involves any of: Xero data pulls, multi-step Composio
2835
+ chains, web research, reading/writing >5 files, image generation, dashboard
2836
+ refreshes, multi-skill activations, or anything you'd reasonably want to
2837
+ acknowledge before you start.
2838
+
2839
+ - **FAST (< 60s):** handle inline. Reply via the channel tool
2840
+ (slack.reply / telegram.reply / directchat.reply) and end your turn.
2841
+
2842
+ - **SLOW (\u2265 60s):** dispatch.
2843
+ 1. Send a one-line acknowledgement via the channel tool \u2014 short, warm,
2844
+ and tell the user you'll come back. Example shape (don't copy verbatim,
2845
+ match your voice): "On it \u2014 this'll take a minute or two, I'll ping
2846
+ when it's done."
2847
+ 2. Invoke the \`channel-message-handler\` subagent (Task tool, with
2848
+ \`subagent_type: channel-message-handler\`) with the full original
2849
+ message text plus the **channel-specific routing keys** the reply
2850
+ tool needs: Slack threads \u2192 \`{ channel_id, thread_ts }\`; Slack
2851
+ non-thread DMs \u2192 \`{ channel_id }\`; Telegram \u2192 \`{ chat_id, message_id }\`;
2852
+ Direct Chat \u2192 \`{ conversation_id }\`. Pass these verbatim from the
2853
+ inbound \`<channel>\` tag \u2014 don't substitute a generic \`message_ts\`,
2854
+ since only Slack threads use it. The subagent will do the actual
2855
+ work and post the real reply itself.
2856
+ 3. End your turn. **Do NOT call slack.reply / telegram.reply with the
2857
+ full result yourself** \u2014 that's the subagent's job.
2858
+
2859
+ **Why this matters more than any other instruction below:** if you handle
2860
+ slow requests inline, you go silent for 60+ seconds while operators send
2861
+ follow-up messages that queue behind you. Dispatching keeps you free to
2862
+ acknowledge new pings. The kanban-tracking-link convention, work-management
2863
+ "create a task" guidance, and Slack reply patterns ALL apply to fast
2864
+ inline replies \u2014 they do NOT replace this dispatch decision.
2865
+
2866
+ If the work turns out to be unexpectedly slow after you started inline,
2867
+ finish the current sub-step, then dispatch the rest. Don't apologise for
2868
+ mid-task switching \u2014 operators care about responsiveness, not consistency.
2869
+
2805
2870
  ${personalitySection}## Identity
2806
2871
 
2807
2872
  - Code Name: ${frontmatter.code_name}
@@ -2813,8 +2878,13 @@ ${personalitySection}## Identity
2813
2878
  ${resolvedChannels?.includes("slack") ? `
2814
2879
  ## Slack
2815
2880
 
2816
- You have a Slack MCP server connected. When Slack messages arrive via the channel
2817
- protocol, respond directly in the conversation. You can also proactively use:
2881
+ You have a Slack MCP server connected. **First, see \xA7 FIRST ACTION on
2882
+ every channel message: triage** at the top of this document \u2014 decide
2883
+ fast vs slow before anything else, and dispatch slow work via
2884
+ \`channel-message-handler\` rather than handling it inline.
2885
+
2886
+ For fast requests, respond directly in the conversation. You can also
2887
+ proactively use:
2818
2888
 
2819
2889
  - **slack.reply** \u2014 reply to a message in a channel/thread
2820
2890
  - **slack.react** \u2014 add an emoji reaction to a message (use sparingly \u2014 see taxonomy below)
@@ -3007,6 +3077,124 @@ The marginal cost of completeness is near zero. Do the whole thing.
3007
3077
  ${frontmatter.environment === "prod" ? "- Production environment: exercise extra caution with all operations.\n" : ""}`;
3008
3078
  }
3009
3079
 
3080
+ // ../../packages/core/dist/integrations/oauth-providers.js
3081
+ var OAUTH_PROVIDERS = {
3082
+ "google-workspace": {
3083
+ definitionId: "google-workspace",
3084
+ authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
3085
+ tokenUrl: "https://oauth2.googleapis.com/token",
3086
+ revokeUrl: "https://oauth2.googleapis.com/revoke",
3087
+ defaultScopes: [
3088
+ "https://www.googleapis.com/auth/gmail.modify",
3089
+ "https://www.googleapis.com/auth/calendar",
3090
+ "https://www.googleapis.com/auth/drive",
3091
+ "https://www.googleapis.com/auth/spreadsheets",
3092
+ "https://www.googleapis.com/auth/documents",
3093
+ "https://www.googleapis.com/auth/chat.messages",
3094
+ "https://www.googleapis.com/auth/chat.spaces.readonly"
3095
+ ],
3096
+ supportsRefresh: true,
3097
+ extraAuthorizeParams: {
3098
+ access_type: "offline",
3099
+ prompt: "consent"
3100
+ },
3101
+ clientAuthMethod: "body",
3102
+ userInfoUrl: "https://www.googleapis.com/oauth2/v2/userinfo"
3103
+ },
3104
+ "github": {
3105
+ definitionId: "github",
3106
+ authorizeUrl: "https://github.com/login/oauth/authorize",
3107
+ tokenUrl: "https://github.com/login/oauth/access_token",
3108
+ defaultScopes: ["repo", "read:org", "gist", "workflow"],
3109
+ supportsRefresh: true,
3110
+ extraAuthorizeParams: {},
3111
+ clientAuthMethod: "body",
3112
+ userInfoUrl: "https://api.github.com/user"
3113
+ },
3114
+ "granola": {
3115
+ // Granola MCP — remote streamable-HTTP at https://mcp.granola.ai/mcp.
3116
+ // The AS is at mcp-auth.granola.ai and exposes RFC 8414 metadata at
3117
+ // /.well-known/oauth-authorization-server. Auth is OAuth 2.0 with
3118
+ // mandatory PKCE (S256) and a public client (no client_secret) issued
3119
+ // via Dynamic Client Registration (RFC 7591). The bootstrap script
3120
+ // (`packages/api/scripts/dcr-register.ts`) registers a client once at
3121
+ // deploy time; OAUTH_GRANOLA_CLIENT_ID is set from its output.
3122
+ definitionId: "granola",
3123
+ authorizeUrl: "https://mcp-auth.granola.ai/oauth2/authorize",
3124
+ tokenUrl: "https://mcp-auth.granola.ai/oauth2/token",
3125
+ // openid+profile+email give us the user identity for status_message;
3126
+ // offline_access is the one that earns us a refresh_token so the
3127
+ // refresh cron can rotate the bearer without operator action.
3128
+ defaultScopes: ["openid", "profile", "email", "offline_access"],
3129
+ supportsRefresh: true,
3130
+ extraAuthorizeParams: {},
3131
+ clientAuthMethod: "body",
3132
+ pkce: "S256",
3133
+ publicClient: true,
3134
+ mcpUrl: "https://mcp.granola.ai/mcp"
3135
+ },
3136
+ "xero": {
3137
+ definitionId: "xero",
3138
+ authorizeUrl: "https://login.xero.com/identity/connect/authorize",
3139
+ tokenUrl: "https://identity.xero.com/connect/token",
3140
+ revokeUrl: "https://identity.xero.com/connect/revocation",
3141
+ defaultScopes: [
3142
+ "openid",
3143
+ "profile",
3144
+ "email",
3145
+ "offline_access",
3146
+ // Granular scopes (required for apps created after March 2, 2026 —
3147
+ // do NOT revert to the broad `accounting.transactions` /
3148
+ // `accounting.contacts` scopes, Xero rejects the manifest).
3149
+ // The variant *without* `.read` is the read+write granular scope.
3150
+ "accounting.settings.read",
3151
+ // contacts: write enables agent-driven supplier/customer creation
3152
+ // (required for bill creation since a bill must reference a contact).
3153
+ "accounting.contacts",
3154
+ // invoices: write enables bill creation (Type=ACCPAY invoices) and
3155
+ // updates to sales invoices alongside the existing read access.
3156
+ "accounting.invoices",
3157
+ // attachments: write enables agents to attach the source PDF to a
3158
+ // bill at creation time. Read-only would force a follow-up manual
3159
+ // upload in Xero; write closes the loop.
3160
+ "accounting.attachments",
3161
+ // accounting.transactions.read → granular read-only replacements
3162
+ // for the surfaces we don't yet need write access on.
3163
+ "accounting.payments.read",
3164
+ "accounting.banktransactions.read",
3165
+ "accounting.manualjournals.read",
3166
+ // accounting.reports.read → granular read-only replacements
3167
+ "accounting.reports.balancesheet.read",
3168
+ "accounting.reports.profitandloss.read",
3169
+ "accounting.reports.trialbalance.read",
3170
+ "accounting.reports.budgetsummary.read",
3171
+ "accounting.reports.banksummary.read",
3172
+ "accounting.reports.executivesummary.read",
3173
+ "accounting.reports.aged.read"
3174
+ ],
3175
+ supportsRefresh: true,
3176
+ extraAuthorizeParams: {},
3177
+ clientAuthMethod: "basic",
3178
+ userInfoUrl: "https://api.xero.com/connections"
3179
+ }
3180
+ };
3181
+
3182
+ // ../../packages/core/dist/provisioning/remote-mcp.js
3183
+ function envVarForToken(definitionId) {
3184
+ return `${definitionId.replace(/-/g, "_").toUpperCase()}_ACCESS_TOKEN`;
3185
+ }
3186
+ function buildRemoteMcpEntry(definitionId) {
3187
+ const provider = OAUTH_PROVIDERS[definitionId];
3188
+ if (!provider?.mcpUrl)
3189
+ return null;
3190
+ return {
3191
+ url: provider.mcpUrl,
3192
+ headers: {
3193
+ Authorization: `Bearer \${${envVarForToken(definitionId)}}`
3194
+ }
3195
+ };
3196
+ }
3197
+
3010
3198
  // ../../packages/core/dist/provisioning/frameworks/claudecode/index.js
3011
3199
  var VALID_CODE_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
3012
3200
  var SECRET_FILE_MODE = 384;
@@ -3160,6 +3348,38 @@ function deployArtifactsToProject(codeName, provisionDir) {
3160
3348
  }
3161
3349
  } catch {
3162
3350
  }
3351
+ const agentsDir = join4(provisionDir, ".claude", "agents");
3352
+ const destAgentsDir = join4(projectDir, ".claude", "agents");
3353
+ try {
3354
+ if (existsSync4(agentsDir)) {
3355
+ const sourceAgentFiles = new Set(readdirSync(agentsDir).filter((f) => f.endsWith(".md")));
3356
+ if (existsSync4(destAgentsDir)) {
3357
+ for (const destFile of readdirSync(destAgentsDir)) {
3358
+ if (!destFile.endsWith(".md"))
3359
+ continue;
3360
+ if (sourceAgentFiles.has(destFile))
3361
+ continue;
3362
+ try {
3363
+ rmSync(join4(destAgentsDir, destFile));
3364
+ } catch {
3365
+ }
3366
+ }
3367
+ }
3368
+ for (const agentFile of sourceAgentFiles) {
3369
+ const srcPath = join4(agentsDir, agentFile);
3370
+ const destPath = join4(destAgentsDir, agentFile);
3371
+ const srcContent = readFileSync4(srcPath, "utf-8");
3372
+ try {
3373
+ if (existsSync4(destPath) && readFileSync4(destPath, "utf-8") === srcContent)
3374
+ continue;
3375
+ } catch {
3376
+ }
3377
+ mkdirSync4(destAgentsDir, { recursive: true });
3378
+ writeFileSync4(destPath, srcContent);
3379
+ }
3380
+ }
3381
+ } catch {
3382
+ }
3163
3383
  const agentMcpPath = join4(getAgentDir(codeName), "provision", ".mcp.json");
3164
3384
  const projectMcpPath = join4(projectDir, ".mcp.json");
3165
3385
  try {
@@ -3581,6 +3801,30 @@ function buildSettingsJson(input) {
3581
3801
  settings["permissions"] = { deny: SECRETS_DENY_PERMISSIONS };
3582
3802
  return settings;
3583
3803
  }
3804
+ function buildChannelMessageHandlerAgent() {
3805
+ return `---
3806
+ name: channel-message-handler
3807
+ description: Handles a single inbound Slack/Telegram/Direct-Chat message end to end. Posts the reply itself via the matching channel tool. The parent agent dispatches to this subagent only for slow requests (\u2265 ~60s) so the parent's listener turn stays free for new inbound work.
3808
+ background: true
3809
+ tools: Bash, Read, Write, Edit, Grep, Glob, Skill, Agent, mcp__augmented__*, mcp__slack__*, mcp__telegram__*, mcp__direct_chat__*, mcp__xero__*, mcp__granola__*, mcp__composio_attio__*, mcp__composio_canva__*, mcp__composio_gmail__*, mcp__composio_googlecalendar__*, mcp__composio_googledocs__*, mcp__composio_googledrive__*, mcp__composio_googlesheets__*
3810
+ ---
3811
+
3812
+ You are dispatched by the parent agent to handle one channel message.
3813
+
3814
+ The parent passes you in the task description:
3815
+ - The full original message text
3816
+ - Channel metadata: Slack channel ID + thread_ts, Telegram chat_id + message_id, OR Direct Chat conversation_id
3817
+ - Any supporting context the parent thought relevant
3818
+
3819
+ Your job:
3820
+
3821
+ 1. Do the work the message asks for (Xero pull, research, multi-step skill, etc.). Use whichever tools you need.
3822
+ 2. Post the reply yourself via the matching channel tool \u2014 slack.reply for Slack, telegram.reply for Telegram, directchat.reply for Direct Chat. Use the metadata the parent gave you to address the right thread/conversation.
3823
+ 3. End. Do not do additional follow-up work; if more is needed, the user will send another message.
3824
+
3825
+ 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.
3826
+ `;
3827
+ }
3584
3828
  function buildMcpJson(input) {
3585
3829
  const mcpServers = {};
3586
3830
  const localMcpPath = join4(getHomeDir3(), ".augmented", "_mcp", "index.js");
@@ -3627,6 +3871,12 @@ function buildMcpJson(input) {
3627
3871
  }
3628
3872
  };
3629
3873
  }
3874
+ for (const integration of input.integrations ?? []) {
3875
+ const entry = buildRemoteMcpEntry(integration.definition_id);
3876
+ if (entry) {
3877
+ mcpServers[integration.definition_id] = entry;
3878
+ }
3879
+ }
3630
3880
  return { mcpServers };
3631
3881
  }
3632
3882
  function parseIntervalMinutes(scheduleEvery) {
@@ -3709,7 +3959,16 @@ var claudeCodeAdapter = {
3709
3959
  { relativePath: "settings.json", content: JSON.stringify(buildSettingsJson(input), null, 2) },
3710
3960
  { relativePath: ".mcp.json", content: JSON.stringify(buildMcpJson(input), null, 2) },
3711
3961
  { relativePath: "CHARTER.md", content: input.charterContent },
3712
- { relativePath: "TOOLS.md", content: input.toolsContent }
3962
+ { relativePath: "TOOLS.md", content: input.toolsContent },
3963
+ // ENG-4684: named subagent the parent uses for slow channel-message
3964
+ // handling. Frontmatter `background: true` makes the parent's listener
3965
+ // turn return immediately on dispatch, so new inbound messages get a
3966
+ // fresh turn while the subagent does the work in parallel. Triggered
3967
+ // by the "Channel message triage" instruction in CLAUDE.md.
3968
+ {
3969
+ relativePath: ".claude/agents/channel-message-handler.md",
3970
+ content: buildChannelMessageHandlerAgent()
3971
+ }
3713
3972
  ];
3714
3973
  const knowledgeEntries = input.knowledge ?? [];
3715
3974
  const delivery = input.knowledgeDelivery ?? "both";
@@ -4115,6 +4374,12 @@ ${sections}`
4115
4374
  }
4116
4375
  });
4117
4376
  }
4377
+ for (const integration of integrations) {
4378
+ const entry = buildRemoteMcpEntry(integration.definition_id);
4379
+ if (entry) {
4380
+ this.writeMcpServer(codeName, integration.definition_id, entry);
4381
+ }
4382
+ }
4118
4383
  const projectDir = getProjectDir(codeName);
4119
4384
  const claudeMdPath = join4(projectDir, "CLAUDE.md");
4120
4385
  try {
@@ -4185,6 +4450,11 @@ ${sections}`
4185
4450
  PIPEDREAM_PROJECT_ENVIRONMENT: headers["x-pd-environment"] ?? process.env["PIPEDREAM_ENVIRONMENT"] ?? "development"
4186
4451
  }
4187
4452
  };
4453
+ } else if (config.headers && Object.keys(config.headers).length > 0) {
4454
+ serverEntry = {
4455
+ url: config.url,
4456
+ headers: config.headers
4457
+ };
4188
4458
  } else {
4189
4459
  serverEntry = {
4190
4460
  command: "npx",
@@ -7697,4 +7967,4 @@ export {
7697
7967
  managerInstallCommand,
7698
7968
  managerUninstallCommand
7699
7969
  };
7700
- //# sourceMappingURL=chunk-P52H3XS6.js.map
7970
+ //# sourceMappingURL=chunk-HMN7YJOD.js.map