Fix #9 #12: Add configuration to disable subagent notifications (#10)

* Add configuration option to disable subagent notifications

- Added 'enableSubagentNotifications' config option (default: false)
- Modified notification handler to check config before sending subagent notifications
- Created documentation explaining the feature
- Updated README with note about subagent notifications

This addresses the issue where frequent subagent notifications can be distracting.
Users can now control whether they receive notifications when subagents stop/start.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add subagent activity tracking in completion emails

- Track subagent activities instead of sending individual notifications
- Include subagent activity summary in completion emails
- Update email templates to display subagent activities
- Add SubagentTracker utility to manage activity tracking
- Update documentation to explain the new behavior

This provides a better user experience by:
1. Reducing notification noise from frequent subagent activities
2. Still providing full visibility into what subagents did
3. Consolidating all information in the completion email

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Improve subagent activity details and documentation

- Enhanced activity capture to include up to 1000 characters (was 200)
- Improved email display format with better visual separation
- Added detection for initialization-only captures with helpful message
- Added configuration option for activity detail level
- Created comprehensive documentation explaining the timing limitation
- Added visual indicators for processing status

This addresses the issue where subagent outputs were truncated or only
showed initialization messages. Users now get better visibility into
what subagents are doing, with clear indication when full output is
available in tmux.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* delete redundant files and modify README

* Fix HTML escaping in email notifications

- Add _escapeHtml function to properly escape HTML entities in emails
- Escape user-generated content to prevent HTML tags from being hidden
- Fix issue where <developer> and other HTML-like strings disappeared in emails
- Apply escaping to both main email content and subagent activity summaries

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Song-Ze Yu 2025-08-01 14:49:48 +08:00 committed by GitHub
parent 3d2a26286c
commit 5159e53eaa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 294 additions and 871 deletions

View File

