myceliumail 1.0.9 → 1.0.13

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.
Files changed (96) hide show
  1. package/.mappersan/outbox.json +15 -0
  2. package/.spidersan/registry.json +39 -0
  3. package/CHANGELOG.md +29 -0
  4. package/CLAUDE.md +29 -0
  5. package/README.md +23 -2
  6. package/dist/bin/myceliumail.js +17 -1
  7. package/dist/bin/myceliumail.js.map +1 -1
  8. package/dist/commands/close.d.ts +9 -0
  9. package/dist/commands/close.d.ts.map +1 -0
  10. package/dist/commands/close.js +153 -0
  11. package/dist/commands/close.js.map +1 -0
  12. package/dist/commands/collab.d.ts +8 -0
  13. package/dist/commands/collab.d.ts.map +1 -0
  14. package/dist/commands/collab.js +112 -0
  15. package/dist/commands/collab.js.map +1 -0
  16. package/dist/commands/inbox.d.ts.map +1 -1
  17. package/dist/commands/inbox.js +105 -26
  18. package/dist/commands/inbox.js.map +1 -1
  19. package/dist/commands/tags.d.ts +6 -0
  20. package/dist/commands/tags.d.ts.map +1 -0
  21. package/dist/commands/tags.js +90 -0
  22. package/dist/commands/tags.js.map +1 -0
  23. package/dist/commands/wake.d.ts +9 -0
  24. package/dist/commands/wake.d.ts.map +1 -0
  25. package/dist/commands/wake.js +198 -0
  26. package/dist/commands/wake.js.map +1 -0
  27. package/dist/dashboard/public/app.js +117 -0
  28. package/dist/dashboard/public/index.html +63 -5
  29. package/dist/dashboard/routes.d.ts.map +1 -1
  30. package/dist/dashboard/routes.js +31 -2
  31. package/dist/dashboard/routes.js.map +1 -1
  32. package/dist/lib/update-check.d.ts.map +1 -1
  33. package/dist/lib/update-check.js +6 -4
  34. package/dist/lib/update-check.js.map +1 -1
  35. package/dist/lib/watson-digest.d.ts +40 -0
  36. package/dist/lib/watson-digest.d.ts.map +1 -0
  37. package/dist/lib/watson-digest.js +164 -0
  38. package/dist/lib/watson-digest.js.map +1 -0
  39. package/dist/storage/supabase.d.ts +4 -0
  40. package/dist/storage/supabase.d.ts.map +1 -1
  41. package/dist/storage/supabase.js +57 -0
  42. package/dist/storage/supabase.js.map +1 -1
  43. package/docs/COLLAB_mappersan_mycmail_setup.md +115 -0
  44. package/docs/COLLAB_wake_close_commands.md +518 -0
  45. package/docs/CROSS_TOOL_INTEGRATION_PLAN.md +246 -0
  46. package/docs/JSON_SCHEMA_WAKE_CLOSE.md +246 -0
  47. package/docs/MYCMAIL_QUICKSTART.md +103 -0
  48. package/docs/WAKE_AGENTS_SHARED_DOC.md +1215 -0
  49. package/mcp-server/README.md +75 -69
  50. package/mcp-server/package-lock.json +2 -2
  51. package/mcp-server/package.json +5 -1
  52. package/mcp-server/postinstall.js +14 -0
  53. package/mcp-server/src/server.ts +39 -0
  54. package/mobile-app/README.md +36 -0
  55. package/mobile-app/app/compose/page.tsx +140 -0
  56. package/mobile-app/app/favicon.ico +0 -0
  57. package/mobile-app/app/globals.css +26 -0
  58. package/mobile-app/app/layout.tsx +42 -0
  59. package/mobile-app/app/message/[id]/page.tsx +126 -0
  60. package/mobile-app/app/page.tsx +131 -0
  61. package/mobile-app/components/MessageCard.tsx +60 -0
  62. package/mobile-app/eslint.config.mjs +18 -0
  63. package/mobile-app/lib/supabase.ts +87 -0
  64. package/mobile-app/next.config.ts +7 -0
  65. package/mobile-app/package-lock.json +6674 -0
  66. package/mobile-app/package.json +27 -0
  67. package/mobile-app/postcss.config.mjs +7 -0
  68. package/mobile-app/public/file.svg +1 -0
  69. package/mobile-app/public/globe.svg +1 -0
  70. package/mobile-app/public/next.svg +1 -0
  71. package/mobile-app/public/vercel.svg +1 -0
  72. package/mobile-app/public/window.svg +1 -0
  73. package/mobile-app/tsconfig.json +34 -0
  74. package/package.json +2 -1
  75. package/postinstall.js +14 -0
  76. package/src/bin/myceliumail.ts +19 -1
  77. package/src/commands/close.ts +172 -0
  78. package/src/commands/collab.ts +125 -0
  79. package/src/commands/inbox.ts +120 -29
  80. package/src/commands/tags.ts +102 -0
  81. package/src/commands/wake.ts +228 -0
  82. package/src/dashboard/public/app.js +117 -0
  83. package/src/dashboard/public/index.html +63 -5
  84. package/src/dashboard/routes.ts +31 -2
  85. package/src/lib/update-check.ts +7 -4
  86. package/src/lib/watson-digest.ts +217 -0
  87. package/src/storage/supabase.ts +71 -0
  88. package/vscode-extension/README.md +107 -0
  89. package/vscode-extension/package-lock.json +1941 -0
  90. package/vscode-extension/package.json +117 -0
  91. package/vscode-extension/src/chatParticipant.ts +179 -0
  92. package/vscode-extension/src/extension.ts +262 -0
  93. package/vscode-extension/src/handlers.ts +265 -0
  94. package/vscode-extension/src/realtime.ts +302 -0
  95. package/vscode-extension/src/types.ts +41 -0
  96. package/vscode-extension/tsconfig.json +26 -0
