@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.
- package/README.md +0 -2
- package/dashboard/js/render-utils.js +3 -1
- package/dashboard/js/settings.js +1 -36
- package/dashboard.js +1 -131
- package/docs/README.md +1 -3
- package/docs/deprecated.json +24 -0
- package/docs/distribution.md +32 -1
- package/docs/rfc-completion-json.md +4 -4
- package/engine/ado.js +0 -17
- package/engine/cc-worker-pool.js +30 -42
- package/engine/cli.js +0 -14
- package/engine/github.js +0 -17
- package/engine/lifecycle.js +0 -29
- package/engine/preflight.js +0 -19
- package/engine/shared.js +0 -13
- package/package.json +1 -4
- package/docs/teams-production.md +0 -370
- package/docs/teams-setup.md +0 -352
- package/engine/teams-cards.js +0 -137
- package/engine/teams.js +0 -647
package/docs/teams-setup.md
DELETED
|
@@ -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).
|
package/engine/teams-cards.js
DELETED
|
@@ -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
|
-
};
|