@ -28,9 +28,9 @@ Control [Claude Code](https://claude.ai/code) remotely via email. Start tasks lo
## 📅 Changelog ## 📅 Changelog
### January 2025 ### January 2025
- **2025-01-15**: Implement terminal-style UI for email notifications ([#8](https://github.com/JessyTsui/Claude-Code-Remote/pull/8) by [@vaclisinc](https://github.com/vaclisinc)) - **2025-08-01**: Implement terminal-style UI for email notifications ([#8](https://github.com/JessyTsui/Claude-Code-Remote/pull/8) by [@vaclisinc](https://github.com/vaclisinc))
- **2025-01-15**: Fix working directory issue - enable claude-remote to run from any directory ([#7](https://github.com/JessyTsui/Claude-Code-Remote/pull/7) by [@vaclisinc](https://github.com/vaclisinc)) - **2025-08-01**: Fix working directory issue - enable claude-remote to run from any directory ([#7](https://github.com/JessyTsui/Claude-Code-Remote/pull/7) by [@vaclisinc](https://github.com/vaclisinc))
- **2025-01-14**: Fix self-reply loop issue when using same email for send/receive ([#4](https://github.com/JessyTsui/Claude-Code-Remote/pull/4) by [@vaclisinc](https://github.com/vaclisinc)) - **2025-07-31**: Fix self-reply loop issue when using same email for send/receive ([#4](https://github.com/JessyTsui/Claude-Code-Remote/pull/4) by [@vaclisinc](https://github.com/vaclisinc))
### July 2025 ### July 2025
- **2025-07-28**: Remove hardcoded values and implement environment-based configuration ([#2](https://github.com/JessyTsui/Claude-Code-Remote/pull/2) by [@kevinsslin](https://github.com/kevinsslin)) - **2025-07-28**: Remove hardcoded values and implement environment-based configuration ([#2](https://github.com/JessyTsui/Claude-Code-Remote/pull/2) by [@kevinsslin](https://github.com/kevinsslin))
@ -99,6 +99,7 @@ SESSION_MAP_PATH=/your/absolute/path/to/Claude-Code-Remote/src/data/session-map.
``` ```
📌 **Gmail users**: Create an [App Password](https://myaccount.google.com/security) instead of using your regular password. 📌 **Gmail users**: Create an [App Password](https://myaccount.google.com/security) instead of using your regular password.
> Note: You may need to enable two-step verification in your google account first before create app password.
### Step 3: Set Up Claude Code Hooks ### Step 3: Set Up Claude Code Hooks
@ -137,6 +138,8 @@ Add this configuration (replace `/your/absolute/path/` with your actual path):
} }
``` ```
> **Note**: Subagent notifications are disabled by default. To enable them, set `enableSubagentNotifications: true` in your config. See [Subagent Notifications Guide](./docs/SUBAGENT_NOTIFICATIONS.md) for details.
### Step 4: Test Your Setup ### Step 4: Test Your Setup
```bash ```bash

View File

@ -116,6 +116,62 @@ class ClaudeCodeRemoteCLI {
// Automatically capture current tmux session conversation content // Automatically capture current tmux session conversation content
const metadata = await this.captureCurrentConversation(); const metadata = await this.captureCurrentConversation();
// Handle subagent notifications
if (type === 'waiting') {
const Config = require('./src/core/config');
const config = new Config();
config.load();
const enableSubagentNotifications = config.get('enableSubagentNotifications', false);
if (!enableSubagentNotifications) {
// Instead of skipping, track the subagent activity
const SubagentTracker = require('./src/utils/subagent-tracker');
const tracker = new SubagentTracker();
// Use tmux session as the tracking key
const trackingKey = metadata.tmuxSession || 'default';
// Capture more detailed information about the subagent activity
const activityDetails = {
userQuestion: metadata.userQuestion || 'No question captured',
claudeResponse: metadata.claudeResponse || 'No response captured',
timestamp: new Date().toISOString(),
tmuxSession: metadata.tmuxSession
};
// Don't truncate the response too aggressively
if (activityDetails.claudeResponse && activityDetails.claudeResponse.length > 1000) {
activityDetails.claudeResponse = activityDetails.claudeResponse.substring(0, 1000) + '...[see full output in tmux]';
}
tracker.addActivity(trackingKey, {
type: 'SubagentStop',
description: metadata.userQuestion || 'Subagent task',
details: activityDetails
});
this.logger.info(`Subagent activity tracked for tmux session: ${trackingKey}`);
process.exit(0);
}
}
// For completed notifications, include subagent activities
if (type === 'completed') {
const SubagentTracker = require('./src/utils/subagent-tracker');
const tracker = new SubagentTracker();
const trackingKey = metadata.tmuxSession || 'default';
// Get and format subagent activities
const subagentSummary = tracker.formatActivitiesForEmail(trackingKey);
if (subagentSummary) {
metadata.subagentActivities = subagentSummary;
this.logger.info('Including subagent activities in completion email');
// Clear activities after including them
tracker.clearActivities(trackingKey);
}
}
const result = await this.notifier.notify(type, metadata); const result = await this.notifier.notify(type, metadata);
if (result.success) { if (result.success) {

View File

@ -5,6 +5,8 @@
"waiting": "Hero" "waiting": "Hero"
}, },
"enabled": true, "enabled": true,
"enableSubagentNotifications": false,
"subagentActivityDetail": "medium",
"timeout": 5, "timeout": 5,
"customMessages": { "customMessages": {
"completed": null, "completed": null,

View File

@ -24,6 +24,18 @@ class EmailChannel extends NotificationChannel {
this._initializeTransporter(); this._initializeTransporter();
} }
_escapeHtml(text) {
if (!text) return '';
const htmlEntities = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;'
};
return text.replace(/[&<>"']/g, char => htmlEntities[char]);
}
_ensureDirectories() { _ensureDirectories() {
if (!fs.existsSync(this.sessionsDir)) { if (!fs.existsSync(this.sessionsDir)) {
fs.mkdirSync(this.sessionsDir, { recursive: true }); fs.mkdirSync(this.sessionsDir, { recursive: true });
@ -286,7 +298,8 @@ class EmailChannel extends NotificationChannel {
userQuestion: userQuestion || 'No specified task', userQuestion: userQuestion || 'No specified task',
claudeResponse: claudeResponse || notification.message, claudeResponse: claudeResponse || notification.message,
projectDir: projectDir, projectDir: projectDir,
shortQuestion: shortQuestion || 'No specific question' shortQuestion: shortQuestion || 'No specific question',
subagentActivities: notification.metadata?.subagentActivities || ''
}; };
let subject = enhancedSubject; let subject = enhancedSubject;
@ -297,7 +310,9 @@ class EmailChannel extends NotificationChannel {
Object.keys(variables).forEach(key => { Object.keys(variables).forEach(key => {
const placeholder = new RegExp(`{{${key}}}`, 'g'); const placeholder = new RegExp(`{{${key}}}`, 'g');
subject = subject.replace(placeholder, variables[key]); subject = subject.replace(placeholder, variables[key]);
html = html.replace(placeholder, variables[key]); // Escape HTML entities for HTML content
html = html.replace(placeholder, this._escapeHtml(variables[key]));
// No escaping needed for plain text
text = text.replace(placeholder, variables[key]); text = text.replace(placeholder, variables[key]);
}); });
@ -356,6 +371,8 @@ class EmailChannel extends NotificationChannel {
</div> </div>
</div> </div>
{{subagentActivities}}
<!-- Continue Instructions --> <!-- Continue Instructions -->
<div style="margin: 30px 0 20px 0; border-top: 1px solid #333; padding-top: 20px;"> <div style="margin: 30px 0 20px 0; border-top: 1px solid #333; padding-top: 20px;">
<span style="color: #999;">$</span> <span style="color: #00ff00;">claude-code help --continue</span><br> <span style="color: #999;">$</span> <span style="color: #00ff00;">claude-code help --continue</span><br>
@ -398,6 +415,8 @@ Status: {{type}}
🤖 Claude's Response: 🤖 Claude's Response:
{{claudeResponse}} {{claudeResponse}}
{{subagentActivities}}
How to Continue Conversation: How to Continue Conversation:
To continue conversation with Claude Code, please reply to this email directly and enter your instructions in the email body. To continue conversation with Claude Code, please reply to this email directly and enter your instructions in the email body.

View File

@ -1,137 +1,3 @@
{ {
"messages": [ "messages": []
{
"messageId": "<52d15aa1-d5a4-4d7d-8f01-4752d7d5fc6f-1754021037319@claude-code-remote>",
"sessionId": "52d15aa1-d5a4-4d7d-8f01-4752d7d5fc6f",
"token": "49WUF9NS",
"type": "notification",
"sentAt": "2025-08-01T04:03:59.850Z"
},
{
"messageId": "<eba8744e-8cc1-4fad-9dc8-69d558c51cca-1754021210179@claude-code-remote>",
"sessionId": "eba8744e-8cc1-4fad-9dc8-69d558c51cca",
"token": "N9PHUN4Q",
"type": "notification",
"sentAt": "2025-08-01T04:06:52.776Z"
},
{
"messageId": "<859daa99-1ea9-4c40-aa68-c3967a0d7e4e-1754021233658@claude-code-remote>",
"sessionId": "859daa99-1ea9-4c40-aa68-c3967a0d7e4e",
"token": "GXWFSL3S",
"type": "notification",
"sentAt": "2025-08-01T04:07:15.556Z"
},
{
"messageId": "<a1ed6757-6782-4b22-a486-aab5a9d60a3c-1754021267945@claude-code-remote>",
"sessionId": "a1ed6757-6782-4b22-a486-aab5a9d60a3c",
"token": "6EZXA6IN",
"type": "notification",
"sentAt": "2025-08-01T04:07:49.959Z"
},
{
"messageId": "<2122d57c-8434-44f0-b4e6-7eafb40ed49d-1754021285815@claude-code-remote>",
"sessionId": "2122d57c-8434-44f0-b4e6-7eafb40ed49d",
"token": "ZQY1UOIJ",
"type": "notification",
"sentAt": "2025-08-01T04:08:07.833Z"
},
{
"messageId": "<2b30b1f7-b9c3-4cb4-b889-11c58009bd07-1754021533703@claude-code-remote>",
"sessionId": "2b30b1f7-b9c3-4cb4-b889-11c58009bd07",
"token": "L4KQ8DVJ",
"type": "notification",
"sentAt": "2025-08-01T04:12:15.795Z"
},
{
"messageId": "<e3392712-9a5b-4c96-a23c-5d97c226b415-1754022640364@claude-code-remote>",
"sessionId": "e3392712-9a5b-4c96-a23c-5d97c226b415",
"token": "7ZFMSK5P",
"type": "notification",
"sentAt": "2025-08-01T04:30:41.978Z"
},
{
"messageId": "<5d19da23-5c9d-4855-824e-fbd09a0d986c-1754022731688@claude-code-remote>",
"sessionId": "5d19da23-5c9d-4855-824e-fbd09a0d986c",
"token": "PJOE746Q",
"type": "notification",
"sentAt": "2025-08-01T04:32:13.100Z"
},
{
"messageId": "<ed814c4b-0b97-4e10-8ad1-dae1a7cb7ef9-1754022927776@claude-code-remote>",
"sessionId": "ed814c4b-0b97-4e10-8ad1-dae1a7cb7ef9",
"token": "C9I24JHD",
"type": "notification",
"sentAt": "2025-08-01T04:35:28.987Z"
},
{
"messageId": "<46ae2185-2f70-4355-a3b8-9fc04fa01181-1754023256348@claude-code-remote>",
"sessionId": "46ae2185-2f70-4355-a3b8-9fc04fa01181",
"token": "GGBKJ2DV",
"type": "notification",
"sentAt": "2025-08-01T04:40:58.066Z"
},
{
"messageId": "<49c51c77-8ecc-4a04-a7a8-5955f89411b1-1754023825872@claude-code-remote>",
"sessionId": "49c51c77-8ecc-4a04-a7a8-5955f89411b1",
"token": "DQH198YY",
"type": "notification",
"sentAt": "2025-08-01T04:50:27.443Z"
},
{
"messageId": "<cc5a1eba-7e04-44e6-919f-0395ddf2ee08-1754024054719@claude-code-remote>",
"sessionId": "cc5a1eba-7e04-44e6-919f-0395ddf2ee08",
"token": "GQE6LLIF",
"type": "notification",
"sentAt": "2025-08-01T04:54:16.491Z"
},
{
"messageId": "<63198b90-3b9d-4448-a932-7c39c771554a-1754024273245@claude-code-remote>",
"sessionId": "63198b90-3b9d-4448-a932-7c39c771554a",
"token": "WYKEGTXV",
"type": "notification",
"sentAt": "2025-08-01T04:57:54.938Z"
},
{
"messageId": "<bfd8b8d0-bcc4-4336-a6eb-8ca3f8b6c96e-1754025557415@claude-code-remote>",
"sessionId": "bfd8b8d0-bcc4-4336-a6eb-8ca3f8b6c96e",
"token": "ATUBLIN1",
"type": "notification",
"sentAt": "2025-08-01T05:19:18.866Z"
},
{
"messageId": "<cdbfc3f9-e27e-47d9-82b9-9058f0180fff-1754025634473@claude-code-remote>",
"sessionId": "cdbfc3f9-e27e-47d9-82b9-9058f0180fff",
"token": "2W24RZTM",
"type": "notification",
"sentAt": "2025-08-01T05:20:35.851Z"
},
{
"messageId": "<cf18cb3b-bc72-46ea-985f-2b7f29f0993f-1754025855175@claude-code-remote>",
"sessionId": "cf18cb3b-bc72-46ea-985f-2b7f29f0993f",
"token": "PHAVU604",
"type": "notification",
"sentAt": "2025-08-01T05:24:16.539Z"
},
{
"messageId": "<6da5d6f6-7e68-47eb-8676-175d77f0ddbc-1754026029245@claude-code-remote>",
"sessionId": "6da5d6f6-7e68-47eb-8676-175d77f0ddbc",
"token": "C2APCY3V",
"type": "notification",
"sentAt": "2025-08-01T05:27:10.601Z"
},
{
"messageId": "<9143d717-be05-4869-b40a-2c775addcfc4-1754026119754@claude-code-remote>",
"sessionId": "9143d717-be05-4869-b40a-2c775addcfc4",
"token": "N5P4GUG3",
"type": "notification",
"sentAt": "2025-08-01T05:28:41.439Z"
},
{
"messageId": "<6fb2932d-d4ac-427b-8b7d-54af44fee1f2-1754026220881@claude-code-remote>",
"sessionId": "6fb2932d-d4ac-427b-8b7d-54af44fee1f2",
"token": "CZIKHCFO",
"type": "notification",
"sentAt": "2025-08-01T05:30:22.303Z"
}
]
} }

View File

@ -1,731 +1 @@
{ {}
"7HUMGXOT": {
"type": "pty",
"createdAt": 1753601264,
"expiresAt": 1753687664,
"cwd": "/Users/jessytsui/dev/TaskPing",
"sessionId": "3248adc2-eb7b-4eb2-a57c-b9ce320cb4ec",
"tmuxSession": "hailuo",
"description": "completed - TaskPing"
},
"5CLDW6NQ": {
"type": "pty",
"createdAt": 1753602124,
"expiresAt": 1753688524,
"cwd": "/Users/jessytsui/dev/TaskPing",
"sessionId": "c7b6750f-6246-4ed3-bca5-81201ab980ee",
"tmuxSession": "hailuo",
"description": "completed - TaskPing"
},
"ONY66DAE": {
"type": "pty",
"createdAt": 1753604311,
"expiresAt": 1753690711,
"cwd": "/Users/jessytsui/dev/TaskPing",
"sessionId": "2a8622dd-a0e9-4f4d-9cc8-a3bb432e9621",
"tmuxSession": "hailuo",
"description": "waiting - TaskPing"
},
"QHFI9FIJ": {
"type": "pty",
"createdAt": 1753607753,
"expiresAt": 1753694153,
"cwd": "/Users/jessytsui/dev/TaskPing",
"sessionId": "a966681d-5cfd-47b9-bb1b-c7ee9655b97b",
"tmuxSession": "a-0",
"description": "waiting - TaskPing"
},
"G3QE3STQ": {
"type": "pty",
"createdAt": 1753622403,
"expiresAt": 1753708803,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "7f6e11b3-0ac9-44b1-a75f-d3a15a8ec46e",
"tmuxSession": "claude-taskping",
"description": "completed - TaskPing-Test"
},
"Z0Q98XCC": {
"type": "pty",
"createdAt": 1753624374,
"expiresAt": 1753710774,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "b2408839-8a64-4a07-8ceb-4a7a82ea5b25",
"tmuxSession": "claude-taskping",
"description": "completed - TaskPing-Test"
},
"65S5UGHZ": {
"type": "pty",
"createdAt": 1753624496,
"expiresAt": 1753710896,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "117a1097-dd97-41ab-a276-e4820adc8da8",
"tmuxSession": "claude-taskping",
"description": "completed - Claude-Code-Remote"
},
"N9PPKGTO": {
"type": "pty",
"createdAt": 1753624605,
"expiresAt": 1753711005,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "0caed3af-35ae-4b42-9081-b1a959735bde",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"TEST12345": {
"type": "pty",
"createdAt": 1753628000,
"expiresAt": 1753714400,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "test-session-id",
"tmuxSession": "test-claude",
"description": "testing - Test Session"
},
"YTGT6F6F": {
"type": "pty",
"createdAt": 1753625040,
"expiresAt": 1753711440,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "e6e973b6-20dd-497f-a988-02482af63336",
"tmuxSession": "claude-taskping",
"description": "completed - Claude-Code-Remote"
},
"2XQP1N0P": {
"type": "pty",
"createdAt": 1753625361,
"expiresAt": 1753711761,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "0f694f4c-f8a4-476a-946a-3dc057c3bc46",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"GKPSGCBS": {
"type": "pty",
"createdAt": 1753625618,
"expiresAt": 1753712018,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "e844d2ae-9098-4528-9e05-e77904a35be3",
"tmuxSession": "claude-taskping",
"description": "completed - Claude-Code-Remote"
},
"187JDGZ0": {
"type": "pty",
"createdAt": 1753625623,
"expiresAt": 1753712023,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "633a2687-81e7-456e-9995-3321ce3f3b2b",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"NSYKTAWC": {
"type": "pty",
"createdAt": 1753625650,
"expiresAt": 1753712050,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "b8dac307-8b4b-4286-aa73-324b9b659e60",
"tmuxSession": "claude-taskping",
"description": "completed - Claude-Code-Remote"
},
"1NTEJPH7": {
"type": "pty",
"createdAt": 1753625743,
"expiresAt": 1753712143,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "09466a43-c495-4a30-ac08-eb425748a28c",
"tmuxSession": "claude-taskping",
"description": "completed - Claude-Code-Remote"
},
"5XO64F9Z": {
"type": "pty",
"createdAt": 1753625846,
"expiresAt": 1753712246,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "99132172-7a97-46f7-b282-b22054d6e599",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"D8561S3A": {
"type": "pty",
"createdAt": 1753625904,
"expiresAt": 1753712304,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "772628f1-414b-4242-bc8f-660ad53b6c23",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"GR0GED2E": {
"type": "pty",
"createdAt": 1753626215,
"expiresAt": 1753712615,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "da40ba76-7047-41e0-95f2-081db87c1b3b",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"TTRQKVM9": {
"type": "pty",
"createdAt": 1753626245,
"expiresAt": 1753712645,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "c7c5c95d-4541-47f6-b27a-35c0fd563413",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"P9UBHY8L": {
"type": "pty",
"createdAt": 1753626325,
"expiresAt": 1753712725,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "a3f2b4f9-811e-4721-914f-f025919c2530",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"JQAOXCYJ": {
"type": "pty",
"createdAt": 1753626390,
"expiresAt": 1753712790,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "f0d0635b-59f2-45eb-acfc-d649b12fd2d6",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"B7R9OR3K": {
"type": "pty",
"createdAt": 1753626445,
"expiresAt": 1753712845,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "d33e49aa-a58f-46b0-8829-dfef7f474600",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"0KGM60XO": {
"type": "pty",
"createdAt": 1753626569,
"expiresAt": 1753712969,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "02bd4449-bdcf-464e-916e-61bc62a18dd2",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"5NXM173C": {
"type": "pty",
"createdAt": 1753626834,
"expiresAt": 1753713234,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "f8f915ee-ab64-471c-b3d2-71cb84d2b5fe",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"FU0A5E79": {
"type": "pty",
"createdAt": 1753627838,
"expiresAt": 1753714238,
"cwd": "/Users/jessytsui/dev/coverr_video",
"sessionId": "1df42826-eb8e-47ee-bc5a-5886a1234d84",
"tmuxSession": "video",
"description": "completed - coverr_video"
},
"W3Y4UNV2": {
"type": "pty",
"createdAt": 1753627955,
"expiresAt": 1753714355,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "23f16dc9-4668-4f34-b650-7919d325efd9",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"69PWGS1L": {
"type": "pty",
"createdAt": 1753628092,
"expiresAt": 1753714492,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "8e847e83-677c-4b6a-9be8-184615731c9a",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"BP5WJBYZ": {
"type": "pty",
"createdAt": 1753631837,
"expiresAt": 1753718237,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "0c7ba308-f6da-44bc-a622-8bdb4c7613a5",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"IS18V1WH": {
"type": "pty",
"createdAt": 1753631949,
"expiresAt": 1753718349,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "563a4b27-f459-40fa-aa7b-df9c46643bab",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"QGLEAJLO": {
"type": "pty",
"createdAt": 1753632059,
"expiresAt": 1753718459,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "e81186b8-c990-42a7-a1ec-16009e671f32",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"66VKI9JR": {
"type": "pty",
"createdAt": 1753633791,
"expiresAt": 1753720191,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "29afd212-bfbb-443e-8e9f-7c4a08a9f178",
"tmuxSession": "claude-taskping",
"description": "completed - Claude-Code-Remote"
},
"MROLF6JQ": {
"type": "pty",
"createdAt": 1753633885,
"expiresAt": 1753720285,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "6856d493-a825-45e9-ad87-d3dab6ebd3ed",
"tmuxSession": "claude-taskping",
"description": "completed - Claude-Code-Remote"
},
"JH6IROYI": {
"type": "pty",
"createdAt": 1753635239,
"expiresAt": 1753721639,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "40829580-9b42-45c2-af54-994343101a4b",
"tmuxSession": "claude-taskping",
"description": "completed - Claude-Code-Remote"
},
"18E1GX7G": {
"type": "pty",
"createdAt": 1753635293,
"expiresAt": 1753721693,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "d9524fbe-8915-4175-89e0-9358ccd86921",
"tmuxSession": "claude-taskping",
"description": "completed - Claude-Code-Remote"
},
"8CZC4SWF": {
"type": "pty",
"createdAt": 1753635381,
"expiresAt": 1753721781,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "5d7673c5-5541-4c71-8f33-8270cde90376",
"tmuxSession": "claude-taskping",
"description": "completed - Claude-Code-Remote"
},
"L40V7BIU": {
"type": "pty",
"createdAt": 1753636194,
"expiresAt": 1753722594,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "b4112f01-a8f5-44fe-8bb6-85b1f16d5cd9",
"tmuxSession": "claude-taskping",
"description": "completed - Claude-Code-Remote"
},
"X0PKR9KZ": {
"type": "pty",
"createdAt": 1753636706,
"expiresAt": 1753723106,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "77747aee-ec17-4356-86be-ca20245eaa4c",
"tmuxSession": "claude-taskping",
"description": "completed - Claude-Code-Remote"
},
"K3G8GEM4": {
"type": "pty",
"createdAt": 1753636765,
"expiresAt": 1753723165,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "5b70bf42-ed29-4004-afad-a337be665c74",
"tmuxSession": "claude-taskping",
"description": "completed - Claude-Code-Remote"
},
"1U1074XQ": {
"type": "pty",
"createdAt": 1753636941,
"expiresAt": 1753723341,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "212bd122-ff8e-4299-88cc-93fed221ad2b",
"tmuxSession": "claude-taskping",
"description": "completed - Claude-Code-Remote"
},
"04Z5FEHE": {
"type": "pty",
"createdAt": 1753637049,
"expiresAt": 1753723449,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "da16cada-9121-47c7-b7b8-4b47cbc46c7c",
"tmuxSession": "claude-taskping",
"description": "completed - Claude-Code-Remote"
},
"MSRLCGLS": {
"type": "pty",
"createdAt": 1753638288,
"expiresAt": 1753724688,
"cwd": "/Users/jessytsui",
"sessionId": "d245e06c-9595-48f9-8ef1-c3f826352d75",
"tmuxSession": "claude-taskping",
"description": "completed - jessytsui"
},
"7O21O9ZR": {
"type": "pty",
"createdAt": 1753638308,
"expiresAt": 1753724708,
"cwd": "/Users/jessytsui",
"sessionId": "6ec8789d-5eb0-4138-9180-f32559336906",
"tmuxSession": "claude-taskping",
"description": "completed - jessytsui"
},
"4S5KSCI3": {
"type": "pty",
"createdAt": 1753639559,
"expiresAt": 1753725959,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "302103bd-522f-4349-8041-979a62c606d8",
"tmuxSession": "claude-code-remote",
"description": "completed - Claude-Code-Remote"
},
"VR3AB0NO": {
"type": "pty",
"createdAt": 1753640175,
"expiresAt": 1753726575,
"cwd": "/Users/jessytsui/dev/coverr_video",
"sessionId": "6808bb5d-4268-4f46-aad7-0f01677f781e",
"tmuxSession": "claude-code-remote",
"description": "completed - coverr_video"
},
"RACVYH67": {
"type": "pty",
"createdAt": 1753640283,
"expiresAt": 1753726683,
"cwd": "/Users/jessytsui/dev/coverr_video",
"sessionId": "4d23ece0-6931-4d6d-bb89-b2ba2709bba6",
"tmuxSession": "claude-code-remote",
"description": "completed - coverr_video"
},
"XBUMC8TX": {
"type": "pty",
"createdAt": 1753640359,
"expiresAt": 1753726759,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "50436697-1576-4f70-9ea7-39ae61261192",
"tmuxSession": "claude-code-remote",
"description": "completed - Claude-Code-Remote"
},
"6L3BS2G9": {
"type": "pty",
"createdAt": 1753640370,
"expiresAt": 1753726770,
"cwd": "/Users/jessytsui/dev/coverr_video",
"sessionId": "5ec3baf8-8dcd-44b6-9583-4fac336c92e2",
"tmuxSession": "claude-code-remote",
"description": "completed - coverr_video"
},
"ODFO312K": {
"type": "pty",
"createdAt": 1753640410,
"expiresAt": 1753726810,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "616f15e8-0ae6-4a3b-ac02-373bca701630",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"6XWPQCEF": {
"type": "pty",
"createdAt": 1753640528,
"expiresAt": 1753726928,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "b6d2d75b-c4b7-46cb-b922-d4f935e5424d",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"ZGXY36O1": {
"type": "pty",
"createdAt": 1753640690,
"expiresAt": 1753727090,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "3ce40b4d-3273-4662-a6cf-ead30c91f950",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"MUE5LCUY": {
"type": "pty",
"createdAt": 1753684860,
"expiresAt": 1753771260,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "698b6d2e-32f0-4eaa-8aa4-5bbf408b9640",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"KZVOG2PO": {
"type": "pty",
"createdAt": 1753684912,
"expiresAt": 1753771312,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "0f63ad7f-2312-427f-b1e6-d186a6be3667",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"5HDFXY41": {
"type": "pty",
"createdAt": 1753684929,
"expiresAt": 1753771329,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "22481ebb-0f9f-4f52-9668-347ed0fb0f98",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"NHXQJN3L": {
"type": "pty",
"createdAt": 1753685042,
"expiresAt": 1753771442,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "a1b56007-ef57-48bb-8aa7-449bc5f9b1f7",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"84LX5NLI": {
"type": "pty",
"createdAt": 1753685161,
"expiresAt": 1753771561,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "3535a857-c5da-4764-9367-9816955bfc30",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"3WYHK10U": {
"type": "pty",
"createdAt": 1753685478,
"expiresAt": 1753771878,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "68eca4f9-79f4-4047-ab98-636cd742deee",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"INZLQTW0": {
"type": "pty",
"createdAt": 1753685542,
"expiresAt": 1753771942,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "4bc09041-a751-43c0-93e1-f3b5a69d6aa1",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"TPV9W6VE": {
"type": "pty",
"createdAt": 1753685640,
"expiresAt": 1753772040,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "023bb55f-acc0-4d8a-a2f4-79be0bd9a863",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"IUNWWLOT": {
"type": "pty",
"createdAt": 1753685816,
"expiresAt": 1753772216,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "4e67ac76-5c0a-4229-b3cd-c4ff865c9df3",
"tmuxSession": "video",
"description": "completed - Claude-Code-Remote"
},
"3E0T4KHA": {
"type": "pty",
"createdAt": 1754020190,
"expiresAt": 1754106590,
"cwd": "/Users/vaclis./Documents/project/Claude-Code-Remote",
"sessionId": "1ce6c5e0-4151-4d51-9472-f481ed23f023",
"tmuxSession": "WavJaby",
"description": "completed - Claude-Code-Remote"
},
"8BIFRACK": {
"type": "pty",
"createdAt": 1754020301,
"expiresAt": 1754106701,
"cwd": "/Users/vaclis./Documents/project/ReThreads",
"sessionId": "0fd97a36-da77-4c9b-917f-6963c0373458",
"tmuxSession": "my-project",
"description": "completed - ReThreads"
},
"OG1SS2R9": {
"type": "pty",
"createdAt": 1754020306,
"expiresAt": 1754106706,
"cwd": "/Users/vaclis./Documents/project/Claude-Code-Remote",
"sessionId": "43b979a7-9039-4d0f-8c09-b86365ef0e61",
"tmuxSession": "WavJaby",
"description": "completed - Claude-Code-Remote"
},
"49WUF9NS": {
"type": "pty",
"createdAt": 1754021037,
"expiresAt": 1754107437,
"cwd": "/Users/vaclis./Documents/project/Claude-Code-Remote",
"sessionId": "52d15aa1-d5a4-4d7d-8f01-4752d7d5fc6f",
"tmuxSession": "WavJaby",
"description": "completed - Claude-Code-Remote"
},
"N9PHUN4Q": {
"type": "pty",
"createdAt": 1754021210,
"expiresAt": 1754107610,
"cwd": "/Users/vaclis./Documents/project/Claude-Code-Remote",
"sessionId": "eba8744e-8cc1-4fad-9dc8-69d558c51cca",
"tmuxSession": "test-session",
"description": "completed - Claude-Code-Remote-Test"
},
"GXWFSL3S": {
"type": "pty",
"createdAt": 1754021233,
"expiresAt": 1754107633,
"cwd": "/Users/vaclis./Documents/project/Claude-Code-Remote",
"sessionId": "859daa99-1ea9-4c40-aa68-c3967a0d7e4e",
"tmuxSession": "WavJaby",
"description": "completed - Claude-Code-Remote"
},
"6EZXA6IN": {
"type": "pty",
"createdAt": 1754021267,
"expiresAt": 1754107667,
"cwd": "/Users/vaclis./Documents/project/Claude-Code-Remote",
"sessionId": "a1ed6757-6782-4b22-a486-aab5a9d60a3c",
"tmuxSession": "test-session",
"description": "completed - Claude-Code-Remote-Test"
},
"ZQY1UOIJ": {
"type": "pty",
"createdAt": 1754021285,
"expiresAt": 1754107685,
"cwd": "/Users/vaclis./Documents/project/Claude-Code-Remote",
"sessionId": "2122d57c-8434-44f0-b4e6-7eafb40ed49d",
"tmuxSession": "WavJaby",
"description": "completed - Claude-Code-Remote"
},
"L4KQ8DVJ": {
"type": "pty",
"createdAt": 1754021533,
"expiresAt": 1754107933,
"cwd": "/Users/vaclis./Documents/project/Claude-Code-Remote",
"sessionId": "2b30b1f7-b9c3-4cb4-b889-11c58009bd07",
"tmuxSession": "test-session",
"description": "completed - Claude-Code-Remote-Test"
},
"7ZFMSK5P": {
"type": "pty",
"createdAt": 1754022640,
"expiresAt": 1754109040,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "e3392712-9a5b-4c96-a23c-5d97c226b415",
"tmuxSession": "a",
"description": "completed - Claude-Code-Remote"
},
"PJOE746Q": {
"type": "pty",
"createdAt": 1754022731,
"expiresAt": 1754109131,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "5d19da23-5c9d-4855-824e-fbd09a0d986c",
"tmuxSession": "a",
"description": "completed - Claude-Code-Remote"
},
"C9I24JHD": {
"type": "pty",
"createdAt": 1754022927,
"expiresAt": 1754109327,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "ed814c4b-0b97-4e10-8ad1-dae1a7cb7ef9",
"tmuxSession": "a",
"description": "completed - Claude-Code-Remote"
},
"GGBKJ2DV": {
"type": "pty",
"createdAt": 1754023256,
"expiresAt": 1754109656,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "46ae2185-2f70-4355-a3b8-9fc04fa01181",
"tmuxSession": "a",
"description": "completed - Claude-Code-Remote"
},
"DQH198YY": {
"type": "pty",
"createdAt": 1754023825,
"expiresAt": 1754110225,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "49c51c77-8ecc-4a04-a7a8-5955f89411b1",
"tmuxSession": "a",
"description": "completed - Claude-Code-Remote"
},
"GQE6LLIF": {
"type": "pty",
"createdAt": 1754024054,
"expiresAt": 1754110454,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "cc5a1eba-7e04-44e6-919f-0395ddf2ee08",
"tmuxSession": "a",
"description": "completed - Claude-Code-Remote"
},
"WYKEGTXV": {
"type": "pty",
"createdAt": 1754024273,
"expiresAt": 1754110673,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "63198b90-3b9d-4448-a932-7c39c771554a",
"tmuxSession": "a",
"description": "completed - Claude-Code-Remote"
},
"ATUBLIN1": {
"type": "pty",
"createdAt": 1754025557,
"expiresAt": 1754111957,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "bfd8b8d0-bcc4-4336-a6eb-8ca3f8b6c96e",
"tmuxSession": "a",
"description": "completed - Claude-Code-Remote"
},
"2W24RZTM": {
"type": "pty",
"createdAt": 1754025634,
"expiresAt": 1754112034,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "cdbfc3f9-e27e-47d9-82b9-9058f0180fff",
"tmuxSession": "a",
"description": "completed - Claude-Code-Remote"
},
"PHAVU604": {
"type": "pty",
"createdAt": 1754025855,
"expiresAt": 1754112255,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "cf18cb3b-bc72-46ea-985f-2b7f29f0993f",
"tmuxSession": "a",
"description": "completed - Claude-Code-Remote"
},
"C2APCY3V": {
"type": "pty",
"createdAt": 1754026029,
"expiresAt": 1754112429,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "6da5d6f6-7e68-47eb-8676-175d77f0ddbc",
"tmuxSession": "a",
"description": "completed - Claude-Code-Remote"
},
"N5P4GUG3": {
"type": "pty",
"createdAt": 1754026119,
"expiresAt": 1754112519,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "9143d717-be05-4869-b40a-2c775addcfc4",
"tmuxSession": "a",
"description": "completed - Claude-Code-Remote"
},
"CZIKHCFO": {
"type": "pty",
"createdAt": 1754026220,
"expiresAt": 1754112620,
"cwd": "/Users/jessytsui/dev/Claude-Code-Remote",
"sessionId": "6fb2932d-d4ac-427b-8b7d-54af44fee1f2",
"tmuxSession": "a",
"description": "completed - Claude-Code-Remote"
}
}

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1,206 @@
/**
* Subagent Activity Tracker
* Tracks subagent activities for including in completion emails
*/
const fs = require('fs');
const path = require('path');
class SubagentTracker {
constructor() {
this.dataDir = path.join(__dirname, '../data');
this.trackingFile = path.join(this.dataDir, 'subagent-activities.json');
this._ensureDataDir();
}
_escapeHtml(text) {
if (!text) return '';
const htmlEntities = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;'
};
return String(text).replace(/[&<>"']/g, char => htmlEntities[char]);
}
_ensureDataDir() {
if (!fs.existsSync(this.dataDir)) {
fs.mkdirSync(this.dataDir, { recursive: true });
}
}
/**
* Load existing activities
*/
_loadActivities() {
if (!fs.existsSync(this.trackingFile)) {
return {};
}
try {
return JSON.parse(fs.readFileSync(this.trackingFile, 'utf8'));
} catch (error) {
console.error('Failed to load subagent activities:', error);
return {};
}
}
/**
* Save activities to file
*/
_saveActivities(activities) {
try {
fs.writeFileSync(this.trackingFile, JSON.stringify(activities, null, 2));
} catch (error) {
console.error('Failed to save subagent activities:', error);
}
}
/**
* Add a subagent activity
*/
addActivity(sessionId, activity) {
const activities = this._loadActivities();
if (!activities[sessionId]) {
activities[sessionId] = {
startTime: new Date().toISOString(),
activities: []
};
}
activities[sessionId].activities.push({
timestamp: new Date().toISOString(),
type: activity.type || 'subagent',
description: activity.description || 'Subagent activity',
details: activity.details || {}
});
this._saveActivities(activities);
}
/**
* Get activities for a session
*/
getActivities(sessionId) {
const activities = this._loadActivities();
return activities[sessionId] || null;
}
/**
* Clear activities for a session
*/
clearActivities(sessionId) {
const activities = this._loadActivities();
delete activities[sessionId];
this._saveActivities(activities);
}
/**
* Clean up old activities (older than 24 hours)
*/
cleanupOldActivities() {
const activities = this._loadActivities();
const now = new Date();
const oneDayAgo = new Date(now - 24 * 60 * 60 * 1000);
for (const sessionId in activities) {
const startTime = new Date(activities[sessionId].startTime);
if (startTime < oneDayAgo) {
delete activities[sessionId];
}
}
this._saveActivities(activities);
}
/**
* Format activities for email
*/
formatActivitiesForEmail(sessionId) {
const sessionData = this.getActivities(sessionId);
if (!sessionData || sessionData.activities.length === 0) {
return '';
}
const activities = sessionData.activities;
const grouped = {};
// Group activities by type
activities.forEach(activity => {
const type = activity.type;
if (!grouped[type]) {
grouped[type] = [];
}
grouped[type].push(activity);
});
// Format as HTML
let html = `
<!-- Subagent Activities -->
<div style="margin: 20px 0; padding: 15px; background-color: #1f1f1f; border: 1px solid #444; border-radius: 4px;">
<div style="color: #ff9800; margin-bottom: 10px; font-weight: bold;">📊 Subagent Activities Summary</div>
<div style="color: #ccc; font-size: 13px; line-height: 1.6;">`;
for (const [type, items] of Object.entries(grouped)) {
html += `<div style="margin-bottom: 10px;">`;
html += `<div style="color: #00bcd4; font-weight: bold;">${type} (${items.length} activities)</div>`;
html += `<ul style="margin: 5px 0 0 20px; padding: 0;">`;
items.forEach((item, index) => {
const time = new Date(item.timestamp).toLocaleTimeString();
html += `<li style="color: #ccc; margin: 8px 0; list-style-type: none;">`;
html += `<div style="background-color: #262626; padding: 10px; border-left: 3px solid #00bcd4; margin: 5px 0;">`;
html += `<div><span style="color: #999;">[${time}]</span> <strong style="color: #fff;">${this._escapeHtml(item.description || 'Subagent task')}</strong></div>`;
if (item.details) {
// Show the question if available
if (item.details.userQuestion && item.details.userQuestion !== item.description) {
html += `<div style="color: #00ff00; margin-top: 5px; font-size: 12px;">→ Question: ${this._escapeHtml(item.details.userQuestion)}</div>`;
}
// Show the response
if (item.details.claudeResponse) {
const response = item.details.claudeResponse;
// Check if this is just initialization text
if (response.includes('Initializing...') || response.includes('Concocting...')) {
html += `<div style="color: #ff9800; margin-top: 5px; font-size: 12px; font-style: italic;">⏳ Subagent was processing... (full output available in tmux session)</div>`;
} else {
html += `<div style="color: #ccc; margin-top: 5px; margin-left: 20px; font-size: 12px; white-space: pre-wrap; max-height: 200px; overflow-y: auto; background-color: #1a1a1a; padding: 8px; border-radius: 4px;">`;
html += this._escapeHtml(response);
html += `</div>`;
}
}
}
html += `</div>`;
html += `</li>`;
});
html += `</ul>`;
html += `</div>`;
}
html += `
</div>
</div>`;
// Also format as plain text for text email
let text = '\n📊 Subagent Activities Summary\n\n';
for (const [type, items] of Object.entries(grouped)) {
text += `${type} (${items.length} activities)\n`;
items.forEach((item, index) => {
const time = new Date(item.timestamp).toLocaleTimeString();
text += ` ${index + 1}. [${time}] ${item.description}\n`;
if (item.details && item.details.claudeResponse) {
text += ` ${item.details.claudeResponse}\n`;
}
});
text += '\n';
}
// Return HTML for email (the email sender will use it appropriately)
return html;
}
}
module.exports = SubagentTracker;