@@ -5,11 +5,53 @@ import { Command } from 'commander';
5
5
  import { loadConfig } from '../lib/config.js';
6
6
  import { loadKeyPair, decryptMessage } from '../lib/crypto.js';
7
7
  import * as storage from '../storage/supabase.js';
8
+ /**
9
+ * Extract hashtag from subject (e.g., "#wake-feature: Message" -> "wake-feature")
10
+ */
11
+ function extractTag(subject) {
12
+ if (!subject)
13
+ return null;
14
+ const match = subject.match(/^#([a-zA-Z0-9_-]+):/);
15
+ return match ? match[1].toLowerCase() : null;
16
+ }
17
+ /**
18
+ * Decrypt message subjects for filtering
19
+ */
20
+ function decryptSubject(msg, keyPair) {
21
+ let subject = msg.subject;
22
+ let body = msg.body;
23
+ if (msg.encrypted && keyPair && msg.ciphertext && msg.nonce && msg.senderPublicKey) {
24
+ try {
25
+ const decrypted = decryptMessage({
26
+ ciphertext: msg.ciphertext,
27
+ nonce: msg.nonce,
28
+ senderPublicKey: msg.senderPublicKey,
29
+ }, keyPair);
30
+ if (decrypted) {
31
+ const parsed = JSON.parse(decrypted);
32
+ subject = parsed.subject || subject;
33
+ body = parsed.body || body;
34
+ }
35
+ }
36
+ catch {
37
+ // Keep original
38
+ }
39
+ }
40
+ return {
41
+ original: msg,
42
+ subject,
43
+ body,
44
+ tag: extractTag(subject)
45
+ };
46
+ }
8
47
  export function createInboxCommand() {
9
48
  return new Command('inbox')
10
49
  .description('List incoming messages')
11
50
  .option('-u, --unread', 'Show only unread messages')
12
51
  .option('-l, --limit <n>', 'Limit number of messages', '10')
52
+ .option('-c, --count', 'Show only message count (for scripting)')
53
+ .option('-t, --tag <tag>', 'Filter by hashtag (e.g., --tag wake-feature)')
54
+ .option('--json', 'Output as JSON (for scripting)')
13
55
  .action(async (options) => {
14
56
  const config = loadConfig();
15
57
  const agentId = config.agentId;
@@ -19,39 +61,76 @@ export function createInboxCommand() {
19
61
  process.exit(1);
20
62
  }
21
63
  try {
22
- const messages = await storage.getInbox(agentId, {
64
+ const rawMessages = await storage.getInbox(agentId, {
23
65
  unreadOnly: options.unread,
24
- limit: parseInt(options.limit, 10),
66
+ limit: parseInt(options.limit, 10) * (options.tag ? 10 : 1),
25
67
  });
68
+ const keyPair = loadKeyPair(agentId);
69
+ // Decrypt all subjects first for proper filtering
70
+ let messages = rawMessages.map(m => decryptSubject(m, keyPair));
71
+ // Filter by tag if specified
72
+ if (options.tag) {
73
+ const targetTag = options.tag.toLowerCase().replace(/^#/, '');
74
+ messages = messages.filter(m => m.tag === targetTag);
75
+ messages = messages.slice(0, parseInt(options.limit, 10));
76
+ }
77
+ // Count-only mode
78
+ if (options.count) {
79
+ const unreadCount = messages.filter(m => !m.original.read).length;
80
+ if (options.json) {
81
+ console.log(JSON.stringify({
82
+ total: messages.length,
83
+ unread: unreadCount,
84
+ agentId,
85
+ tag: options.tag || null
86
+ }));
87
+ }
88
+ else {
89
+ console.log(`${unreadCount} unread`);
90
+ }
91
+ return;
92
+ }
93
+ // JSON mode
94
+ if (options.json) {
95
+ const output = {
96
+ agentId,
97
+ total: messages.length,
98
+ unread: messages.filter(m => !m.original.read).length,
99
+ tag: options.tag || null,
100
+ messages: messages.map(m => ({
101
+ id: m.original.id,
102
+ from: m.original.sender,
103
+ subject: m.subject,
104
+ tag: m.tag,
105
+ read: m.original.read,
106
+ encrypted: m.original.encrypted,
107
+ createdAt: m.original.createdAt.toISOString()
108
+ }))
109
+ };
110
+ console.log(JSON.stringify(output, null, 2));
111
+ return;
112
+ }
26
113
  if (messages.length === 0) {
27
- console.log('📭 No messages');
114
+ if (options.tag) {
115
+ console.log(`📭 No messages with tag #${options.tag}`);
116
+ }
117
+ else {
118
+ console.log('📭 No messages');
119
+ }
28
120
  return;
29
121
  }
30
- console.log(`📬 Inbox for ${agentId} (${messages.length} messages)\n`);
31
- const keyPair = loadKeyPair(agentId);
122
+ const tagInfo = options.tag ? ` [#${options.tag}]` : '';
123
+ console.log(`📬 Inbox for ${agentId}${tagInfo} (${messages.length} messages)\n`);
32
124
  for (const msg of messages) {
33
- const readMarker = msg.read ? ' ' : '● ';
34
- const encryptedMarker = msg.encrypted ? '🔐 ' : '';
35
- const date = msg.createdAt.toLocaleString();
36
- let displaySubject = msg.subject;
37
- // Try to decrypt if encrypted and we have keys
38
- if (msg.encrypted && keyPair && msg.ciphertext && msg.nonce && msg.senderPublicKey) {
39
- try {
40
- const decrypted = decryptMessage({
41
- ciphertext: msg.ciphertext,
42
- nonce: msg.nonce,
43
- senderPublicKey: msg.senderPublicKey,
44
- }, keyPair);
45
- if (decrypted) {
46
- const parsed = JSON.parse(decrypted);
47
- displaySubject = parsed.subject || '[Decrypted]';
48
- }
49
- }
50
- catch {
51
- displaySubject = '[Encrypted]';
52
- }
125
+ const readMarker = msg.original.read ? ' ' : '● ';
126
+ const encryptedMarker = msg.original.encrypted ? '🔐 ' : '';
127
+ const date = msg.original.createdAt.toLocaleString();
128
+ let displaySubject = msg.subject || '[No Subject]';
129
+ // Highlight tag in subject if present
130
+ if (msg.tag) {
131
+ displaySubject = displaySubject.replace(`#${msg.tag}:`, `[#${msg.tag}]`);
53
132
  }
54
- console.log(`${readMarker}${encryptedMarker}${msg.id.slice(0, 8)} | From: ${msg.sender} | ${displaySubject}`);
133
+ console.log(`${readMarker}${encryptedMarker}${msg.original.id.slice(0, 8)} | From: ${msg.original.sender} | ${displaySubject}`);
55
134
  console.log(` ${date}`);
56
135
  }
57
136
  console.log('\n💡 Use: mycmail read <id> to read a message');
@@ -1 +1 @@
1
- {"version":3,"file":"inbox.js","sourceRoot":"","sources":["../../src/commands/inbox.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"inbox.js","sourceRoot":"","sources":["../../src/commands/inbox.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * tags command - List all unique hashtags from messages
3
+ */
4
+ import { Command } from 'commander';
5
+ export declare function createTagsCommand(): Command;
6
+ //# sourceMappingURL=tags.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tags.d.ts","sourceRoot":"","sources":["../../src/commands/tags.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAcpC,wBAAgB,iBAAiB,IAAI,OAAO,CAmF3C"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * tags command - List all unique hashtags from messages
3
+ */
4
+ import { Command } from 'commander';
5
+ import { loadConfig } from '../lib/config.js';
6
+ import { loadKeyPair, decryptMessage } from '../lib/crypto.js';
7
+ import * as storage from '../storage/supabase.js';
8
+ /**
9
+ * Extract hashtag from subject (e.g., "#wake-feature: Message" -> "wake-feature")
10
+ */
11
+ function extractTag(subject) {
12
+ if (!subject)
13
+ return null;
14
+ const match = subject.match(/^#([a-zA-Z0-9_-]+):/);
15
+ return match ? match[1].toLowerCase() : null;
16
+ }
17
+ export function createTagsCommand() {
18
+ return new Command('tags')
19
+ .description('List all unique hashtags from your messages')
20
+ .option('--json', 'Output as JSON')
21
+ .action(async (options) => {
22
+ const config = loadConfig();
23
+ const agentId = config.agentId;
24
+ if (agentId === 'anonymous') {
25
+ console.error('❌ Agent ID not configured.');
26
+ process.exit(1);
27
+ }
28
+ try {
29
+ // Fetch all messages (up to 500)
30
+ const messages = await storage.getInbox(agentId, { limit: 500 });
31
+ const keyPair = loadKeyPair(agentId);
32
+ // Count tags
33
+ const tagCounts = {};
34
+ for (const msg of messages) {
35
+ let subject = msg.subject;
36
+ // Try to decrypt if encrypted
37
+ if (msg.encrypted && keyPair && msg.ciphertext && msg.nonce && msg.senderPublicKey) {
38
+ try {
39
+ const decrypted = decryptMessage({
40
+ ciphertext: msg.ciphertext,
41
+ nonce: msg.nonce,
42
+ senderPublicKey: msg.senderPublicKey,
43
+ }, keyPair);
44
+ if (decrypted) {
45
+ const parsed = JSON.parse(decrypted);
46
+ subject = parsed.subject || subject;
47
+ }
48
+ }
49
+ catch {
50
+ // Keep original subject
51
+ }
52
+ }
53
+ const tag = extractTag(subject);
54
+ if (tag) {
55
+ if (!tagCounts[tag]) {
56
+ tagCounts[tag] = { count: 0, unread: 0 };
57
+ }
58
+ tagCounts[tag].count++;
59
+ if (!msg.read) {
60
+ tagCounts[tag].unread++;
61
+ }
62
+ }
63
+ }
64
+ const tagList = Object.entries(tagCounts)
65
+ .sort((a, b) => b[1].count - a[1].count)
66
+ .map(([tag, stats]) => ({ tag, ...stats }));
67
+ if (options.json) {
68
+ console.log(JSON.stringify({ tags: tagList }, null, 2));
69
+ return;
70
+ }
71
+ if (tagList.length === 0) {
72
+ console.log('📭 No tagged messages found');
73
+ console.log('\n💡 Tag messages by prefixing subject with #tag:');
74
+ console.log(' mycmail send wsan "#wake-feature: Need help"');
75
+ return;
76
+ }
77
+ console.log('🏷️ Message Tags\n');
78
+ for (const { tag, count, unread } of tagList) {
79
+ const unreadMarker = unread > 0 ? ` (${unread} unread)` : '';
80
+ console.log(` #${tag}: ${count} message${count > 1 ? 's' : ''}${unreadMarker}`);
81
+ }
82
+ console.log('\n💡 Filter by tag: mycmail inbox --tag <tag>');
83
+ }
84
+ catch (error) {
85
+ console.error('❌ Failed to fetch tags:', error);
86
+ process.exit(1);
87
+ }
88
+ });
89
+ }
90
+ //# sourceMappingURL=tags.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tags.js","sourceRoot":"","sources":["../../src/commands/tags.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * wake command - Start a new session
3
+ *
4
+ * Shows inbox count, active collabs, and last session time.
5
+ * Designed for agent session lifecycle management.
6
+ */
7
+ import { Command } from 'commander';
8
+ export declare function createWakeCommand(): Command;
9
+ //# sourceMappingURL=wake.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wake.d.ts","sourceRoot":"","sources":["../../src/commands/wake.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA8GpC,wBAAgB,iBAAiB,IAAI,OAAO,CA8G3C"}
@@ -0,0 +1,198 @@
1
+ /**
2
+ * wake command - Start a new session
3
+ *
4
+ * Shows inbox count, active collabs, and last session time.
5
+ * Designed for agent session lifecycle management.
6
+ */
7
+ import { Command } from 'commander';
8
+ import { loadConfig } from '../lib/config.js';
9
+ import { loadKeyPair, decryptMessage } from '../lib/crypto.js';
10
+ import { generateDigest, sendDigestToWatsan } from '../lib/watson-digest.js';
11
+ import * as storage from '../storage/supabase.js';
12
+ import * as fs from 'fs';
13
+ import * as path from 'path';
14
+ import * as os from 'os';
15
+ function getSessionPath() {
16
+ return path.join(os.homedir(), '.mycmail', 'session.json');
17
+ }
18
+ function loadSession() {
19
+ const sessionPath = getSessionPath();
20
+ try {
21
+ if (fs.existsSync(sessionPath)) {
22
+ return JSON.parse(fs.readFileSync(sessionPath, 'utf-8'));
23
+ }
24
+ }
25
+ catch {
26
+ // Ignore errors, return default
27
+ }
28
+ return { lastWake: null, lastClose: null, activeCollabs: [] };
29
+ }
30
+ function saveSession(data) {
31
+ const sessionPath = getSessionPath();
32
+ const dir = path.dirname(sessionPath);
33
+ if (!fs.existsSync(dir)) {
34
+ fs.mkdirSync(dir, { recursive: true });
35
+ }
36
+ fs.writeFileSync(sessionPath, JSON.stringify(data, null, 2));
37
+ }
38
+ function formatTimeSince(date) {
39
+ if (!date)
40
+ return 'Never';
41
+ const now = new Date();
42
+ const then = new Date(date);
43
+ const diffMs = now.getTime() - then.getTime();
44
+ const diffMins = Math.floor(diffMs / 60000);
45
+ const diffHours = Math.floor(diffMins / 60);
46
+ const diffDays = Math.floor(diffHours / 24);
47
+ if (diffMins < 1)
48
+ return 'Just now';
49
+ if (diffMins < 60)
50
+ return `${diffMins} minutes ago`;
51
+ if (diffHours < 24)
52
+ return `${diffHours} hours ago`;
53
+ return `${diffDays} days ago`;
54
+ }
55
+ function extractTag(subject) {
56
+ if (!subject)
57
+ return null;
58
+ const match = subject.match(/^#([a-zA-Z0-9_-]+):/);
59
+ return match ? match[1].toLowerCase() : null;
60
+ }
61
+ async function getTagDigest(agentId, messages) {
62
+ const keyPair = loadKeyPair(agentId);
63
+ const tagCounts = {};
64
+ for (const msg of messages) {
65
+ let subject = msg.subject;
66
+ // Try to decrypt if encrypted
67
+ if (msg.encrypted && keyPair && msg.ciphertext && msg.nonce && msg.senderPublicKey) {
68
+ try {
69
+ const decrypted = decryptMessage({
70
+ ciphertext: msg.ciphertext,
71
+ nonce: msg.nonce,
72
+ senderPublicKey: msg.senderPublicKey,
73
+ }, keyPair);
74
+ if (decrypted) {
75
+ const parsed = JSON.parse(decrypted);
76
+ subject = parsed.subject || subject;
77
+ }
78
+ }
79
+ catch {
80
+ // Keep original subject
81
+ }
82
+ }
83
+ const tag = extractTag(subject);
84
+ if (tag) {
85
+ if (!tagCounts[tag]) {
86
+ tagCounts[tag] = { count: 0, unread: 0 };
87
+ }
88
+ tagCounts[tag].count++;
89
+ if (!msg.read) {
90
+ tagCounts[tag].unread++;
91
+ }
92
+ }
93
+ }
94
+ return Object.entries(tagCounts)
95
+ .sort((a, b) => b[1].unread - a[1].unread)
96
+ .slice(0, 5)
97
+ .map(([tag, stats]) => ({ tag, ...stats }));
98
+ }
99
+ export function createWakeCommand() {
100
+ return new Command('wake')
101
+ .description('Start a new session - check inbox, collabs, and announce presence')
102
+ .option('--json', 'Output as JSON (for scripting)')
103
+ .option('-q, --quiet', 'Minimal output')
104
+ .option('--silent', 'No output (only exit code)')
105
+ .option('--digest', 'Show hashtag digest and active threads')
106
+ .action(async (options) => {
107
+ const config = loadConfig();
108
+ const agentId = config.agentId;
109
+ if (agentId === 'anonymous') {
110
+ if (!options.silent) {
111
+ console.error('❌ Agent ID not configured.');
112
+ }
113
+ process.exit(1);
114
+ }
115
+ try {
116
+ // Load session data
117
+ const session = loadSession();
118
+ // Check if this is a duplicate wake (idempotency)
119
+ if (session.lastWake) {
120
+ const lastWakeTime = new Date(session.lastWake);
121
+ const now = new Date();
122
+ const diffMins = (now.getTime() - lastWakeTime.getTime()) / 60000;
123
+ // If woken up less than 5 minutes ago, skip re-registration
124
+ if (diffMins < 5 && !options.json) {
125
+ if (!options.silent && !options.quiet) {
126
+ console.log(`⏰ Already woke ${Math.floor(diffMins)} min ago. Use --force to re-wake.`);
127
+ }
128
+ // Still show status but don't re-register
129
+ }
130
+ }
131
+ // Get inbox count
132
+ const messages = await storage.getInbox(agentId, { limit: 100 });
133
+ const unreadCount = messages.filter(m => !m.read).length;
134
+ const totalCount = messages.length;
135
+ // Update session
136
+ session.lastWake = new Date().toISOString();
137
+ saveSession(session);
138
+ // Output based on mode
139
+ if (options.silent) {
140
+ process.exit(0);
141
+ }
142
+ if (options.json) {
143
+ const output = {
144
+ agentId,
145
+ inbox: {
146
+ total: totalCount,
147
+ unread: unreadCount
148
+ },
149
+ lastClose: session.lastClose,
150
+ activeCollabs: session.activeCollabs,
151
+ wakeTime: session.lastWake
152
+ };
153
+ console.log(JSON.stringify(output, null, 2));
154
+ return;
155
+ }
156
+ // Standard output
157
+ console.log(`\n🌅 Good morning, ${agentId}!\n`);
158
+ console.log(`📬 Inbox: ${unreadCount} unread / ${totalCount} total`);
159
+ console.log(`📋 Active collabs: ${session.activeCollabs.length}`);
160
+ console.log(`🕐 Last close: ${formatTimeSince(session.lastClose)}`);
161
+ // Show digest if requested
162
+ if (options.digest) {
163
+ const digest = await getTagDigest(agentId, messages);
164
+ if (digest.length > 0) {
165
+ console.log('\n🏷️ Active Threads:');
166
+ for (const { tag, count, unread } of digest) {
167
+ const unreadMarker = unread > 0 ? ` (${unread} new)` : '';
168
+ console.log(` #${tag}: ${count}${unreadMarker}`);
169
+ }
170
+ }
171
+ }
172
+ if (!options.quiet) {
173
+ console.log('\n💡 Tip: Run \'mycmail inbox\' to read messages');
174
+ }
175
+ console.log('\n✅ Session started!\n');
176
+ // Send digest to watson (unencrypted)
177
+ if (!options.silent) {
178
+ try {
179
+ const wakeDigest = await generateDigest(agentId, 'wake');
180
+ await sendDigestToWatsan(wakeDigest);
181
+ if (!options.quiet) {
182
+ console.log('📊 Digest sent to watson');
183
+ }
184
+ }
185
+ catch {
186
+ // Silent fail - digest is optional
187
+ }
188
+ }
189
+ }
190
+ catch (error) {
191
+ if (!options.silent) {
192
+ console.error('❌ Wake failed:', error);
193
+ }
194
+ process.exit(1);
195
+ }
196
+ });
197
+ }
198
+ //# sourceMappingURL=wake.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wake.js","sourceRoot":"","sources":["../../src/commands/wake.ts"],"names":[],"mappings":"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"}
@@ -521,3 +521,120 @@ loadInbox();
521
521
 
522
522
  // Poll every 30 seconds as fallback (Realtime handles instant updates)
523
523
  setInterval(() => loadInbox(true), 30000);
524
+
525
+ // ============== COMPOSE MESSAGE FUNCTIONS ==============
526
+
527
+ let availableAgents = [];
528
+
529
+ // Load available agents for compose dropdown
530
+ async function loadAvailableAgents() {
531
+ try {
532
+ const res = await fetch('/api/config/agents');
533
+ const data = await res.json();
534
+ availableAgents = data.agents || [];
535
+ updateAgentDropdown();
536
+ } catch (err) {
537
+ console.error('Failed to load agents:', err);
538
+ }
539
+ }
540
+
541
+ function updateAgentDropdown() {
542
+ const select = document.getElementById('compose-from');
543
+ if (!select) return;
544
+
545
+ if (availableAgents.length === 0) {
546
+ select.innerHTML = `<option value="${currentAgentId}">${currentAgentId}</option>`;
547
+ } else {
548
+ select.innerHTML = availableAgents.map(agent =>
549
+ `<option value="${agent}" ${agent === 'treebird' ? 'selected' : ''}>${agent}</option>`
550
+ ).join('');
551
+ }
552
+ }
553
+
554
+ function showComposeModal() {
555
+ loadAvailableAgents();
556
+ document.getElementById('compose-modal').classList.remove('hidden');
557
+ document.getElementById('compose-to').focus();
558
+ }
559
+
560
+ function hideComposeModal() {
561
+ document.getElementById('compose-modal').classList.add('hidden');
562
+ // Clear form
563
+ document.getElementById('compose-to').value = '';
564
+ document.getElementById('compose-subject').value = '';
565
+ document.getElementById('compose-body').value = '';
566
+ document.getElementById('compose-files').value = '';
567
+ }
568
+
569
+ async function sendNewMessage() {
570
+ const from = document.getElementById('compose-from').value;
571
+ const to = document.getElementById('compose-to').value.trim();
572
+ const subject = document.getElementById('compose-subject').value.trim();
573
+ const body = document.getElementById('compose-body').value;
574
+ const fileInput = document.getElementById('compose-files');
575
+
576
+ if (!to) {
577
+ alert('Please enter a recipient');
578
+ return;
579
+ }
580
+ if (!subject) {
581
+ alert('Please enter a subject');
582
+ return;
583
+ }
584
+ if (!body.trim()) {
585
+ alert('Please enter a message');
586
+ return;
587
+ }
588
+
589
+ // Process attachments
590
+ const attachments = [];
591
+ const MAX_SIZE = 5 * 1024 * 1024; // 5MB
592
+
593
+ if (fileInput && fileInput.files.length > 0) {
594
+ for (const file of fileInput.files) {
595
+ if (file.size > MAX_SIZE) {
596
+ alert(`File "${file.name}" exceeds 5MB limit`);
597
+ return;
598
+ }
599
+ const base64 = await readFileAsBase64(file);
600
+ attachments.push({
601
+ name: file.name,
602
+ type: file.type || 'application/octet-stream',
603
+ data: base64,
604
+ size: file.size
605
+ });
606
+ }
607
+ }
608
+
609
+ try {
610
+ console.log('Sending message from:', from, 'to:', to);
611
+ const response = await fetch('/api/send', {
612
+ method: 'POST',
613
+ headers: { 'Content-Type': 'application/json' },
614
+ body: JSON.stringify({
615
+ to: to,
616
+ subject: subject,
617
+ body: body,
618
+ from: from,
619
+ attachments: attachments.length > 0 ? attachments : undefined
620
+ })
621
+ });
622
+
623
+ const result = await response.json();
624
+ console.log('Send result:', result);
625
+
626
+ if (!response.ok || !result.success) {
627
+ throw new Error(result.error || 'Failed to send');
628
+ }
629
+
630
+ hideComposeModal();
631
+ alert('Message sent!' + (attachments.length > 0 ? ` (${attachments.length} attachment(s))` : ''));
632
+ loadInbox(true);
633
+ } catch (err) {
634
+ console.error('Send message error:', err);
635
+ alert('Failed to send message: ' + err.message);
636
+ }
637
+ }
638
+
639
+ // Load agents on startup
640
+ loadAvailableAgents();