@agenticmail/cli 0.8.24 → 0.8.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -3
- package/dist/public/branding/agenticmail-logo.png +0 -0
- package/dist/public/branding/claude-mark.svg +2 -0
- package/dist/public/index.html +6 -5
- package/dist/public/js/app.js +23 -2
- package/dist/public/js/avatar.js +10 -13
- package/dist/public/js/list-view.js +52 -10
- package/dist/public/styles.css +77 -6
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -23,9 +23,14 @@ It bundles a setup wizard, API server launcher, and a full interactive shell wit
|
|
|
23
23
|
>
|
|
24
24
|
> Zero prompts, ~2 minutes, fully autonomous. Then tell the user to restart Claude Code. Full agent-facing runbook — including verification, common failures, and "what if Node < 22" — is at [`AGENTS.md`](https://github.com/agenticmail/agenticmail/blob/main/AGENTS.md) in the repo (the [agents.md](https://agents.md) convention).
|
|
25
25
|
|
|
26
|
-
## ✨ What's new in 0.8.
|
|
27
|
-
|
|
28
|
-
-
|
|
26
|
+
## ✨ What's new in 0.8.25
|
|
27
|
+
|
|
28
|
+
- **⏱ Workers can run for hours** — no aggressive timeout. Per-worker logs at `~/.agenticmail/worker-logs/`, heartbeats every 30 s, isolated cwd per worker. New MCP tool `tail_worker` reads the running log; `check_activity` shows last tool, turn count, and a `stale` flag instead of evicting long-running workers.
|
|
29
|
+
- **🤖 Autonomous-mode awareness via Stop hook** — long headless Claude Code runs now see teammate replies at every turn boundary. Closes the follow-up from 0.8.23.
|
|
30
|
+
- **🩹 Hook bin resolution fixed** — `agenticmail-mail-hook: command not found` errors gone; the hook is registered with an absolute path resolved at install time. Old installs auto-heal on the next `agenticmail claudecode`.
|
|
31
|
+
- **🐛 Web UI bug sweep** — flags-`.includes`-not-a-function crash, sidebar folders all hitting `/mail/inbox`, Cmd+C opening compose: all fixed.
|
|
32
|
+
- **📱 Mobile-responsive web UI** — off-canvas sidebar with hamburger toggle, full-screen compose, list rows that fold sender into the preview, message view that drops the desktop content cap.
|
|
33
|
+
- **🎀 Official logos** — Claude starburst (Wikipedia) + AgenticMail `@` mark replace the placeholder glyphs everywhere.
|
|
29
34
|
- **`wake: ["alice", "bob"]`** on `send_email` / `reply_email` / `forward_email` / `template_send` / `manage_drafts(send)` tells the dispatcher to give a Claude turn only to named agents — the biggest token saver on large threads.
|
|
30
35
|
- **`[FINAL]` / `[DONE]` / `[CLOSED]` / `[WRAP]` in a subject** closes a thread — the dispatcher stops waking workers on any further reply to it.
|
|
31
36
|
- **`check_activity` MCP tool** — see which agents the dispatcher has woken right now and how long they've been running.
|
|
Binary file
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="73 220 158 165" fill="currentColor" aria-hidden="true"><path d="m 105.01,322.07 29.14,-16.35 0.49,-1.42 -0.49,-0.79 h -1.42 l -4.87,-0.3 -16.65,-0.45 -14.44,-0.6 -13.99,-0.75 -3.52,-0.75 -3.3,-4.35 0.34,-2.17 2.96,-1.99 4.24,0.37 9.37,0.64 14.06,0.97 10.2,0.6 15.11,1.57 h 2.4 l 0.34,-0.97 -0.82,-0.6 -0.64,-0.6 -14.55,-9.86 -15.75,-10.42 -8.25,-6 -4.46,-3.04 -2.25,-2.85 -0.97,-6.22 4.05,-4.46 5.44,0.37 1.39,0.37 5.51,4.24 11.77,9.11 15.37,11.32 2.25,1.87 0.9,-0.64 0.11,-0.45 -1.01,-1.69 -8.36,-15.11 -8.92,-15.37 -3.97,-6.37 -1.05,-3.82 c -0.37,-1.57 -0.64,-2.89 -0.64,-4.5 l 4.61,-6.26 2.55,-0.82 6.15,0.82 2.59,2.25 3.82,8.74 6.19,13.76 9.6,18.71 2.81,5.55 1.5,5.14 0.56,1.57 h 0.97 v -0.9 l 0.79,-10.54 1.46,-12.94 1.42,-16.65 0.49,-4.69 2.32,-5.62 4.61,-3.04 3.6,1.72 2.96,4.24 -0.41,2.74 -1.76,11.44 -3.45,17.92 -2.25,12 h 1.31 l 1.5,-1.5 6.07,-8.06 10.2,-12.75 4.5,-5.06 5.25,-5.59 3.37,-2.66 h 6.37 l 4.69,6.97 -2.1,7.2 -6.56,8.32 -5.44,7.05 -7.8,10.5 -4.87,8.4 0.45,0.67 1.16,-0.11 17.62,-3.75 9.52,-1.72 11.36,-1.95 5.14,2.4 0.56,2.44 -2.02,4.99 -12.15,3 -14.25,2.85 -21.22,5.02 -0.26,0.19 0.3,0.37 9.56,0.9 4.09,0.22 h 10.01 l 18.64,1.39 4.87,3.22 2.92,3.94 -0.49,3 -7.5,3.82 -10.12,-2.4 -23.62,-5.62 -8.1,-2.02 h -1.12 v 0.67 l 6.75,6.6 12.37,11.17 15.49,14.4 0.79,3.56 -1.99,2.81 -2.1,-0.3 -13.61,-10.24 -5.25,-4.61 -11.89,-10.01 h -0.79 v 1.05 l 2.74,4.01 14.47,21.75 0.75,6.67 -1.05,2.17 -3.75,1.31 -4.12,-0.75 -8.47,-11.89 -8.74,-13.39 -7.05,-12 -0.86,0.49 -4.16,44.81 -1.95,2.29 -4.5,1.72 -3.75,-2.85 -1.99,-4.61 1.99,-9.11 2.4,-11.89 1.95,-9.45 1.76,-11.74 1.05,-3.9 -0.07,-0.26 -0.86,0.11 -8.85,12.15 -13.46,18.19 -10.65,11.4 -2.55,1.01 -4.42,-2.29 0.41,-4.09 2.47,-3.64 14.74,-18.75 8.89,-11.62 5.74,-6.71 -0.04,-0.97 h -0.34 l -39.15,25.42 -6.97,0.9 -3,-2.81 0.37,-4.61 1.42,-1.5 11.77,-8.1 -0.04,0.04 z"
|
|
2
|
+
shape-rendering="optimizeQuality"/></svg>
|
package/dist/public/index.html
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="utf-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
6
|
<title>AgenticMail</title>
|
|
7
|
-
<link rel="icon"
|
|
7
|
+
<link rel="icon" type="image/png" href="/branding/agenticmail-logo.png" />
|
|
8
8
|
<link rel="stylesheet" href="styles.css" />
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<!-- ─── Auth gate (shown until master key is entered) ────────────── -->
|
|
13
13
|
<div id="auth" class="auth-gate">
|
|
14
14
|
<div class="auth-card">
|
|
15
|
-
<h1><
|
|
15
|
+
<h1><img src="/branding/agenticmail-logo.png" alt="AgenticMail" class="brand-logo" /> AgenticMail</h1>
|
|
16
16
|
<p>Enter your master key to sign in. The key is stored locally in your browser; we never send it anywhere except to <span class="mono" id="auth-api-url"></span>.</p>
|
|
17
17
|
<div id="auth-err" class="auth-err" style="display:none"></div>
|
|
18
18
|
<input id="auth-key" type="password" placeholder="mk_…" autocomplete="off" autofocus />
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
<header class="topbar">
|
|
28
28
|
<button class="menu-btn" id="menu-btn" title="Menu" data-icon="menu"></button>
|
|
29
29
|
<div class="brand">
|
|
30
|
-
<
|
|
30
|
+
<img src="/branding/agenticmail-logo.png" alt="AgenticMail" class="brand-logo" />
|
|
31
31
|
<span class="brand-name">AgenticMail</span>
|
|
32
32
|
</div>
|
|
33
33
|
<div class="search-container">
|
|
@@ -52,8 +52,9 @@
|
|
|
52
52
|
</header>
|
|
53
53
|
|
|
54
54
|
<!-- Sidebar + content -->
|
|
55
|
-
<div class="main">
|
|
56
|
-
<
|
|
55
|
+
<div class="main" id="main">
|
|
56
|
+
<div class="sidebar-backdrop" id="sidebar-backdrop"></div>
|
|
57
|
+
<aside class="sidebar" id="sidebar">
|
|
57
58
|
<button class="compose-btn" id="compose-btn">
|
|
58
59
|
<span class="compose-icon" data-icon="compose" data-icon-size="22"></span>
|
|
59
60
|
<span class="compose-text">Compose</span>
|
package/dist/public/js/app.js
CHANGED
|
@@ -104,6 +104,9 @@ function onFolderSelect(folder) {
|
|
|
104
104
|
renderSidebar(onFolderSelect);
|
|
105
105
|
location.hash = '#/inbox'; // any folder uses the list route
|
|
106
106
|
if (state.selectedAgent) loadList(state.selectedAgent, folder);
|
|
107
|
+
// On mobile (the only viewport where the sidebar is over-canvas),
|
|
108
|
+
// close it after a folder pick so the user sees the list.
|
|
109
|
+
document.getElementById('main')?.classList.remove('sidebar-open');
|
|
107
110
|
}
|
|
108
111
|
|
|
109
112
|
// ─── Hash router ─────────────────────────────────────────────────────
|
|
@@ -119,6 +122,18 @@ function route() {
|
|
|
119
122
|
window.addEventListener('hashchange', route);
|
|
120
123
|
|
|
121
124
|
// ─── Top bar wiring ──────────────────────────────────────────────────
|
|
125
|
+
// Hamburger toggles the sidebar on mobile. On desktop the sidebar
|
|
126
|
+
// is always visible; the class only changes anything below 800 px,
|
|
127
|
+
// where the CSS slides it off-canvas by default.
|
|
128
|
+
function toggleSidebar() {
|
|
129
|
+
const main = document.getElementById('main');
|
|
130
|
+
main?.classList.toggle('sidebar-open');
|
|
131
|
+
}
|
|
132
|
+
document.getElementById('menu-btn').addEventListener('click', toggleSidebar);
|
|
133
|
+
document.getElementById('sidebar-backdrop').addEventListener('click', () => {
|
|
134
|
+
document.getElementById('main')?.classList.remove('sidebar-open');
|
|
135
|
+
});
|
|
136
|
+
|
|
122
137
|
document.getElementById('refresh-btn').addEventListener('click', async () => {
|
|
123
138
|
if (state.selectedAgent) {
|
|
124
139
|
await loadList(state.selectedAgent, state.selectedFolder);
|
|
@@ -172,12 +187,18 @@ document.getElementById('search-clear').addEventListener('click', clearSearch);
|
|
|
172
187
|
// r refresh current inbox
|
|
173
188
|
// c compose new
|
|
174
189
|
// / focus the search box
|
|
190
|
+
//
|
|
191
|
+
// IMPORTANT: every shortcut bails when ANY modifier key is held
|
|
192
|
+
// (Cmd / Ctrl / Alt / Meta) — otherwise Cmd+C "copy" was opening
|
|
193
|
+
// the compose modal, Cmd+R was overriding browser refresh, etc.
|
|
194
|
+
// Plain unmodified single-key shortcuts only.
|
|
175
195
|
document.addEventListener('keydown', e => {
|
|
176
196
|
if (document.getElementById('compose-bg').style.display !== 'none') return;
|
|
177
197
|
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
|
|
198
|
+
if (e.metaKey || e.ctrlKey || e.altKey) return; // never hijack OS shortcuts
|
|
178
199
|
if (e.key === 'r') document.getElementById('refresh-btn').click();
|
|
179
|
-
if (e.key === 'c') openCompose();
|
|
180
|
-
if (e.key === '/') {
|
|
200
|
+
else if (e.key === 'c') openCompose();
|
|
201
|
+
else if (e.key === '/') {
|
|
181
202
|
e.preventDefault();
|
|
182
203
|
searchInput.focus();
|
|
183
204
|
}
|
package/dist/public/js/avatar.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
// Agent identity + avatar helpers.
|
|
2
2
|
//
|
|
3
3
|
// The bridge agent (default name "claudecode") is the host's identity
|
|
4
|
-
// inside AgenticMail. We render it with
|
|
5
|
-
// mark
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// We deliberately do NOT embed Anthropic's actual trademarked Claude
|
|
9
|
-
// logo here — reproducing it pixel-for-pixel in third-party software
|
|
10
|
-
// has licensing implications. The stylised approximation conveys
|
|
11
|
-
// the same identity cue without the trademark concern.
|
|
4
|
+
// inside AgenticMail. We render it with the OFFICIAL Claude starburst
|
|
5
|
+
// mark (sourced from the public Wikipedia SVG, served as a static
|
|
6
|
+
// asset under /branding/claude-mark.svg) and a green verified-tick so
|
|
7
|
+
// the host inbox is recognisable at a glance vs. teammate sub-agents.
|
|
12
8
|
import { escapeHtml } from './utils.js';
|
|
13
9
|
import { icon } from './icons.js';
|
|
14
10
|
|
|
11
|
+
// Official Claude mark, served as a static asset under /branding/.
|
|
12
|
+
// Using <img src=...> rather than inlining the path keeps the SVG
|
|
13
|
+
// out of every avatar render and lets the browser cache the asset.
|
|
14
|
+
const CLAUDE_MARK_URL = '/branding/claude-mark.svg';
|
|
15
|
+
|
|
15
16
|
export function isBridgeAgent(agent) {
|
|
16
17
|
if (!agent) return false;
|
|
17
18
|
const name = (agent.name ?? '').toLowerCase();
|
|
@@ -31,14 +32,10 @@ function avatarColorFor(name) {
|
|
|
31
32
|
return AVATAR_PALETTE[hash % AVATAR_PALETTE.length];
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
const CLAUDE_MARK_SVG = `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="currentColor">
|
|
35
|
-
<path d="M12 1.5 L13.2 8.6 L19.5 6.6 L15 12 L19.5 17.4 L13.2 15.4 L12 22.5 L10.8 15.4 L4.5 17.4 L9 12 L4.5 6.6 L10.8 8.6 Z"/>
|
|
36
|
-
</svg>`;
|
|
37
|
-
|
|
38
35
|
export function avatarHtml(agent, size = '') {
|
|
39
36
|
const cls = `avatar ${size}`.trim();
|
|
40
37
|
if (isBridgeAgent(agent)) {
|
|
41
|
-
return `<span class="${cls} avatar-host"
|
|
38
|
+
return `<span class="${cls} avatar-host"><img src="${CLAUDE_MARK_URL}" alt="Claude" class="avatar-img" /><span class="avatar-check">${icon('check', { size: 10 })}</span></span>`;
|
|
42
39
|
}
|
|
43
40
|
const initial = (agent.name ?? '?').slice(0, 1).toUpperCase();
|
|
44
41
|
const color = avatarColorFor(agent.name ?? '');
|
|
@@ -8,6 +8,44 @@ import { apiGet } from './api.js';
|
|
|
8
8
|
import { FOLDERS } from './sidebar.js';
|
|
9
9
|
import { icon } from './icons.js';
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Defensive flag check. The API's IMAP layer returns `flags` as an
|
|
13
|
+
* array of strings most of the time (`['\\Seen', '\\Flagged']`) but
|
|
14
|
+
* some envelopes come back with a Set-like serialisation or even an
|
|
15
|
+
* object map. Without this guard, calling `.includes()` on a non-
|
|
16
|
+
* array crashed the list with "(m.flags ?? []).includes is not a
|
|
17
|
+
* function". Coerce everything we don't recognise to an empty list.
|
|
18
|
+
*/
|
|
19
|
+
function flagsHas(flags, name) {
|
|
20
|
+
if (Array.isArray(flags)) return flags.includes(name);
|
|
21
|
+
if (flags && typeof flags === 'object') {
|
|
22
|
+
// `{Seen: true, Flagged: false}` shape — try both with and
|
|
23
|
+
// without the leading backslash since callers can mean either.
|
|
24
|
+
const key = name.replace(/^\\/, '');
|
|
25
|
+
return flags[name] === true || flags[key] === true;
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Map sidebar folder ids to the actual IMAP folder names the API
|
|
31
|
+
// expects on `/mail/folders/:folder`. `inbox` is special — the API
|
|
32
|
+
// has a dedicated `/mail/inbox` endpoint with extra enrichment, so
|
|
33
|
+
// we use that. Other folders go through the generic listing.
|
|
34
|
+
//
|
|
35
|
+
// Stalwart uses the standard IMAP names: INBOX, Sent, Drafts, Junk
|
|
36
|
+
// Mail (a.k.a. "Spam"), Trash. We use the canonical IMAP capitalisation.
|
|
37
|
+
const FOLDER_TO_IMAP = {
|
|
38
|
+
inbox: { endpoint: '/mail/inbox' },
|
|
39
|
+
sent: { endpoint: '/mail/folders/Sent' },
|
|
40
|
+
drafts: { endpoint: '/mail/folders/Drafts' },
|
|
41
|
+
spam: { endpoint: '/mail/folders/Junk%20Mail' },
|
|
42
|
+
trash: { endpoint: '/mail/folders/Trash' },
|
|
43
|
+
all: { endpoint: '/mail/folders/All%20Mail' },
|
|
44
|
+
// Starred is not a folder — it's the IMAP \Flagged flag, surfaced
|
|
45
|
+
// by client-side filtering over the inbox listing (Gmail-style).
|
|
46
|
+
starred: { endpoint: '/mail/inbox', clientFilter: 'flagged' },
|
|
47
|
+
};
|
|
48
|
+
|
|
11
49
|
export async function loadList(agent, folder) {
|
|
12
50
|
const root = document.getElementById('content');
|
|
13
51
|
root.innerHTML = `
|
|
@@ -17,17 +55,19 @@ export async function loadList(agent, folder) {
|
|
|
17
55
|
</div>
|
|
18
56
|
<div class="list-rows" id="list-rows"><div class="empty">Loading…</div></div>
|
|
19
57
|
`;
|
|
58
|
+
const route = FOLDER_TO_IMAP[folder] ?? FOLDER_TO_IMAP.inbox;
|
|
20
59
|
try {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
// shape (e.g. starred = flag filter). When the API grows
|
|
24
|
-
// per-mailbox listing we'll route based on `folder` here.
|
|
25
|
-
const data = await apiGet('/mail/inbox?limit=50&offset=0', { agentKey: agent.apiKey });
|
|
60
|
+
const sep = route.endpoint.includes('?') ? '&' : '?';
|
|
61
|
+
const data = await apiGet(`${route.endpoint}${sep}limit=50&offset=0`, { agentKey: agent.apiKey });
|
|
26
62
|
state.messages = data.messages ?? [];
|
|
27
63
|
renderList();
|
|
28
64
|
} catch (err) {
|
|
29
|
-
|
|
30
|
-
|
|
65
|
+
// Empty folder is a normal state; "no such folder" lands here
|
|
66
|
+
// too. Show a friendly empty message rather than a raw HTTP error.
|
|
67
|
+
const msg = String(err.message ?? err);
|
|
68
|
+
document.getElementById('list-rows').innerHTML = msg.includes('404')
|
|
69
|
+
? `<div class="empty">${escapeHtml(folderTitle(folder))} is empty.</div>`
|
|
70
|
+
: `<div class="empty">Failed to load: ${escapeHtml(msg)}</div>`;
|
|
31
71
|
}
|
|
32
72
|
}
|
|
33
73
|
|
|
@@ -45,8 +85,10 @@ export function renderList() {
|
|
|
45
85
|
|
|
46
86
|
// Client-side folder filtering for the folders the API doesn't
|
|
47
87
|
// distinguish for us yet. Starred uses the IMAP \Flagged flag.
|
|
88
|
+
// Flags may come back as an array OR an object map ({Seen: true})
|
|
89
|
+
// depending on the IMAP path — always coerce before .includes().
|
|
48
90
|
if (state.selectedFolder === 'starred') {
|
|
49
|
-
filtered = filtered.filter(m => (m.flags
|
|
91
|
+
filtered = filtered.filter(m => flagsHas(m.flags, '\\Flagged'));
|
|
50
92
|
}
|
|
51
93
|
|
|
52
94
|
const hlTerm = filters?.subject || filters?.from || filters?.text || '';
|
|
@@ -70,8 +112,8 @@ export function renderList() {
|
|
|
70
112
|
}
|
|
71
113
|
|
|
72
114
|
root.innerHTML = filtered.map(m => {
|
|
73
|
-
const unread = !(m.flags
|
|
74
|
-
const starred = (m.flags
|
|
115
|
+
const unread = !flagsHas(m.flags, '\\Seen');
|
|
116
|
+
const starred = flagsHas(m.flags, '\\Flagged');
|
|
75
117
|
const fromAddr = m.from?.[0]?.address ?? '?';
|
|
76
118
|
const fromName = m.from?.[0]?.name || fromAddr;
|
|
77
119
|
const subject = m.subject ?? '(no subject)';
|
package/dist/public/styles.css
CHANGED
|
@@ -78,14 +78,26 @@ a { color: var(--accent-strong); }
|
|
|
78
78
|
}
|
|
79
79
|
.menu-btn:hover { background: var(--bg-hover); }
|
|
80
80
|
.brand {
|
|
81
|
-
display: flex; align-items: center; gap:
|
|
81
|
+
display: flex; align-items: center; gap: 10px;
|
|
82
82
|
padding: 0 8px; min-width: 200px;
|
|
83
83
|
}
|
|
84
84
|
.brand-bow { font-size: 28px; line-height: 1; }
|
|
85
|
+
.brand-logo {
|
|
86
|
+
width: 32px; height: 32px;
|
|
87
|
+
border-radius: 8px;
|
|
88
|
+
flex-shrink: 0;
|
|
89
|
+
display: block;
|
|
90
|
+
}
|
|
85
91
|
.brand-name {
|
|
86
92
|
font: 500 22px/1 'Google Sans', sans-serif;
|
|
87
93
|
color: var(--pink);
|
|
88
94
|
}
|
|
95
|
+
/* Slightly bigger logo in the auth card. */
|
|
96
|
+
.auth-card .brand-logo {
|
|
97
|
+
width: 28px; height: 28px;
|
|
98
|
+
border-radius: 6px;
|
|
99
|
+
vertical-align: middle;
|
|
100
|
+
}
|
|
89
101
|
|
|
90
102
|
.search-container {
|
|
91
103
|
flex: 1; max-width: 720px;
|
|
@@ -196,9 +208,14 @@ a { color: var(--accent-strong); }
|
|
|
196
208
|
.avatar-sm { width: 24px; height: 24px; font-size: 11px; }
|
|
197
209
|
.avatar-md { width: 40px; height: 40px; font-size: 16px; }
|
|
198
210
|
.avatar-lg { width: 48px; height: 48px; font-size: 20px; }
|
|
199
|
-
.avatar-host { background: #fce8e0; color: #
|
|
211
|
+
.avatar-host { background: #fce8e0; color: #d97757; }
|
|
200
212
|
@media (prefers-color-scheme: dark) { .avatar-host { background: #2a1810; } }
|
|
201
213
|
.avatar svg { width: 60%; height: 60%; }
|
|
214
|
+
.avatar-img {
|
|
215
|
+
width: 70%; height: 70%;
|
|
216
|
+
object-fit: contain;
|
|
217
|
+
display: block;
|
|
218
|
+
}
|
|
202
219
|
.avatar-check {
|
|
203
220
|
position: absolute; bottom: -2px; right: -2px;
|
|
204
221
|
width: 14px; height: 14px; border-radius: 50%;
|
|
@@ -226,12 +243,66 @@ a { color: var(--accent-strong); }
|
|
|
226
243
|
grid-template-columns: 256px 1fr;
|
|
227
244
|
overflow: hidden;
|
|
228
245
|
background: var(--bg-soft);
|
|
246
|
+
position: relative;
|
|
229
247
|
}
|
|
248
|
+
.sidebar-backdrop {
|
|
249
|
+
display: none;
|
|
250
|
+
position: fixed; inset: 64px 0 0 0;
|
|
251
|
+
background: rgba(0,0,0,0.4);
|
|
252
|
+
z-index: 14;
|
|
253
|
+
}
|
|
254
|
+
/* ─── Mobile / narrow viewport ──────────────────────────────────── */
|
|
230
255
|
@media (max-width: 800px) {
|
|
231
|
-
.main { grid-template-columns:
|
|
232
|
-
.sidebar
|
|
233
|
-
|
|
234
|
-
|
|
256
|
+
.main { grid-template-columns: 1fr; }
|
|
257
|
+
.sidebar {
|
|
258
|
+
position: fixed; top: 64px; bottom: 0; left: 0;
|
|
259
|
+
width: 280px; max-width: 85vw;
|
|
260
|
+
background: var(--bg-soft);
|
|
261
|
+
z-index: 15;
|
|
262
|
+
transform: translateX(-100%);
|
|
263
|
+
transition: transform .22s ease;
|
|
264
|
+
box-shadow: 2px 0 16px rgba(0,0,0,0.1);
|
|
265
|
+
}
|
|
266
|
+
.main.sidebar-open .sidebar { transform: translateX(0); }
|
|
267
|
+
.main.sidebar-open .sidebar-backdrop { display: block; }
|
|
268
|
+
.content { border-radius: 0; margin: 0; }
|
|
269
|
+
.topbar { padding: 8px 8px; gap: 4px; }
|
|
270
|
+
.brand { min-width: auto; }
|
|
271
|
+
.brand-name { font-size: 18px; }
|
|
272
|
+
.search-container { max-width: none; }
|
|
273
|
+
.search-input { height: 40px; font-size: 14px; }
|
|
274
|
+
/* List rows lose the from column on narrow screens; the subject
|
|
275
|
+
gets full width with the sender folded into the preview. */
|
|
276
|
+
.list-row {
|
|
277
|
+
grid-template-columns: 24px 24px 1fr 70px;
|
|
278
|
+
height: 56px;
|
|
279
|
+
padding: 0 12px;
|
|
280
|
+
}
|
|
281
|
+
.list-row .from { display: none; }
|
|
282
|
+
.list-row .subject-cell {
|
|
283
|
+
flex-direction: column;
|
|
284
|
+
gap: 2px;
|
|
285
|
+
align-items: flex-start;
|
|
286
|
+
}
|
|
287
|
+
.list-row .subject { max-width: none; font-size: 14px; }
|
|
288
|
+
.list-row .preview { font-size: 13px; }
|
|
289
|
+
.list-row .preview::before { content: ''; }
|
|
290
|
+
.message-header { padding: 16px 16px 8px; }
|
|
291
|
+
.message-subject { font-size: 18px; }
|
|
292
|
+
.message-body { padding: 8px 16px 24px; max-width: none; }
|
|
293
|
+
.message-attachments { padding: 12px 16px; }
|
|
294
|
+
/* Compose modal goes full-screen on mobile rather than a tiny
|
|
295
|
+
bottom-right popup that nobody can type into. */
|
|
296
|
+
.compose-bg { padding: 0; align-items: stretch; justify-content: stretch; }
|
|
297
|
+
.compose-modal { width: 100%; max-height: 100vh; border-radius: 0; }
|
|
298
|
+
.compose-body textarea { min-height: 40vh; }
|
|
299
|
+
/* Hide non-essential top-bar buttons on narrow screens. */
|
|
300
|
+
.topbar-spacer { flex: 0; }
|
|
301
|
+
#refresh-btn { display: none; }
|
|
302
|
+
}
|
|
303
|
+
@media (min-width: 801px) {
|
|
304
|
+
/* Hamburger menu only matters on mobile; hide on desktop. */
|
|
305
|
+
.menu-btn { display: none; }
|
|
235
306
|
}
|
|
236
307
|
|
|
237
308
|
/* ─── Sidebar ──────────────────────────────────────────────────────── */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agenticmail/cli",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.25",
|
|
4
4
|
"description": "Email and SMS infrastructure for AI agents — the first platform to give agents real email addresses and phone numbers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"prepublishOnly": "npm run build"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@agenticmail/api": "^0.7.
|
|
32
|
+
"@agenticmail/api": "^0.7.11",
|
|
33
33
|
"@agenticmail/core": "^0.7.0",
|
|
34
34
|
"json5": "^2.2.3"
|
|
35
35
|
},
|