@yemi33/minions 0.1.1937 → 0.1.1939

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.
@@ -1,352 +0,0 @@
1
- # Teams Integration Setup
2
-
3
- End-to-end guide for connecting Minions to Microsoft Teams via Azure Bot Framework. After completing these steps, messages sent to a Teams channel will be routed to the Minions Command Center, and agent events (completions, PR merges, plan updates) will be posted back to Teams.
4
-
5
- **Prerequisites:**
6
-
7
- - An Azure subscription (free tier works)
8
- - Azure CLI installed (`az --version`) or access to the [Azure Portal](https://portal.azure.com)
9
- - Dev Tunnel CLI installed (`devtunnel --version`) — see [Step 5](#step-5-set-up-dev-tunnel) for installation
10
- - Minions dashboard running locally (`minions dash`)
11
- - Admin or owner permissions on the target Teams team (for side-loading)
12
-
13
- ## Step 1: Create an Azure Bot Resource
14
-
15
- 1. Open the [Azure Portal](https://portal.azure.com) and search for **Azure Bot** in the top search bar.
16
- 2. Click **Create**.
17
- 3. Fill in the basics:
18
- - **Bot handle**: A unique name (e.g., `minions-bot`). This is the internal identifier — it doesn't appear in Teams.
19
- - **Subscription**: Select your Azure subscription.
20
- - **Resource group**: Create a new one (e.g., `rg-minions`) or use an existing one.
21
- - **Data residency**: Choose **Global** unless you have regional compliance requirements.
22
- - **Pricing tier**: Select **F0 (Free)** for development.
23
- 4. Under **Microsoft App ID**, select **Single Tenant**.
24
- - Choose **Create new Microsoft App ID**.
25
- - This creates a new Entra ID (Azure AD) app registration for the bot.
26
-
27
- > **Why Single Tenant?** Single-tenant bots only accept tokens from your Azure AD tenant, which is more secure for an internal tool like Minions. Multi-tenant is needed only if the bot must work across organizations.
28
-
29
- 5. Click **Review + create**, then **Create**.
30
- 6. Wait for deployment to complete (usually under 1 minute), then click **Go to resource**.
31
-
32
- ## Step 2: Configure the Teams Channel
33
-
34
- 1. In your Azure Bot resource, click **Channels** in the left sidebar.
35
- 2. Click the **Microsoft Teams** icon in the available channels list.
36
- 3. Accept the Terms of Service.
37
- 4. Leave the channel settings at defaults:
38
- - **Messaging** tab: Enabled (default).
39
- - **Calling** and **Group Chat** tabs: Leave disabled unless needed.
40
- 5. Click **Apply**.
41
-
42
- The Teams channel should now appear as **Running** in the channels list.
43
-
44
- ## Step 3: Obtain App ID and App Password
45
-
46
- You need two credentials: the **App ID** (also called Microsoft App ID or Client ID) and the **App Password** (a client secret).
47
-
48
- ### Get the App ID
49
-
50
- 1. In your Azure Bot resource, click **Configuration** in the left sidebar.
51
- 2. Copy the **Microsoft App ID** value. This is a GUID like `a1b2c3d4-e5f6-7890-abcd-ef1234567890`.
52
- 3. Save it — you'll add it to your Minions config.
53
-
54
- ### Create an App Password (Client Secret)
55
-
56
- 1. On the same **Configuration** page, click **Manage Password** next to the Microsoft App ID. This opens the Entra ID app registration.
57
- 2. In the app registration, click **Certificates & secrets** in the left sidebar.
58
- 3. Click **New client secret**.
59
- 4. Enter a description (e.g., `minions-bot-secret`) and choose an expiry (e.g., 24 months).
60
- 5. Click **Add**.
61
- 6. **Immediately copy the secret Value** (not the Secret ID). It is shown only once — if you navigate away, you cannot retrieve it again.
62
-
63
- ### Add Credentials to Minions Config
64
-
65
- Add a `teams` section to your `config.json`:
66
-
67
- ```json
68
- {
69
- "projects": [ ... ],
70
- "agents": { ... },
71
- "engine": { ... },
72
- "teams": {
73
- "enabled": true,
74
- "appId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
75
- "appPassword": "your-client-secret-value-here",
76
- "notifyEvents": ["pr-merged", "agent-completed", "plan-completed", "agent-failed"],
77
- "ccMirror": true,
78
- "inboxPollInterval": 15000
79
- }
80
- }
81
- ```
82
-
83
- | Field | Description |
84
- |-------|-------------|
85
- | `enabled` | Master switch — `true` to activate Teams integration |
86
- | `appId` | Microsoft App ID from the Azure Bot Configuration page |
87
- | `appPassword` | Client secret value from Entra ID Certificates & secrets (leave blank for certificate auth) |
88
- | `certPath` | Path to PEM certificate file (certificate auth only) |
89
- | `privateKeyPath` | Path to PEM private key file (certificate auth only) |
90
- | `tenantId` | Azure AD tenant ID (required for certificate auth) |
91
- | `notifyEvents` | Which events trigger Teams notifications (see below) |
92
- | `ccMirror` | Mirror CC dashboard responses to Teams (`true`/`false`) |
93
- | `inboxPollInterval` | How often to check for new Teams messages, in ms (default: 15000) |
94
-
95
- **Available notification events:** `pr-merged`, `agent-completed`, `plan-completed`, `agent-failed`, `pr-abandoned`, `pr-approved`, `pr-build-failed`, `plan-approved`, `plan-rejected`, `verify-created`
96
-
97
- > **Security note:** `config.json` is gitignored by default and should never be committed. For shared machines, consider setting the app password via an environment variable and reading it in your config setup.
98
-
99
- ### Certificate Auth (Alternative to Client Secret)
100
-
101
- Some tenants prohibit creating client secrets in Entra ID. Use certificate-based authentication instead — no client secret needed.
102
-
103
- #### Generate a Self-Signed Certificate
104
-
105
- ```bash
106
- # Generate a private key and self-signed certificate (valid for 1 year)
107
- openssl req -x509 -newkey rsa:2048 -keyout bot-private-key.pem -out bot-cert.pem -days 365 -nodes -subj "/CN=minions-bot"
108
-
109
- # Verify the certificate
110
- openssl x509 -in bot-cert.pem -text -noout
111
- ```
112
-
113
- This creates two files:
114
- - `bot-cert.pem` — the public certificate (upload to Entra ID)
115
- - `bot-private-key.pem` — the private key (keep secret, do not commit)
116
-
117
- #### Upload the Certificate to Entra ID
118
-
119
- 1. In the [Azure Portal](https://portal.azure.com), go to **Entra ID** > **App registrations**.
120
- 2. Find and click the app registration for your bot (same App ID from Step 3).
121
- 3. Click **Certificates & secrets** in the left sidebar.
122
- 4. Click the **Certificates** tab, then **Upload certificate**.
123
- 5. Select your `bot-cert.pem` file and click **Add**.
124
-
125
- #### Configure Minions for Certificate Auth
126
-
127
- Use certificate fields instead of `appPassword` in your `config.json`:
128
-
129
- ```json
130
- {
131
- "teams": {
132
- "enabled": true,
133
- "appId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
134
- "certPath": "/path/to/bot-cert.pem",
135
- "privateKeyPath": "/path/to/bot-private-key.pem",
136
- "tenantId": "your-azure-ad-tenant-id",
137
- "notifyEvents": ["pr-merged", "agent-completed", "plan-completed", "agent-failed"],
138
- "ccMirror": true,
139
- "inboxPollInterval": 15000
140
- }
141
- }
142
- ```
143
-
144
- > **Finding your Tenant ID:** In the Azure Portal, go to **Entra ID** > **Overview**. The **Tenant ID** is listed under Basic Information.
145
-
146
- > When both `appPassword` and cert fields are configured, certificate auth takes precedence.
147
-
148
- ## Step 4: Set the Messaging Endpoint
149
-
150
- The messaging endpoint is the URL that Azure Bot Framework sends incoming messages to. It must point to your Minions dashboard's `/api/bot` route.
151
-
152
- 1. In your Azure Bot resource, click **Configuration** in the left sidebar.
153
- 2. Set the **Messaging endpoint** to:
154
- ```
155
- https://<your-tunnel-url>/api/bot
156
- ```
157
- For local development, this will be your Dev Tunnel URL (see [Step 5](#step-5-set-up-dev-tunnel)).
158
-
159
- For example: `https://abc123.devtunnels.ms/api/bot`
160
-
161
- 3. Click **Apply** to save.
162
-
163
- > The endpoint must be **HTTPS**. Bot Framework will not send messages to plain HTTP URLs. Dev Tunnels and production hosting (Azure App Service, etc.) both provide HTTPS by default.
164
-
165
- > Changes to the messaging endpoint take effect immediately — no need to reinstall the bot in Teams.
166
-
167
- ## Step 5: Set Up Dev Tunnel
168
-
169
- [Dev Tunnels](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/overview) create a public HTTPS URL that forwards traffic to your local machine. This lets Azure Bot Framework reach your locally running dashboard.
170
-
171
- ### Install Dev Tunnel CLI
172
-
173
- If you don't have it installed:
174
-
175
- ```bash
176
- # Windows (winget)
177
- winget install Microsoft.devtunnel
178
-
179
- # macOS (Homebrew)
180
- brew install --cask devtunnel
181
-
182
- # Linux (curl)
183
- curl -sL https://aka.ms/DevTunnelCliInstall | bash
184
- ```
185
-
186
- ### Authenticate
187
-
188
- ```bash
189
- devtunnel user login
190
- ```
191
-
192
- This opens a browser for Microsoft account authentication. Sign in with the same account that has access to your Azure subscription.
193
-
194
- ### Start the Tunnel
195
-
196
- ```bash
197
- devtunnel host -p 7331 --allow-anonymous
198
- ```
199
-
200
- - `-p 7331` forwards to the Minions dashboard port.
201
- - `--allow-anonymous` allows Bot Framework to reach the endpoint without additional auth (the Bot Framework adapter handles its own authentication via the App ID and Password).
202
-
203
- You'll see output like:
204
-
205
- ```
206
- Connect via browser: https://abc123.devtunnels.ms
207
- Inspect network activity: https://abc123-7331.devtunnels.ms
208
-
209
- Hosting port: 7331
210
- Connect via browser: https://abc123-7331.devtunnels.ms
211
- ```
212
-
213
- ### Copy the Forwarding URL to Azure Bot
214
-
215
- 1. Copy the **port-specific** tunnel URL from the output (e.g., `https://abc123-7331.devtunnels.ms`).
216
- 2. Go back to your Azure Bot resource > **Configuration**.
217
- 3. Set the **Messaging endpoint** to:
218
- ```
219
- https://abc123-7331.devtunnels.ms/api/bot
220
- ```
221
- 4. Click **Apply**.
222
-
223
- ### Persistent Tunnel (Optional)
224
-
225
- By default, the tunnel URL changes each time you restart `devtunnel host`. To get a persistent URL:
226
-
227
- ```bash
228
- # Create a named tunnel
229
- devtunnel create minions-tunnel
230
-
231
- # Add the port
232
- devtunnel port create minions-tunnel -p 7331
233
-
234
- # Host with anonymous access
235
- devtunnel host minions-tunnel --allow-anonymous
236
- ```
237
-
238
- The named tunnel keeps the same URL across restarts — you won't need to update the Azure Bot messaging endpoint each time.
239
-
240
- ### Verify Connectivity
241
-
242
- With the tunnel running and the dashboard started (`minions dash`), open the tunnel URL in a browser:
243
-
244
- ```
245
- https://abc123-7331.devtunnels.ms/api/routes
246
- ```
247
-
248
- You should see the Minions API route list as JSON. If you get a connection error, check that:
249
- - The dashboard is running (`minions dash`)
250
- - The tunnel is active (`devtunnel host` is still running)
251
- - The port number matches (7331)
252
-
253
- ## Step 6: Install the Bot in Teams
254
-
255
- There are two ways to add the bot to a Teams channel: via App Studio / Teams Developer Portal (recommended for development) or via the Teams Admin Center (for org-wide deployment).
256
-
257
- ### Option A: Teams Developer Portal (Recommended for Development)
258
-
259
- 1. Open [Teams Developer Portal](https://dev.teams.microsoft.com/apps) in a browser.
260
- 2. Click **New app**.
261
- 3. Fill in the app details:
262
- - **Name**: `Minions Bot` (or any display name)
263
- - **Short description**: `Minions agent orchestration`
264
- - **Developer name**: Your name or team name
265
- - **Website**: `https://github.com/yemi33/minions` (or any URL)
266
- - **Privacy policy** and **Terms of use**: Can be any URL for development
267
- 4. Under **App features**, click **Bot**.
268
- 5. Select **Enter a bot ID manually** and paste the **App ID** from [Step 3](#step-3-obtain-app-id-and-app-password).
269
- 6. Check the scopes:
270
- - **Team** — enables the bot in team channels
271
- - **Group chat** — optional, enables the bot in group chats
272
- 7. Click **Save**.
273
- 8. Click **Publish** > **Publish to your org** (or **Download app package** to side-load manually).
274
-
275
- ### Side-Load the App Package
276
-
277
- If your organization doesn't allow direct publishing:
278
-
279
- 1. In the Developer Portal, click **Download app package** to get a `.zip` file.
280
- 2. Open Microsoft Teams.
281
- 3. Click **Apps** in the left sidebar.
282
- 4. Click **Manage your apps** > **Upload an app**.
283
- 5. Select **Upload a custom app** (or **Upload a custom app for [org name]** if you have admin rights).
284
- 6. Choose the downloaded `.zip` file.
285
- 7. In the app details dialog, click **Add to a team**.
286
- 8. Select the team and channel where you want the bot.
287
- 9. Click **Set up a bot**.
288
-
289
- ### Option B: Teams Admin Center (Org-Wide Deployment)
290
-
291
- For deploying to all users or specific groups:
292
-
293
- 1. Open [Teams Admin Center](https://admin.teams.microsoft.com/).
294
- 2. Go to **Teams apps** > **Manage apps**.
295
- 3. Click **Upload new app** and upload the app package `.zip`.
296
- 4. Go to **Teams apps** > **Setup policies**.
297
- 5. Edit the relevant policy and add the Minions Bot to the **Installed apps** list.
298
-
299
- ### Verify the Bot Works
300
-
301
- 1. Open the Teams channel where you installed the bot.
302
- 2. Send a message that @mentions the bot:
303
- ```
304
- @Minions Bot hello
305
- ```
306
- 3. If everything is configured correctly, the message will:
307
- - Reach your dashboard via the Dev Tunnel
308
- - Be written to `engine/teams-inbox.json`
309
- - Be processed by the CC on the next poll cycle
310
- - The CC response will appear as a thread reply in Teams
311
-
312
- If you don't see a response, check:
313
- - **Dashboard logs**: Look for incoming `/api/bot` requests
314
- - **Dev Tunnel**: Ensure it's still running and the URL matches the Azure Bot messaging endpoint
315
- - **Azure Bot**: Test the bot connection in the Azure Portal via **Test in Web Chat** (Configuration page)
316
- - **Config**: Verify `config.json` has `teams.enabled: true` and correct `appId`/`appPassword`
317
-
318
- ## Troubleshooting
319
-
320
- ### "Unauthorized" or 401 Errors
321
-
322
- The App ID or App Password in `config.json` doesn't match what's registered in Azure. Double-check:
323
- - The App ID matches the Azure Bot's **Microsoft App ID** on the Configuration page.
324
- - The App Password is the client secret **Value** (not the Secret ID) from Entra ID.
325
- - The client secret hasn't expired.
326
-
327
- ### "Endpoint not reachable" in Azure Bot Test
328
-
329
- - Verify the Dev Tunnel is running: `devtunnel host -p 7331 --allow-anonymous`
330
- - Verify the messaging endpoint URL ends with `/api/bot`
331
- - Verify the dashboard is running: `minions dash`
332
- - Try opening the tunnel URL in a browser to confirm it's accessible
333
-
334
- ### Bot Doesn't Respond in Teams
335
-
336
- - Check `engine/teams-inbox.json` — if messages appear there, the webhook is working but the CC processing loop may not be running.
337
- - Check that the engine is running: `minions start`
338
- - Check the engine logs for Teams-related errors.
339
- - Ensure `config.teams.enabled` is `true`.
340
-
341
- ### "App not found" When Side-Loading
342
-
343
- - Your Teams admin may have disabled custom app side-loading. Contact your Teams admin to enable **Upload custom apps** in the Teams Admin Center > Setup policies.
344
- - Alternatively, ask an admin to upload the app via the Admin Center (Option B above).
345
-
346
- ## What's Next
347
-
348
- Once the bot is responding to messages in Teams:
349
-
350
- - **Agent notifications** will appear in the Teams channel when agents complete work, PRs are merged, or plans are finished.
351
- - **CC mirror** mode (enabled by default) posts Command Center responses from the dashboard to Teams so the whole team sees orchestration activity.
352
- - For production deployment (replacing Dev Tunnel with a stable public URL), see [docs/teams-production.md](teams-production.md).
@@ -1,137 +0,0 @@
1
- /**
2
- * engine/teams-cards.js — Adaptive Card templates for Teams notifications.
3
- * All cards use schema version 1.4 and include fallback text.
4
- */
5
-
6
- const SCHEMA = 'http://adaptivecards.io/schemas/adaptive-card.json';
7
- const VERSION = '1.4';
8
- const DASHBOARD_URL = 'http://localhost:7331';
9
-
10
- function wrapCard(body, actions, fallbackText) {
11
- return {
12
- type: 'AdaptiveCard',
13
- $schema: SCHEMA,
14
- version: VERSION,
15
- fallbackText: fallbackText || 'Minions notification',
16
- body,
17
- actions: actions || [],
18
- };
19
- }
20
-
21
- /**
22
- * Agent completion card — shows agent name, task title, result, PR link.
23
- * @param {string} agent — agent name/id
24
- * @param {object} item — { title, id }
25
- * @param {string} result — 'success' or 'error'
26
- * @param {string} [prUrl] — PR URL if available
27
- */
28
- function buildCompletionCard(agent, item, result, prUrl) {
29
- const isSuccess = result === 'success';
30
- const badge = isSuccess ? 'Done' : 'Failed';
31
- const color = isSuccess ? 'good' : 'attention';
32
- const title = item?.title || item?.id || 'Unknown task';
33
-
34
- const body = [
35
- { type: 'TextBlock', text: `${badge} — ${agent}`, weight: 'bolder', size: 'medium', color },
36
- { type: 'TextBlock', text: title, wrap: true },
37
- ];
38
-
39
- const actions = [
40
- { type: 'Action.OpenUrl', title: 'Open Dashboard', url: DASHBOARD_URL },
41
- ];
42
- if (prUrl) {
43
- actions.unshift({ type: 'Action.OpenUrl', title: 'View PR', url: prUrl });
44
- }
45
-
46
- return wrapCard(body, actions, `${badge}: ${agent} — ${title}`);
47
- }
48
-
49
- /**
50
- * PR lifecycle card — shows PR title, event, author, project.
51
- * @param {object} pr — { id, title, url, agent }
52
- * @param {string} event — 'pr-merged', 'pr-abandoned', 'build-failed', etc.
53
- * @param {object} [project] — { name }
54
- */
55
- function buildPrCard(pr, event, project) {
56
- const title = pr?.title || pr?.id || 'Unknown PR';
57
- const agent = pr?.agent || 'unknown';
58
- const projectName = project?.name || '';
59
-
60
- const body = [
61
- { type: 'TextBlock', text: `${event}`, weight: 'bolder', size: 'medium' },
62
- { type: 'ColumnSet', columns: [
63
- { type: 'Column', width: 'stretch', items: [
64
- { type: 'TextBlock', text: title, wrap: true, weight: 'bolder' },
65
- { type: 'TextBlock', text: `${agent}${projectName ? ' | ' + projectName : ''}`, isSubtle: true, spacing: 'none' },
66
- ]},
67
- ]},
68
- ];
69
-
70
- const actions = [
71
- { type: 'Action.OpenUrl', title: 'Open Dashboard', url: DASHBOARD_URL },
72
- ];
73
- if (pr?.url) {
74
- actions.unshift({ type: 'Action.OpenUrl', title: 'View PR', url: pr.url });
75
- }
76
-
77
- return wrapCard(body, actions, `${event}: ${title} (${agent})`);
78
- }
79
-
80
- /**
81
- * Plan lifecycle card — shows plan name, event, item counts.
82
- * @param {object} plan — { name, file, doneCount, totalCount }
83
- * @param {string} event — 'plan-completed', 'plan-approved', 'plan-rejected', 'verify-created'
84
- */
85
- function buildPlanCard(plan, event) {
86
- const name = plan?.name || plan?.file || 'Unknown plan';
87
- const hasCounts = plan?.doneCount != null && plan?.totalCount != null;
88
-
89
- const body = [
90
- { type: 'TextBlock', text: `${event}`, weight: 'bolder', size: 'medium' },
91
- { type: 'TextBlock', text: name, wrap: true },
92
- ];
93
-
94
- if (hasCounts) {
95
- body.push({ type: 'TextBlock', text: `${plan.doneCount}/${plan.totalCount} items completed`, isSubtle: true });
96
- }
97
-
98
- const actions = [
99
- { type: 'Action.OpenUrl', title: 'Open Dashboard', url: `${DASHBOARD_URL}/prd` },
100
- ];
101
-
102
- return wrapCard(body, actions, `${event}: ${name}${hasCounts ? ` (${plan.doneCount}/${plan.totalCount})` : ''}`);
103
- }
104
-
105
- /**
106
- * CC response mirror card — shows user question and CC answer.
107
- * @param {string} question — user's CC input
108
- * @param {string} answer — CC response (truncated if needed)
109
- */
110
- function buildCCResponseCard(question, answer) {
111
- const maxLen = 3000;
112
- const truncated = answer.length > maxLen
113
- ? answer.slice(0, maxLen) + '...'
114
- : answer;
115
-
116
- const body = [
117
- { type: 'TextBlock', text: 'Command Center', weight: 'bolder', size: 'medium' },
118
- { type: 'TextBlock', text: `> ${question.slice(0, 200)}`, wrap: true, isSubtle: true },
119
- { type: 'TextBlock', text: truncated, wrap: true },
120
- ];
121
-
122
- const actions = [
123
- { type: 'Action.OpenUrl', title: 'Open Dashboard', url: DASHBOARD_URL },
124
- ];
125
-
126
- return wrapCard(body, actions, `CC: ${question.slice(0, 100)} — ${answer.slice(0, 200)}`);
127
- }
128
-
129
- module.exports = {
130
- buildCompletionCard,
131
- buildPrCard,
132
- buildPlanCard,
133
- buildCCResponseCard,
134
- SCHEMA,
135
- VERSION,
136
- DASHBOARD_URL,
137
- };