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.
- package/.mappersan/outbox.json +15 -0
- package/.spidersan/registry.json +39 -0
- package/CHANGELOG.md +29 -0
- package/CLAUDE.md +29 -0
- package/README.md +23 -2
- package/dist/bin/myceliumail.js +17 -1
- package/dist/bin/myceliumail.js.map +1 -1
- package/dist/commands/close.d.ts +9 -0
- package/dist/commands/close.d.ts.map +1 -0
- package/dist/commands/close.js +153 -0
- package/dist/commands/close.js.map +1 -0
- package/dist/commands/collab.d.ts +8 -0
- package/dist/commands/collab.d.ts.map +1 -0
- package/dist/commands/collab.js +112 -0
- package/dist/commands/collab.js.map +1 -0
- package/dist/commands/inbox.d.ts.map +1 -1
- package/dist/commands/inbox.js +105 -26
- package/dist/commands/inbox.js.map +1 -1
- package/dist/commands/tags.d.ts +6 -0
- package/dist/commands/tags.d.ts.map +1 -0
- package/dist/commands/tags.js +90 -0
- package/dist/commands/tags.js.map +1 -0
- package/dist/commands/wake.d.ts +9 -0
- package/dist/commands/wake.d.ts.map +1 -0
- package/dist/commands/wake.js +198 -0
- package/dist/commands/wake.js.map +1 -0
- package/dist/dashboard/public/app.js +117 -0
- package/dist/dashboard/public/index.html +63 -5
- package/dist/dashboard/routes.d.ts.map +1 -1
- package/dist/dashboard/routes.js +31 -2
- package/dist/dashboard/routes.js.map +1 -1
- package/dist/lib/update-check.d.ts.map +1 -1
- package/dist/lib/update-check.js +6 -4
- package/dist/lib/update-check.js.map +1 -1
- package/dist/lib/watson-digest.d.ts +40 -0
- package/dist/lib/watson-digest.d.ts.map +1 -0
- package/dist/lib/watson-digest.js +164 -0
- package/dist/lib/watson-digest.js.map +1 -0
- package/dist/storage/supabase.d.ts +4 -0
- package/dist/storage/supabase.d.ts.map +1 -1
- package/dist/storage/supabase.js +57 -0
- package/dist/storage/supabase.js.map +1 -1
- package/docs/COLLAB_mappersan_mycmail_setup.md +115 -0
- package/docs/COLLAB_wake_close_commands.md +518 -0
- package/docs/CROSS_TOOL_INTEGRATION_PLAN.md +246 -0
- package/docs/JSON_SCHEMA_WAKE_CLOSE.md +246 -0
- package/docs/MYCMAIL_QUICKSTART.md +103 -0
- package/docs/WAKE_AGENTS_SHARED_DOC.md +1215 -0
- package/mcp-server/README.md +75 -69
- package/mcp-server/package-lock.json +2 -2
- package/mcp-server/package.json +5 -1
- package/mcp-server/postinstall.js +14 -0
- package/mcp-server/src/server.ts +39 -0
- package/mobile-app/README.md +36 -0
- package/mobile-app/app/compose/page.tsx +140 -0
- package/mobile-app/app/favicon.ico +0 -0
- package/mobile-app/app/globals.css +26 -0
- package/mobile-app/app/layout.tsx +42 -0
- package/mobile-app/app/message/[id]/page.tsx +126 -0
- package/mobile-app/app/page.tsx +131 -0
- package/mobile-app/components/MessageCard.tsx +60 -0
- package/mobile-app/eslint.config.mjs +18 -0
- package/mobile-app/lib/supabase.ts +87 -0
- package/mobile-app/next.config.ts +7 -0
- package/mobile-app/package-lock.json +6674 -0
- package/mobile-app/package.json +27 -0
- package/mobile-app/postcss.config.mjs +7 -0
- package/mobile-app/public/file.svg +1 -0
- package/mobile-app/public/globe.svg +1 -0
- package/mobile-app/public/next.svg +1 -0
- package/mobile-app/public/vercel.svg +1 -0
- package/mobile-app/public/window.svg +1 -0
- package/mobile-app/tsconfig.json +34 -0
- package/package.json +2 -1
- package/postinstall.js +14 -0
- package/src/bin/myceliumail.ts +19 -1
- package/src/commands/close.ts +172 -0
- package/src/commands/collab.ts +125 -0
- package/src/commands/inbox.ts +120 -29
- package/src/commands/tags.ts +102 -0
- package/src/commands/wake.ts +228 -0
- package/src/dashboard/public/app.js +117 -0
- package/src/dashboard/public/index.html +63 -5
- package/src/dashboard/routes.ts +31 -2
- package/src/lib/update-check.ts +7 -4
- package/src/lib/watson-digest.ts +217 -0
- package/src/storage/supabase.ts +71 -0
- package/vscode-extension/README.md +107 -0
- package/vscode-extension/package-lock.json +1941 -0
- package/vscode-extension/package.json +117 -0
- package/vscode-extension/src/chatParticipant.ts +179 -0
- package/vscode-extension/src/extension.ts +262 -0
- package/vscode-extension/src/handlers.ts +265 -0
- package/vscode-extension/src/realtime.ts +302 -0
- package/vscode-extension/src/types.ts +41 -0
- package/vscode-extension/tsconfig.json +26 -0
package/dist/commands/inbox.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
31
|
-
|
|
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
|
-
//
|
|
38
|
-
if (msg.
|
|
39
|
-
|
|
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":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAElD,MAAM,UAAU,kBAAkB;IAC9B,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;SACtB,WAAW,CAAC,wBAAwB,CAAC;SACrC,MAAM,CAAC,cAAc,EAAE,2BAA2B,CAAC;SACnD,MAAM,CAAC,iBAAiB,EAAE,0BAA0B,EAAE,IAAI,CAAC;SAC3D,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QACtB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QAE/B,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;YAC1B,OAAO,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;YAC5C,OAAO,CAAC,KAAK,CAAC,kEAAkE,CAAC,CAAC;YAClF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;QAED,IAAI,CAAC;YACD,MAAM,
|
|
1
|
+
{"version":3,"file":"inbox.js","sourceRoot":"","sources":["../../src/commands/inbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -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":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7E,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAQzB,SAAS,cAAc;IACnB,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC;AAC/D,CAAC;AAED,SAAS,WAAW;IAChB,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IACrC,IAAI,CAAC;QACD,IAAI,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;QAC7D,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACL,gCAAgC;IACpC,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC;AAClE,CAAC;AAED,SAAS,WAAW,CAAC,IAAiB;IAClC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IACrC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACtC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,CAAC;IACD,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AACjE,CAAC;AAED,SAAS,eAAe,CAAC,IAAmB;IACxC,IAAI,CAAC,IAAI;QAAE,OAAO,OAAO,CAAC;IAC1B,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5B,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;IAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC;IAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,EAAE,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,EAAE,CAAC,CAAC;IAE5C,IAAI,QAAQ,GAAG,CAAC;QAAE,OAAO,UAAU,CAAC;IACpC,IAAI,QAAQ,GAAG,EAAE;QAAE,OAAO,GAAG,QAAQ,cAAc,CAAC;IACpD,IAAI,SAAS,GAAG,EAAE;QAAE,OAAO,GAAG,SAAS,YAAY,CAAC;IACpD,OAAO,GAAG,QAAQ,WAAW,CAAC;AAClC,CAAC;AAED,SAAS,UAAU,CAAC,OAAsB;IACtC,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACnD,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACjD,CAAC;AAQD,KAAK,UAAU,YAAY,CAAC,OAAe,EAAE,QAAe;IACxD,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IACrC,MAAM,SAAS,GAAsD,EAAE,CAAC;IAExE,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;QAE1B,8BAA8B;QAC9B,IAAI,GAAG,CAAC,SAAS,IAAI,OAAO,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,eAAe,EAAE,CAAC;YACjF,IAAI,CAAC;gBACD,MAAM,SAAS,GAAG,cAAc,CAAC;oBAC7B,UAAU,EAAE,GAAG,CAAC,UAAU;oBAC1B,KAAK,EAAE,GAAG,CAAC,KAAK;oBAChB,eAAe,EAAE,GAAG,CAAC,eAAe;iBACvC,EAAE,OAAO,CAAC,CAAC;gBAEZ,IAAI,SAAS,EAAE,CAAC;oBACZ,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;oBACrC,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC;gBACxC,CAAC;YACL,CAAC;YAAC,MAAM,CAAC;gBACL,wBAAwB;YAC5B,CAAC;QACL,CAAC;QAED,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QAChC,IAAI,GAAG,EAAE,CAAC;YACN,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;gBAClB,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;YAC7C,CAAC;YACD,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC;YACvB,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;gBACZ,SAAS,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC;YAC5B,CAAC;QACL,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC;SAC3B,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;SACzC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;SACX,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC7B,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;SACrB,WAAW,CAAC,mEAAmE,CAAC;SAChF,MAAM,CAAC,QAAQ,EAAE,gCAAgC,CAAC;SAClD,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC;SACvC,MAAM,CAAC,UAAU,EAAE,4BAA4B,CAAC;SAChD,MAAM,CAAC,UAAU,EAAE,wCAAwC,CAAC;SAC5D,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QACtB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QAE/B,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;YAC1B,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;gBAClB,OAAO,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;YAChD,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;QAED,IAAI,CAAC;YACD,oBAAoB;YACpB,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;YAE9B,kDAAkD;YAClD,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;gBACnB,MAAM,YAAY,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;gBAChD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,YAAY,CAAC,OAAO,EAAE,CAAC,GAAG,KAAK,CAAC;gBAElE,4DAA4D;gBAC5D,IAAI,QAAQ,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;oBAChC,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;wBACpC,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,mCAAmC,CAAC,CAAC;oBAC3F,CAAC;oBACD,0CAA0C;gBAC9C,CAAC;YACL,CAAC;YAED,kBAAkB;YAClB,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YACjE,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;YACzD,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC;YAEnC,iBAAiB;YACjB,OAAO,CAAC,QAAQ,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YAC5C,WAAW,CAAC,OAAO,CAAC,CAAC;YAErB,uBAAuB;YACvB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACjB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,CAAC;YAED,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;gBACf,MAAM,MAAM,GAAG;oBACX,OAAO;oBACP,KAAK,EAAE;wBACH,KAAK,EAAE,UAAU;wBACjB,MAAM,EAAE,WAAW;qBACtB;oBACD,SAAS,EAAE,OAAO,CAAC,SAAS;oBAC5B,aAAa,EAAE,OAAO,CAAC,aAAa;oBACpC,QAAQ,EAAE,OAAO,CAAC,QAAQ;iBAC7B,CAAC;gBACF,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC7C,OAAO;YACX,CAAC;YAED,kBAAkB;YAClB,OAAO,CAAC,GAAG,CAAC,sBAAsB,OAAO,KAAK,CAAC,CAAC;YAChD,OAAO,CAAC,GAAG,CAAC,aAAa,WAAW,aAAa,UAAU,QAAQ,CAAC,CAAC;YACrE,OAAO,CAAC,GAAG,CAAC,sBAAsB,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC;YAClE,OAAO,CAAC,GAAG,CAAC,kBAAkB,eAAe,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YAEpE,2BAA2B;YAC3B,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACjB,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;gBACrD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACpB,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;oBACtC,KAAK,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,MAAM,EAAE,CAAC;wBAC1C,MAAM,YAAY,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;wBAC1D,OAAO,CAAC,GAAG,CAAC,OAAO,GAAG,KAAK,KAAK,GAAG,YAAY,EAAE,CAAC,CAAC;oBACvD,CAAC;gBACL,CAAC;YACL,CAAC;YAED,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;gBACjB,OAAO,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAC;YACpE,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;YAEtC,sCAAsC;YACtC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;gBAClB,IAAI,CAAC;oBACD,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;oBACzD,MAAM,kBAAkB,CAAC,UAAU,CAAC,CAAC;oBACrC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;wBACjB,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;oBAC5C,CAAC;gBACL,CAAC;gBAAC,MAAM,CAAC;oBACL,mCAAmC;gBACvC,CAAC;YACL,CAAC;QAEL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;gBAClB,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;YAC3C,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;IACL,CAAC,CAAC,CAAC;AACX,CAAC"}
|
|
@@ -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();
|