oysterun 1.4.6 → 1.4.8
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/dev/client/web/index.html +761 -116
- package/dev/client/web-chat/dist/assets/{ReactPrism-lmxWDpVG.js → ReactPrism-C6f8462z.js} +1 -1
- package/dev/client/web-chat/dist/assets/{ReactPrism-lmxWDpVG.js.map → ReactPrism-C6f8462z.js.map} +1 -1
- package/dev/client/web-chat/dist/assets/{index-6GA21osP.js → index-BXXBmMM8.js} +93 -93
- package/dev/client/web-chat/dist/assets/index-BXXBmMM8.js.map +1 -0
- package/dev/client/web-chat/dist/assets/{index-DgT92KX_.js → index-Bhqm7xK7.js} +2 -2
- package/dev/client/web-chat/dist/assets/{index-DgT92KX_.js.map → index-Bhqm7xK7.js.map} +1 -1
- package/dev/client/web-chat/dist/assets/{index-BrEPk04R.js → index-tlM2bptc.js} +1 -1
- package/dev/client/web-chat/dist/assets/{index-BrEPk04R.js.map → index-tlM2bptc.js.map} +1 -1
- package/dev/client/web-chat/dist/assets/{pdf-BgTAydf1.js → pdf-D0Ks17S3.js} +3 -3
- package/dev/client/web-chat/dist/assets/{pdf-BgTAydf1.js.map → pdf-D0Ks17S3.js.map} +1 -1
- package/dev/client/web-chat/dist/assets/{web-BPMNryMv.js → web-Bnl6J5CG.js} +1 -1
- package/dev/client/web-chat/dist/assets/{web-BPMNryMv.js.map → web-Bnl6J5CG.js.map} +1 -1
- package/dev/client/web-chat/dist/assets/{web-B6RLoRzA.js → web-lzzU_sai.js} +1 -1
- package/dev/client/web-chat/dist/assets/{web-B6RLoRzA.js.map → web-lzzU_sai.js.map} +1 -1
- package/dev/client/web-chat/dist/index.html +1 -1
- package/docs/routec/dev/scheduler_mail_skill.md +96 -0
- package/host-service/assets/product-skills/Oysterun/modules/oysterun-mail/SKILL.md +28 -4
- package/host-service/assets/product-skills/Oysterun/modules/oysterun-mail/scripts/send_mail.mjs +25 -23
- package/host-service/assets/product-skills/Oysterun/modules/oysterun-scheduler/SKILL.md +29 -0
- package/host-service/assets/product-skills/oysterun-mail/SKILL.md +28 -4
- package/host-service/assets/product-skills/oysterun-mail/scripts/send_mail.mjs +25 -23
- package/host-service/assets/product-skills/oysterun-scheduler/SKILL.md +29 -0
- package/host-service/cli/product-cli.mjs +60 -7
- package/host-service/folder-browser.mjs +129 -2
- package/host-service/mail-notification-dispatcher.mjs +2 -2
- package/host-service/mail-store.mjs +17 -26
- package/host-service/package.json +1 -1
- package/host-service/scheduler-direct-provider-runner.mjs +8 -1
- package/host-service/scheduler-service.mjs +49 -0
- package/host-service/server.mjs +71 -7
- package/host-service/session-loop-definitions.mjs +36 -1
- package/host-service/session-manager.mjs +35 -1
- package/host-service/templates/demo-agents/oysterun-github-tracker/.codex/prompts/scheduler_task.md +71 -0
- package/host-service/templates/demo-agents/oysterun-github-tracker/.oysterun/config.json +5 -1
- package/host-service/templates/demo-agents/oysterun-github-tracker/.oysterun/schedulers.json +60 -0
- package/host-service/templates/demo-agents/oysterun-github-tracker/README.md +40 -5
- package/host-service/templates/demo-agents/oysterun-github-tracker/config.json +18 -0
- package/host-service/templates/demo-agents/oysterun-github-tracker/lib/github_tracker.py +247 -0
- package/host-service/templates/demo-agents/oysterun-github-tracker/tasks/repo_crawler_rich.py +825 -0
- package/package.json +1 -1
- package/static/site/index.html +13 -0
- package/tool_scripts/install_oysterun_launch_agents.sh +4 -0
- package/dev/client/web-chat/dist/assets/index-6GA21osP.js.map +0 -1
- package/host-service/templates/demo-agents/oysterun-github-tracker/agent_brief.md +0 -11
- package/host-service/templates/demo-agents/oysterun-github-tracker/issues.md +0 -11
|
@@ -1160,7 +1160,8 @@
|
|
|
1160
1160
|
.topbar.sessions-mode,
|
|
1161
1161
|
.topbar.scheduler-mode,
|
|
1162
1162
|
.topbar.explorer-mode,
|
|
1163
|
-
.topbar.session-loop-mode
|
|
1163
|
+
.topbar.session-loop-mode,
|
|
1164
|
+
.topbar.mail-detail-mode {
|
|
1164
1165
|
display: grid;
|
|
1165
1166
|
grid-template-columns: 58px minmax(0, 1fr) 58px;
|
|
1166
1167
|
gap: 0;
|
|
@@ -1175,7 +1176,8 @@
|
|
|
1175
1176
|
.topbar.sessions-mode .topbar-left,
|
|
1176
1177
|
.topbar.scheduler-mode .topbar-left,
|
|
1177
1178
|
.topbar.explorer-mode .topbar-left,
|
|
1178
|
-
.topbar.session-loop-mode .topbar-left
|
|
1179
|
+
.topbar.session-loop-mode .topbar-left,
|
|
1180
|
+
.topbar.mail-detail-mode .topbar-left {
|
|
1179
1181
|
display: contents;
|
|
1180
1182
|
}
|
|
1181
1183
|
|
|
@@ -1192,7 +1194,8 @@
|
|
|
1192
1194
|
|
|
1193
1195
|
.topbar.scheduler-setup-mode #topbar-back-btn,
|
|
1194
1196
|
.topbar.explorer-mode #topbar-back-btn,
|
|
1195
|
-
.topbar.session-loop-mode #topbar-back-btn
|
|
1197
|
+
.topbar.session-loop-mode #topbar-back-btn,
|
|
1198
|
+
.topbar.mail-detail-mode #topbar-back-btn {
|
|
1196
1199
|
grid-column: 1;
|
|
1197
1200
|
justify-self: start;
|
|
1198
1201
|
color: var(--accent);
|
|
@@ -1201,7 +1204,8 @@
|
|
|
1201
1204
|
.topbar.sessions-mode .topbar-title,
|
|
1202
1205
|
.topbar.scheduler-mode .topbar-title,
|
|
1203
1206
|
.topbar.explorer-mode .topbar-title,
|
|
1204
|
-
.topbar.session-loop-mode .topbar-title
|
|
1207
|
+
.topbar.session-loop-mode .topbar-title,
|
|
1208
|
+
.topbar.mail-detail-mode .topbar-title {
|
|
1205
1209
|
grid-column: 2;
|
|
1206
1210
|
justify-self: center;
|
|
1207
1211
|
text-align: center;
|
|
@@ -1223,7 +1227,8 @@
|
|
|
1223
1227
|
.topbar.sessions-mode .topbar-title strong,
|
|
1224
1228
|
.topbar.scheduler-mode .topbar-title strong,
|
|
1225
1229
|
.topbar.explorer-mode .page-title strong,
|
|
1226
|
-
.topbar.session-loop-mode .page-title strong
|
|
1230
|
+
.topbar.session-loop-mode .page-title strong,
|
|
1231
|
+
.topbar.mail-detail-mode .page-title strong {
|
|
1227
1232
|
font-family: var(--font-ui);
|
|
1228
1233
|
font-size: 20px;
|
|
1229
1234
|
font-weight: 700;
|
|
@@ -1244,14 +1249,16 @@
|
|
|
1244
1249
|
}
|
|
1245
1250
|
|
|
1246
1251
|
.topbar.explorer-mode .page-title span,
|
|
1247
|
-
.topbar.session-loop-mode .page-title span
|
|
1252
|
+
.topbar.session-loop-mode .page-title span,
|
|
1253
|
+
.topbar.mail-detail-mode .page-title span {
|
|
1248
1254
|
display: none;
|
|
1249
1255
|
}
|
|
1250
1256
|
|
|
1251
1257
|
.topbar.sessions-mode .topbar-right,
|
|
1252
1258
|
.topbar.scheduler-mode .topbar-right,
|
|
1253
1259
|
.topbar.explorer-mode .topbar-right,
|
|
1254
|
-
.topbar.session-loop-mode .topbar-right
|
|
1260
|
+
.topbar.session-loop-mode .topbar-right,
|
|
1261
|
+
.topbar.mail-detail-mode .topbar-right {
|
|
1255
1262
|
grid-column: 3;
|
|
1256
1263
|
justify-self: end;
|
|
1257
1264
|
}
|
|
@@ -4430,6 +4437,181 @@
|
|
|
4430
4437
|
outline: none;
|
|
4431
4438
|
}
|
|
4432
4439
|
|
|
4440
|
+
.mail-row-actions {
|
|
4441
|
+
display: grid;
|
|
4442
|
+
place-items: start center;
|
|
4443
|
+
padding: 10px 10px 0 0;
|
|
4444
|
+
}
|
|
4445
|
+
|
|
4446
|
+
.mail-row-menu-button {
|
|
4447
|
+
width: 36px;
|
|
4448
|
+
height: 36px;
|
|
4449
|
+
display: grid;
|
|
4450
|
+
place-items: center;
|
|
4451
|
+
border-radius: 50%;
|
|
4452
|
+
background: transparent;
|
|
4453
|
+
color: #7f715f;
|
|
4454
|
+
cursor: pointer;
|
|
4455
|
+
}
|
|
4456
|
+
|
|
4457
|
+
.mail-row-menu-button:hover,
|
|
4458
|
+
.mail-row-menu-button:focus-visible {
|
|
4459
|
+
transform: none;
|
|
4460
|
+
background: rgba(39, 28, 18, 0.08);
|
|
4461
|
+
outline: none;
|
|
4462
|
+
}
|
|
4463
|
+
|
|
4464
|
+
.mail-row-menu-button span::before {
|
|
4465
|
+
content: "\2022\2022\2022";
|
|
4466
|
+
display: block;
|
|
4467
|
+
font-size: 13px;
|
|
4468
|
+
letter-spacing: 2px;
|
|
4469
|
+
line-height: 1;
|
|
4470
|
+
}
|
|
4471
|
+
|
|
4472
|
+
.topbar-mail-actions {
|
|
4473
|
+
align-self: center;
|
|
4474
|
+
justify-self: end;
|
|
4475
|
+
}
|
|
4476
|
+
|
|
4477
|
+
.mail-detail {
|
|
4478
|
+
display: grid;
|
|
4479
|
+
gap: 14px;
|
|
4480
|
+
width: 100%;
|
|
4481
|
+
min-width: 0;
|
|
4482
|
+
}
|
|
4483
|
+
|
|
4484
|
+
.mail-detail-header {
|
|
4485
|
+
display: grid;
|
|
4486
|
+
gap: 6px;
|
|
4487
|
+
min-width: 0;
|
|
4488
|
+
padding: 0 2px;
|
|
4489
|
+
}
|
|
4490
|
+
|
|
4491
|
+
.mail-detail-title {
|
|
4492
|
+
margin: 0;
|
|
4493
|
+
min-width: 0;
|
|
4494
|
+
color: var(--ink);
|
|
4495
|
+
font-family: var(--font-ui);
|
|
4496
|
+
font-size: clamp(22px, 5vw, 30px);
|
|
4497
|
+
font-weight: 750;
|
|
4498
|
+
line-height: 1.15;
|
|
4499
|
+
letter-spacing: 0;
|
|
4500
|
+
overflow-wrap: anywhere;
|
|
4501
|
+
word-break: break-word;
|
|
4502
|
+
}
|
|
4503
|
+
|
|
4504
|
+
.mail-detail-meta {
|
|
4505
|
+
display: flex;
|
|
4506
|
+
flex-wrap: wrap;
|
|
4507
|
+
gap: 4px 8px;
|
|
4508
|
+
min-width: 0;
|
|
4509
|
+
color: var(--ink-soft);
|
|
4510
|
+
font-size: 12px;
|
|
4511
|
+
line-height: 1.45;
|
|
4512
|
+
}
|
|
4513
|
+
|
|
4514
|
+
.mail-detail-meta span {
|
|
4515
|
+
min-width: 0;
|
|
4516
|
+
overflow-wrap: anywhere;
|
|
4517
|
+
word-break: break-word;
|
|
4518
|
+
}
|
|
4519
|
+
|
|
4520
|
+
.mail-detail-meta span + span::before {
|
|
4521
|
+
content: "\00b7";
|
|
4522
|
+
margin-right: 8px;
|
|
4523
|
+
color: rgba(101, 76, 51, 0.45);
|
|
4524
|
+
}
|
|
4525
|
+
|
|
4526
|
+
.mail-detail-body {
|
|
4527
|
+
width: 100%;
|
|
4528
|
+
min-width: 0;
|
|
4529
|
+
}
|
|
4530
|
+
|
|
4531
|
+
.mail-html-frame-shell {
|
|
4532
|
+
width: 100%;
|
|
4533
|
+
min-width: 0;
|
|
4534
|
+
background: transparent;
|
|
4535
|
+
}
|
|
4536
|
+
|
|
4537
|
+
.mail-html-frame {
|
|
4538
|
+
display: block;
|
|
4539
|
+
width: 100%;
|
|
4540
|
+
min-width: 0;
|
|
4541
|
+
min-height: min(640px, calc(100vh - var(--topbar-height) - 148px));
|
|
4542
|
+
border: 0;
|
|
4543
|
+
background: transparent;
|
|
4544
|
+
}
|
|
4545
|
+
|
|
4546
|
+
.mail-row-menu-layer {
|
|
4547
|
+
position: fixed;
|
|
4548
|
+
inset: 0;
|
|
4549
|
+
z-index: 10000;
|
|
4550
|
+
background: transparent;
|
|
4551
|
+
pointer-events: auto;
|
|
4552
|
+
}
|
|
4553
|
+
|
|
4554
|
+
.mail-row-menu-panel {
|
|
4555
|
+
position: fixed;
|
|
4556
|
+
width: 190px;
|
|
4557
|
+
padding: 6px;
|
|
4558
|
+
border: 1px solid var(--line);
|
|
4559
|
+
border-radius: 14px;
|
|
4560
|
+
background: rgba(255, 253, 250, 0.98);
|
|
4561
|
+
box-shadow: var(--shadow);
|
|
4562
|
+
pointer-events: auto;
|
|
4563
|
+
}
|
|
4564
|
+
|
|
4565
|
+
.mail-row-menu-action {
|
|
4566
|
+
width: 100%;
|
|
4567
|
+
min-height: 36px;
|
|
4568
|
+
display: grid;
|
|
4569
|
+
grid-template-columns: 22px minmax(0, 1fr);
|
|
4570
|
+
gap: 8px;
|
|
4571
|
+
align-items: center;
|
|
4572
|
+
padding: 8px 10px;
|
|
4573
|
+
border-radius: 10px;
|
|
4574
|
+
background: transparent;
|
|
4575
|
+
color: var(--ink);
|
|
4576
|
+
font-size: 13px;
|
|
4577
|
+
font-weight: 700;
|
|
4578
|
+
text-align: left;
|
|
4579
|
+
}
|
|
4580
|
+
|
|
4581
|
+
.mail-row-menu-action-icon {
|
|
4582
|
+
width: 22px;
|
|
4583
|
+
height: 22px;
|
|
4584
|
+
display: grid;
|
|
4585
|
+
place-items: center;
|
|
4586
|
+
color: #7f715f;
|
|
4587
|
+
}
|
|
4588
|
+
|
|
4589
|
+
.mail-row-menu-action-icon svg {
|
|
4590
|
+
width: 18px;
|
|
4591
|
+
height: 18px;
|
|
4592
|
+
display: block;
|
|
4593
|
+
fill: none;
|
|
4594
|
+
stroke: currentColor;
|
|
4595
|
+
stroke-width: 1.8;
|
|
4596
|
+
stroke-linecap: round;
|
|
4597
|
+
stroke-linejoin: round;
|
|
4598
|
+
}
|
|
4599
|
+
|
|
4600
|
+
.mail-row-menu-action:hover,
|
|
4601
|
+
.mail-row-menu-action:focus-visible {
|
|
4602
|
+
transform: none;
|
|
4603
|
+
background: rgba(39, 28, 18, 0.08);
|
|
4604
|
+
outline: none;
|
|
4605
|
+
}
|
|
4606
|
+
|
|
4607
|
+
.mail-row-menu-action.danger {
|
|
4608
|
+
color: var(--red);
|
|
4609
|
+
}
|
|
4610
|
+
|
|
4611
|
+
.mail-row-menu-action.danger .mail-row-menu-action-icon {
|
|
4612
|
+
color: var(--red);
|
|
4613
|
+
}
|
|
4614
|
+
|
|
4433
4615
|
.session-row-menu {
|
|
4434
4616
|
position: relative;
|
|
4435
4617
|
align-self: start;
|
|
@@ -7197,11 +7379,46 @@
|
|
|
7197
7379
|
white-space: nowrap;
|
|
7198
7380
|
}
|
|
7199
7381
|
|
|
7382
|
+
.bottom-nav-item .bottom-nav-icon {
|
|
7383
|
+
position: relative;
|
|
7384
|
+
width: 28px;
|
|
7385
|
+
height: 22px;
|
|
7386
|
+
display: grid;
|
|
7387
|
+
place-items: center;
|
|
7388
|
+
overflow: visible;
|
|
7389
|
+
text-overflow: clip;
|
|
7390
|
+
}
|
|
7391
|
+
|
|
7200
7392
|
.bottom-nav-item svg {
|
|
7201
7393
|
width: 18px;
|
|
7202
7394
|
height: 18px;
|
|
7203
7395
|
}
|
|
7204
7396
|
|
|
7397
|
+
.bottom-nav-item .bottom-nav-mail-badge {
|
|
7398
|
+
position: absolute;
|
|
7399
|
+
top: -7px;
|
|
7400
|
+
right: -9px;
|
|
7401
|
+
min-width: 17px;
|
|
7402
|
+
height: 17px;
|
|
7403
|
+
display: inline-flex;
|
|
7404
|
+
align-items: center;
|
|
7405
|
+
justify-content: center;
|
|
7406
|
+
padding: 0 4px;
|
|
7407
|
+
border-radius: 999px;
|
|
7408
|
+
border: 1.5px solid rgba(248, 242, 233, 0.96);
|
|
7409
|
+
background: #ff3b30;
|
|
7410
|
+
color: #fff;
|
|
7411
|
+
box-shadow: 0 2px 7px rgba(165, 34, 27, 0.28);
|
|
7412
|
+
font-size: 10px;
|
|
7413
|
+
font-weight: 500;
|
|
7414
|
+
line-height: 1;
|
|
7415
|
+
letter-spacing: 0;
|
|
7416
|
+
pointer-events: none;
|
|
7417
|
+
overflow: visible;
|
|
7418
|
+
text-overflow: clip;
|
|
7419
|
+
white-space: nowrap;
|
|
7420
|
+
}
|
|
7421
|
+
|
|
7205
7422
|
.bottom-nav-item.active {
|
|
7206
7423
|
background: rgba(185, 99, 53, 0.12);
|
|
7207
7424
|
color: var(--ink);
|
|
@@ -7593,6 +7810,18 @@
|
|
|
7593
7810
|
>
|
|
7594
7811
|
Save
|
|
7595
7812
|
</button>
|
|
7813
|
+
<button
|
|
7814
|
+
class="mail-row-menu-button topbar-mail-actions hidden"
|
|
7815
|
+
id="topbar-mail-actions-btn"
|
|
7816
|
+
type="button"
|
|
7817
|
+
title="Mail actions"
|
|
7818
|
+
aria-label="Mail actions"
|
|
7819
|
+
data-mail-menu-action="open"
|
|
7820
|
+
data-mail-id=""
|
|
7821
|
+
data-oysterun-mail-detail-actions="topbar_overflow_menu"
|
|
7822
|
+
>
|
|
7823
|
+
<span aria-hidden="true"></span>
|
|
7824
|
+
</button>
|
|
7596
7825
|
<button
|
|
7597
7826
|
class="topbar-circle-btn hidden"
|
|
7598
7827
|
id="btn-agent-site"
|
|
@@ -9863,6 +10092,11 @@ Terminal output will appear here.</pre
|
|
|
9863
10092
|
class="hidden"
|
|
9864
10093
|
data-oysterun-mail-detail="host_owned_mail_item"
|
|
9865
10094
|
></div>
|
|
10095
|
+
<div
|
|
10096
|
+
class="mail-row-menu-layer hidden"
|
|
10097
|
+
id="mail-row-menu-layer"
|
|
10098
|
+
data-oysterun-mail-row-menu-layer="true"
|
|
10099
|
+
></div>
|
|
9866
10100
|
</section>
|
|
9867
10101
|
</div>
|
|
9868
10102
|
</div>
|
|
@@ -10785,35 +11019,39 @@ Waiting for Claude login output…</pre
|
|
|
10785
11019
|
data-oysterun-mail-tab="true"
|
|
10786
11020
|
onClick=${call("switchTab", "mail")}
|
|
10787
11021
|
>
|
|
10788
|
-
<
|
|
10789
|
-
|
|
11022
|
+
<span
|
|
11023
|
+
class="bottom-nav-icon bottom-nav-mail-icon"
|
|
10790
11024
|
aria-hidden="true"
|
|
10791
|
-
focusable="false"
|
|
10792
|
-
data-oysterun-bottom-tab-icon="mail"
|
|
10793
11025
|
>
|
|
10794
|
-
<
|
|
10795
|
-
|
|
10796
|
-
|
|
10797
|
-
|
|
10798
|
-
|
|
10799
|
-
|
|
10800
|
-
|
|
10801
|
-
|
|
10802
|
-
|
|
10803
|
-
|
|
10804
|
-
|
|
10805
|
-
|
|
10806
|
-
|
|
10807
|
-
|
|
10808
|
-
|
|
10809
|
-
|
|
11026
|
+
<svg
|
|
11027
|
+
viewBox="0 0 24 24"
|
|
11028
|
+
focusable="false"
|
|
11029
|
+
data-oysterun-bottom-tab-icon="mail"
|
|
11030
|
+
>
|
|
11031
|
+
<path
|
|
11032
|
+
d="M4.8 6h14.4c1 0 1.8.8 1.8 1.8v8.4c0 1-.8 1.8-1.8 1.8H4.8c-1 0-1.8-.8-1.8-1.8V7.8C3 6.8 3.8 6 4.8 6Z"
|
|
11033
|
+
fill="none"
|
|
11034
|
+
stroke="currentColor"
|
|
11035
|
+
stroke-width="1.7"
|
|
11036
|
+
stroke-linejoin="round"
|
|
11037
|
+
></path>
|
|
11038
|
+
<path
|
|
11039
|
+
d="m4.5 7.5 7.5 5.25 7.5-5.25"
|
|
11040
|
+
fill="none"
|
|
11041
|
+
stroke="currentColor"
|
|
11042
|
+
stroke-width="1.7"
|
|
11043
|
+
stroke-linecap="round"
|
|
11044
|
+
stroke-linejoin="round"
|
|
11045
|
+
></path>
|
|
11046
|
+
</svg>
|
|
11047
|
+
<span
|
|
11048
|
+
class="bottom-nav-mail-badge hidden"
|
|
11049
|
+
id="mail-unread-badge"
|
|
11050
|
+
data-oysterun-mail-unread-badge="true"
|
|
11051
|
+
aria-label="Unread mail count"
|
|
11052
|
+
></span>
|
|
11053
|
+
</span>
|
|
10810
11054
|
<span>Mail</span>
|
|
10811
|
-
<span
|
|
10812
|
-
class="pill hidden"
|
|
10813
|
-
id="mail-unread-badge"
|
|
10814
|
-
data-oysterun-mail-unread-badge="true"
|
|
10815
|
-
aria-label="Unread mail count"
|
|
10816
|
-
></span>
|
|
10817
11055
|
</button>
|
|
10818
11056
|
</nav>
|
|
10819
11057
|
</div>
|
|
@@ -11347,6 +11585,7 @@ Waiting for Claude login output…</pre
|
|
|
11347
11585
|
loaded: false,
|
|
11348
11586
|
loading: false,
|
|
11349
11587
|
saving: false,
|
|
11588
|
+
pendingTargets: {},
|
|
11350
11589
|
editingId: null,
|
|
11351
11590
|
error: "",
|
|
11352
11591
|
};
|
|
@@ -12546,6 +12785,7 @@ Waiting for Claude login output…</pre
|
|
|
12546
12785
|
let sessionLoopState = createSessionLoopState();
|
|
12547
12786
|
let hostSchedulerState = createHostSchedulerState();
|
|
12548
12787
|
let mailState = createMailState();
|
|
12788
|
+
let mailRowActionMenuState = null;
|
|
12549
12789
|
let schedulerSetupCopyState = createSchedulerSetupCopyState();
|
|
12550
12790
|
let hostSchedulerActionMenuState = null;
|
|
12551
12791
|
let sessionLoopActionMenuState = null;
|
|
@@ -27749,8 +27989,8 @@ Waiting for Claude login output…</pre
|
|
|
27749
27989
|
if (screen === "mail") {
|
|
27750
27990
|
if (normalized.mailId) {
|
|
27751
27991
|
return {
|
|
27752
|
-
title: "
|
|
27753
|
-
subtitle: "
|
|
27992
|
+
title: "Email",
|
|
27993
|
+
subtitle: "",
|
|
27754
27994
|
};
|
|
27755
27995
|
}
|
|
27756
27996
|
return {
|
|
@@ -27839,6 +28079,7 @@ Waiting for Claude login output…</pre
|
|
|
27839
28079
|
const isAgentProfile = screen === "agent-profile";
|
|
27840
28080
|
const isBrowser = screen === "browser";
|
|
27841
28081
|
const currentRoute = normalizeClientRoute(getCurrentRoute());
|
|
28082
|
+
const isMailDetail = screen === "mail" && Boolean(currentRoute.mailId);
|
|
27842
28083
|
const isExplorer = screen === "explorer";
|
|
27843
28084
|
const isSessionSetupFolderPicker =
|
|
27844
28085
|
screen === "folder-picker" &&
|
|
@@ -27873,6 +28114,30 @@ Waiting for Claude login output…</pre
|
|
|
27873
28114
|
setVisible("topbar-scheduler-new-btn", isSchedulerList);
|
|
27874
28115
|
setVisible("topbar-session-loop-new-btn", isSessionLoop);
|
|
27875
28116
|
setVisible("topbar-explorer-add-folder-btn", showTopbarAddFolder);
|
|
28117
|
+
setVisible("topbar-mail-actions-btn", isMailDetail);
|
|
28118
|
+
const topbarMailActionsButton = $("topbar-mail-actions-btn");
|
|
28119
|
+
if (topbarMailActionsButton) {
|
|
28120
|
+
if (isMailDetail) {
|
|
28121
|
+
topbarMailActionsButton.setAttribute(
|
|
28122
|
+
"data-mail-id",
|
|
28123
|
+
currentRoute.mailId
|
|
28124
|
+
);
|
|
28125
|
+
const item =
|
|
28126
|
+
mailState.selectedItem ||
|
|
28127
|
+
mailState.itemById.get(currentRoute.mailId) ||
|
|
28128
|
+
null;
|
|
28129
|
+
topbarMailActionsButton.setAttribute(
|
|
28130
|
+
"aria-label",
|
|
28131
|
+
`Mail actions${item?.title ? ` for ${item.title}` : ""}`
|
|
28132
|
+
);
|
|
28133
|
+
topbarMailActionsButton.disabled =
|
|
28134
|
+
mailState.actionBusyId === currentRoute.mailId;
|
|
28135
|
+
} else {
|
|
28136
|
+
topbarMailActionsButton.removeAttribute("data-mail-id");
|
|
28137
|
+
topbarMailActionsButton.disabled = false;
|
|
28138
|
+
topbarMailActionsButton.setAttribute("aria-label", "Mail actions");
|
|
28139
|
+
}
|
|
28140
|
+
}
|
|
27876
28141
|
const topbarExplorerAddFolderButton = $(
|
|
27877
28142
|
"topbar-explorer-add-folder-btn"
|
|
27878
28143
|
);
|
|
@@ -28060,6 +28325,7 @@ Waiting for Claude login output…</pre
|
|
|
28060
28325
|
$("topbar")?.classList.toggle("scheduler-mode", isSchedulerList);
|
|
28061
28326
|
$("topbar")?.classList.toggle("explorer-mode", isExplorer);
|
|
28062
28327
|
$("topbar")?.classList.toggle("session-loop-mode", isSessionLoop);
|
|
28328
|
+
$("topbar")?.classList.toggle("mail-detail-mode", isMailDetail);
|
|
28063
28329
|
$("topbar")?.classList.toggle("browser-mode", isBrowser);
|
|
28064
28330
|
$("topbar")?.classList.toggle(
|
|
28065
28331
|
"scheduler-setup-mode",
|
|
@@ -30521,6 +30787,10 @@ Waiting for Claude login output…</pre
|
|
|
30521
30787
|
badge.textContent = count > 99 ? "99+" : String(count);
|
|
30522
30788
|
badge.classList.toggle("hidden", count <= 0);
|
|
30523
30789
|
badge.setAttribute("data-oysterun-mail-unread-count", String(count));
|
|
30790
|
+
badge.setAttribute(
|
|
30791
|
+
"aria-label",
|
|
30792
|
+
count === 1 ? "1 unread mail" : `${count} unread mail`
|
|
30793
|
+
);
|
|
30524
30794
|
}
|
|
30525
30795
|
|
|
30526
30796
|
function renderMailFilterBar() {
|
|
@@ -30588,6 +30858,122 @@ Waiting for Claude login output…</pre
|
|
|
30588
30858
|
`;
|
|
30589
30859
|
}
|
|
30590
30860
|
|
|
30861
|
+
function renderMailActionIcon(name) {
|
|
30862
|
+
if (name === "read") {
|
|
30863
|
+
return `
|
|
30864
|
+
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
|
|
30865
|
+
<path d="M4.5 7h15v10h-15z" />
|
|
30866
|
+
<path d="m5 8 7 5 7-5" />
|
|
30867
|
+
<path d="m8 12 2.4 2.4L16 9" />
|
|
30868
|
+
</svg>
|
|
30869
|
+
`;
|
|
30870
|
+
}
|
|
30871
|
+
if (name === "unread") {
|
|
30872
|
+
return `
|
|
30873
|
+
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
|
|
30874
|
+
<path d="M4.5 7h15v10h-15z" />
|
|
30875
|
+
<path d="m5 8 7 5 7-5" />
|
|
30876
|
+
<circle cx="18" cy="6" r="2.2" />
|
|
30877
|
+
</svg>
|
|
30878
|
+
`;
|
|
30879
|
+
}
|
|
30880
|
+
if (name === "archive") {
|
|
30881
|
+
return `
|
|
30882
|
+
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
|
|
30883
|
+
<path d="M4.5 6.5h15v3h-15z" />
|
|
30884
|
+
<path d="M6 9.5v8h12v-8" />
|
|
30885
|
+
<path d="M9.5 13h5" />
|
|
30886
|
+
</svg>
|
|
30887
|
+
`;
|
|
30888
|
+
}
|
|
30889
|
+
if (name === "unarchive") {
|
|
30890
|
+
return `
|
|
30891
|
+
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
|
|
30892
|
+
<path d="M4.5 6.5h15v3h-15z" />
|
|
30893
|
+
<path d="M6 9.5v8h12v-8" />
|
|
30894
|
+
<path d="M12 16v-4" />
|
|
30895
|
+
<path d="m9.5 14.5 2.5-2.5 2.5 2.5" />
|
|
30896
|
+
</svg>
|
|
30897
|
+
`;
|
|
30898
|
+
}
|
|
30899
|
+
if (name === "copy") {
|
|
30900
|
+
return `
|
|
30901
|
+
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
|
|
30902
|
+
<path d="M8 7.5V5.8c0-1 .8-1.8 1.8-1.8h6.4c1 0 1.8.8 1.8 1.8v8.4c0 1-.8 1.8-1.8 1.8h-1.7" />
|
|
30903
|
+
<path d="M5.8 8h6.4c1 0 1.8.8 1.8 1.8v8.4c0 1-.8 1.8-1.8 1.8H5.8c-1 0-1.8-.8-1.8-1.8V9.8C4 8.8 4.8 8 5.8 8Z" />
|
|
30904
|
+
</svg>
|
|
30905
|
+
`;
|
|
30906
|
+
}
|
|
30907
|
+
if (name === "trash") {
|
|
30908
|
+
return `
|
|
30909
|
+
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
|
|
30910
|
+
<path d="M5 7h14" />
|
|
30911
|
+
<path d="M9 7V5.8c0-1 .8-1.8 1.8-1.8h2.4c1 0 1.8.8 1.8 1.8V7" />
|
|
30912
|
+
<path d="m7 7 1 12c.1 1 1 1.8 2 1.8h4c1 0 1.9-.8 2-1.8l1-12" />
|
|
30913
|
+
<path d="M10.5 11v6M13.5 11v6" />
|
|
30914
|
+
</svg>
|
|
30915
|
+
`;
|
|
30916
|
+
}
|
|
30917
|
+
return "";
|
|
30918
|
+
}
|
|
30919
|
+
|
|
30920
|
+
function getMailRowActionMenuItems(item) {
|
|
30921
|
+
if (!item?.id) return [];
|
|
30922
|
+
const unread = !item.read_at;
|
|
30923
|
+
const archived = Boolean(item.archived_at);
|
|
30924
|
+
const busy = mailState.actionBusyId === item.id;
|
|
30925
|
+
return [
|
|
30926
|
+
{
|
|
30927
|
+
action: unread ? "read" : "unread",
|
|
30928
|
+
label: unread ? "Mark read" : "Mark unread",
|
|
30929
|
+
icon: unread ? "read" : "unread",
|
|
30930
|
+
disabled: busy,
|
|
30931
|
+
},
|
|
30932
|
+
{
|
|
30933
|
+
action: archived ? "unarchive" : "archive",
|
|
30934
|
+
label: archived ? "Unarchive" : "Archive",
|
|
30935
|
+
icon: archived ? "unarchive" : "archive",
|
|
30936
|
+
disabled: busy,
|
|
30937
|
+
},
|
|
30938
|
+
{
|
|
30939
|
+
action: "copy",
|
|
30940
|
+
label: "Copy mail link",
|
|
30941
|
+
icon: "copy",
|
|
30942
|
+
},
|
|
30943
|
+
{
|
|
30944
|
+
action: "delete",
|
|
30945
|
+
label: "Delete",
|
|
30946
|
+
icon: "trash",
|
|
30947
|
+
danger: true,
|
|
30948
|
+
disabled: busy,
|
|
30949
|
+
},
|
|
30950
|
+
];
|
|
30951
|
+
}
|
|
30952
|
+
|
|
30953
|
+
function renderMailRowMenuActionButton({
|
|
30954
|
+
action,
|
|
30955
|
+
label,
|
|
30956
|
+
icon,
|
|
30957
|
+
danger = false,
|
|
30958
|
+
disabled = false,
|
|
30959
|
+
}) {
|
|
30960
|
+
return `
|
|
30961
|
+
<button
|
|
30962
|
+
class="mail-row-menu-action${danger ? " danger" : ""}"
|
|
30963
|
+
type="button"
|
|
30964
|
+
data-mail-menu-item-action="${esc(action)}"
|
|
30965
|
+
role="menuitem"
|
|
30966
|
+
aria-disabled="${String(disabled)}"
|
|
30967
|
+
${disabled ? "disabled" : ""}
|
|
30968
|
+
>
|
|
30969
|
+
<span class="mail-row-menu-action-icon">
|
|
30970
|
+
${renderMailActionIcon(icon)}
|
|
30971
|
+
</span>
|
|
30972
|
+
<span>${esc(label)}</span>
|
|
30973
|
+
</button>
|
|
30974
|
+
`;
|
|
30975
|
+
}
|
|
30976
|
+
|
|
30591
30977
|
function renderMailRow(item) {
|
|
30592
30978
|
const mailId = item.id;
|
|
30593
30979
|
const unread = !item.read_at;
|
|
@@ -30629,55 +31015,148 @@ Waiting for Claude login output…</pre
|
|
|
30629
31015
|
</span>
|
|
30630
31016
|
</span>
|
|
30631
31017
|
</button>
|
|
30632
|
-
<div class="
|
|
31018
|
+
<div class="mail-row-actions" data-oysterun-mail-row-actions="true">
|
|
30633
31019
|
<button
|
|
30634
|
-
class="
|
|
31020
|
+
class="mail-row-menu-button"
|
|
30635
31021
|
type="button"
|
|
30636
|
-
title="
|
|
30637
|
-
aria-label="
|
|
30638
|
-
data-mail-action="
|
|
31022
|
+
title="Mail actions"
|
|
31023
|
+
aria-label="Mail actions for ${esc(item.title)}"
|
|
31024
|
+
data-mail-menu-action="open"
|
|
30639
31025
|
data-mail-id="${esc(mailId)}"
|
|
30640
31026
|
${getMailActionBusyAttr(mailId)}
|
|
30641
31027
|
>
|
|
30642
|
-
|
|
30643
|
-
</button>
|
|
30644
|
-
<button
|
|
30645
|
-
class="web-site-row-action"
|
|
30646
|
-
type="button"
|
|
30647
|
-
title="${archived ? "Unarchive" : "Archive"}"
|
|
30648
|
-
aria-label="${archived ? "Unarchive" : "Archive"}"
|
|
30649
|
-
data-mail-action="${archived ? "unarchive" : "archive"}"
|
|
30650
|
-
data-mail-id="${esc(mailId)}"
|
|
30651
|
-
${getMailActionBusyAttr(mailId)}
|
|
30652
|
-
>
|
|
30653
|
-
${archived ? "Inbox" : "Archive"}
|
|
30654
|
-
</button>
|
|
30655
|
-
<button
|
|
30656
|
-
class="web-site-row-action"
|
|
30657
|
-
type="button"
|
|
30658
|
-
title="Copy mail link"
|
|
30659
|
-
aria-label="Copy mail link"
|
|
30660
|
-
data-mail-action="copy"
|
|
30661
|
-
data-mail-id="${esc(mailId)}"
|
|
30662
|
-
>
|
|
30663
|
-
Copy
|
|
30664
|
-
</button>
|
|
30665
|
-
<button
|
|
30666
|
-
class="web-site-row-action"
|
|
30667
|
-
type="button"
|
|
30668
|
-
title="Delete"
|
|
30669
|
-
aria-label="Delete"
|
|
30670
|
-
data-mail-action="delete"
|
|
30671
|
-
data-mail-id="${esc(mailId)}"
|
|
30672
|
-
${getMailActionBusyAttr(mailId)}
|
|
30673
|
-
>
|
|
30674
|
-
Delete
|
|
31028
|
+
<span aria-hidden="true"></span>
|
|
30675
31029
|
</button>
|
|
30676
31030
|
</div>
|
|
30677
31031
|
</article>
|
|
30678
31032
|
`;
|
|
30679
31033
|
}
|
|
30680
31034
|
|
|
31035
|
+
function getMailRowItem(mailId) {
|
|
31036
|
+
const normalizedId = sanitizeRouteText(mailId);
|
|
31037
|
+
if (!normalizedId) return null;
|
|
31038
|
+
return (
|
|
31039
|
+
mailState.itemById.get(normalizedId) ||
|
|
31040
|
+
mailState.items.find((item) => item.id === normalizedId) ||
|
|
31041
|
+
(mailState.selectedItem?.id === normalizedId
|
|
31042
|
+
? mailState.selectedItem
|
|
31043
|
+
: null)
|
|
31044
|
+
);
|
|
31045
|
+
}
|
|
31046
|
+
|
|
31047
|
+
function closeMailRowActionMenu() {
|
|
31048
|
+
const layer = $("mail-row-menu-layer");
|
|
31049
|
+
if (layer) {
|
|
31050
|
+
layer.classList.add("hidden");
|
|
31051
|
+
layer.innerHTML = "";
|
|
31052
|
+
}
|
|
31053
|
+
mailRowActionMenuState = null;
|
|
31054
|
+
document.removeEventListener(
|
|
31055
|
+
"click",
|
|
31056
|
+
handleMailRowActionMenuDocumentClick,
|
|
31057
|
+
true
|
|
31058
|
+
);
|
|
31059
|
+
document.removeEventListener("keydown", handleMailRowActionMenuKeydown);
|
|
31060
|
+
}
|
|
31061
|
+
|
|
31062
|
+
function handleMailRowActionMenuDocumentClick(event) {
|
|
31063
|
+
const target = event.target;
|
|
31064
|
+
if (!(target instanceof Element)) {
|
|
31065
|
+
closeMailRowActionMenu();
|
|
31066
|
+
event.preventDefault();
|
|
31067
|
+
event.stopPropagation();
|
|
31068
|
+
return;
|
|
31069
|
+
}
|
|
31070
|
+
if (
|
|
31071
|
+
target.closest(".mail-row-menu-panel") ||
|
|
31072
|
+
target.closest("[data-mail-menu-action='open']")
|
|
31073
|
+
) {
|
|
31074
|
+
return;
|
|
31075
|
+
}
|
|
31076
|
+
event.preventDefault();
|
|
31077
|
+
event.stopPropagation();
|
|
31078
|
+
closeMailRowActionMenu();
|
|
31079
|
+
}
|
|
31080
|
+
|
|
31081
|
+
function handleMailRowActionMenuKeydown(event) {
|
|
31082
|
+
if (event.key === "Escape") {
|
|
31083
|
+
closeMailRowActionMenu();
|
|
31084
|
+
}
|
|
31085
|
+
}
|
|
31086
|
+
|
|
31087
|
+
function positionMailRowActionMenu(anchorButton) {
|
|
31088
|
+
const layer = $("mail-row-menu-layer");
|
|
31089
|
+
const panel = layer?.querySelector(".mail-row-menu-panel");
|
|
31090
|
+
if (!layer || !panel || !anchorButton) return;
|
|
31091
|
+
const rect = anchorButton.getBoundingClientRect();
|
|
31092
|
+
const panelWidth = panel.offsetWidth || 190;
|
|
31093
|
+
const panelHeight = panel.offsetHeight || 160;
|
|
31094
|
+
const edgeInset = 12;
|
|
31095
|
+
let left = rect.right - panelWidth;
|
|
31096
|
+
left = Math.max(
|
|
31097
|
+
edgeInset,
|
|
31098
|
+
Math.min(left, window.innerWidth - panelWidth - edgeInset)
|
|
31099
|
+
);
|
|
31100
|
+
let top = rect.bottom + 6;
|
|
31101
|
+
if (top + panelHeight > window.innerHeight - edgeInset) {
|
|
31102
|
+
top = rect.top - panelHeight - 6;
|
|
31103
|
+
}
|
|
31104
|
+
top = Math.max(
|
|
31105
|
+
edgeInset,
|
|
31106
|
+
Math.min(top, window.innerHeight - panelHeight - edgeInset)
|
|
31107
|
+
);
|
|
31108
|
+
panel.style.left = `${Math.round(left)}px`;
|
|
31109
|
+
panel.style.top = `${Math.round(top)}px`;
|
|
31110
|
+
}
|
|
31111
|
+
|
|
31112
|
+
function openMailRowActionMenu(anchorButton, mailId) {
|
|
31113
|
+
const normalizedId = sanitizeRouteText(mailId);
|
|
31114
|
+
if (!normalizedId) return;
|
|
31115
|
+
const item = getMailRowItem(normalizedId);
|
|
31116
|
+
if (!item) return;
|
|
31117
|
+
const layer = $("mail-row-menu-layer");
|
|
31118
|
+
if (!layer) return;
|
|
31119
|
+
const alreadyOpen =
|
|
31120
|
+
mailRowActionMenuState?.mailId === normalizedId &&
|
|
31121
|
+
!layer.classList.contains("hidden");
|
|
31122
|
+
closeMailRowActionMenu();
|
|
31123
|
+
if (alreadyOpen) return;
|
|
31124
|
+
mailRowActionMenuState = { mailId: normalizedId };
|
|
31125
|
+
const menuItems = getMailRowActionMenuItems(item);
|
|
31126
|
+
layer.innerHTML = `
|
|
31127
|
+
<div
|
|
31128
|
+
class="mail-row-menu-panel"
|
|
31129
|
+
role="menu"
|
|
31130
|
+
data-oysterun-mail-row-menu="${esc(normalizedId)}"
|
|
31131
|
+
>
|
|
31132
|
+
${menuItems.map(renderMailRowMenuActionButton).join("")}
|
|
31133
|
+
</div>
|
|
31134
|
+
`;
|
|
31135
|
+
layer.classList.remove("hidden");
|
|
31136
|
+
positionMailRowActionMenu(anchorButton);
|
|
31137
|
+
for (const actionButton of layer.querySelectorAll(
|
|
31138
|
+
"[data-mail-menu-item-action]"
|
|
31139
|
+
)) {
|
|
31140
|
+
actionButton.addEventListener("click", (event) => {
|
|
31141
|
+
event.preventDefault();
|
|
31142
|
+
event.stopPropagation();
|
|
31143
|
+
const action = actionButton.getAttribute(
|
|
31144
|
+
"data-mail-menu-item-action"
|
|
31145
|
+
);
|
|
31146
|
+
closeMailRowActionMenu();
|
|
31147
|
+
void performMailAction(normalizedId, action || "");
|
|
31148
|
+
});
|
|
31149
|
+
}
|
|
31150
|
+
window.setTimeout(() => {
|
|
31151
|
+
document.addEventListener(
|
|
31152
|
+
"click",
|
|
31153
|
+
handleMailRowActionMenuDocumentClick,
|
|
31154
|
+
true
|
|
31155
|
+
);
|
|
31156
|
+
document.addEventListener("keydown", handleMailRowActionMenuKeydown);
|
|
31157
|
+
}, 0);
|
|
31158
|
+
}
|
|
31159
|
+
|
|
30681
31160
|
function normalizeTrustedMailHref(rawHref) {
|
|
30682
31161
|
const href = String(rawHref || "").trim();
|
|
30683
31162
|
if (!href || href.startsWith("#")) return href;
|
|
@@ -30890,15 +31369,57 @@ Waiting for Claude login output…</pre
|
|
|
30890
31369
|
return doc.body.innerHTML;
|
|
30891
31370
|
}
|
|
30892
31371
|
|
|
31372
|
+
function buildMailHtmlSrcdoc(value) {
|
|
31373
|
+
const html = String(value || "");
|
|
31374
|
+
if (/<(?:!doctype|html|head|body)\b/i.test(html)) return html;
|
|
31375
|
+
return `<!doctype html>
|
|
31376
|
+
<html>
|
|
31377
|
+
<head>
|
|
31378
|
+
<meta charset="utf-8" />
|
|
31379
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
31380
|
+
<style>
|
|
31381
|
+
html,
|
|
31382
|
+
body {
|
|
31383
|
+
margin: 0;
|
|
31384
|
+
padding: 0;
|
|
31385
|
+
min-width: 0;
|
|
31386
|
+
overflow-wrap: anywhere;
|
|
31387
|
+
word-break: normal;
|
|
31388
|
+
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Inter", sans-serif;
|
|
31389
|
+
color: #271c12;
|
|
31390
|
+
background: transparent;
|
|
31391
|
+
}
|
|
31392
|
+
img,
|
|
31393
|
+
video,
|
|
31394
|
+
canvas,
|
|
31395
|
+
svg {
|
|
31396
|
+
max-width: 100%;
|
|
31397
|
+
height: auto;
|
|
31398
|
+
}
|
|
31399
|
+
table {
|
|
31400
|
+
max-width: 100%;
|
|
31401
|
+
}
|
|
31402
|
+
</style>
|
|
31403
|
+
</head>
|
|
31404
|
+
<body>${html}</body>
|
|
31405
|
+
</html>`;
|
|
31406
|
+
}
|
|
31407
|
+
|
|
30893
31408
|
function renderMailBody(item) {
|
|
30894
31409
|
if (item.body_format === "html") {
|
|
30895
31410
|
return `
|
|
30896
31411
|
<div
|
|
30897
|
-
class="
|
|
30898
|
-
data-oysterun-mail-body-format="
|
|
30899
|
-
data-oysterun-mail-html-
|
|
31412
|
+
class="mail-html-frame-shell"
|
|
31413
|
+
data-oysterun-mail-body-format="html"
|
|
31414
|
+
data-oysterun-mail-html-sandboxed="true"
|
|
30900
31415
|
>
|
|
30901
|
-
|
|
31416
|
+
<iframe
|
|
31417
|
+
class="mail-html-frame"
|
|
31418
|
+
title="Mail HTML body"
|
|
31419
|
+
sandbox="allow-same-origin allow-popups allow-popups-to-escape-sandbox"
|
|
31420
|
+
data-oysterun-mail-html-frame="true"
|
|
31421
|
+
srcdoc="${esc(buildMailHtmlSrcdoc(item.body_html))}"
|
|
31422
|
+
></iframe>
|
|
30902
31423
|
</div>
|
|
30903
31424
|
`;
|
|
30904
31425
|
}
|
|
@@ -30936,51 +31457,28 @@ Waiting for Claude login output…</pre
|
|
|
30936
31457
|
const unread = !item.read_at;
|
|
30937
31458
|
const createdLabel = formatMailTimestamp(item.created_at);
|
|
30938
31459
|
const tags = item.tags.length ? item.tags.join(", ") : "";
|
|
31460
|
+
const metaParts = [
|
|
31461
|
+
getMailSourceLabel(item),
|
|
31462
|
+
createdLabel,
|
|
31463
|
+
item.severity,
|
|
31464
|
+
unread ? "Unread" : "Read",
|
|
31465
|
+
archived ? "Archived" : "",
|
|
31466
|
+
tags,
|
|
31467
|
+
].filter(Boolean);
|
|
30939
31468
|
return `
|
|
30940
31469
|
<article
|
|
30941
31470
|
class="mail-detail"
|
|
30942
31471
|
data-oysterun-mail-detail-id="${esc(item.id)}"
|
|
30943
31472
|
data-oysterun-mail-detail-read="${unread ? "false" : "true"}"
|
|
30944
31473
|
data-oysterun-mail-detail-archived="${archived ? "true" : "false"}"
|
|
31474
|
+
data-oysterun-mail-detail-layout="title_meta_body"
|
|
30945
31475
|
>
|
|
30946
|
-
<
|
|
30947
|
-
<
|
|
30948
|
-
|
|
30949
|
-
|
|
30950
|
-
<div class="meta-text">
|
|
30951
|
-
${esc(getMailSourceLabel(item))}
|
|
30952
|
-
${createdLabel ? ` · ${esc(createdLabel)}` : ""}
|
|
30953
|
-
${tags ? ` · ${esc(tags)}` : ""}
|
|
30954
|
-
</div>
|
|
31476
|
+
<header class="mail-detail-header">
|
|
31477
|
+
<h1 class="mail-detail-title">${esc(item.title)}</h1>
|
|
31478
|
+
<div class="mail-detail-meta">
|
|
31479
|
+
${metaParts.map((part) => `<span>${esc(part)}</span>`).join("")}
|
|
30955
31480
|
</div>
|
|
30956
|
-
|
|
30957
|
-
<span class="pill">${unread ? "Unread" : "Read"}</span>
|
|
30958
|
-
${archived ? '<span class="pill">Archived</span>' : ""}
|
|
30959
|
-
</div>
|
|
30960
|
-
</div>
|
|
30961
|
-
<div class="toolbar" data-oysterun-mail-detail-actions="true">
|
|
30962
|
-
<button class="btn-soft" type="button" data-mail-action="${
|
|
30963
|
-
unread ? "read" : "unread"
|
|
30964
|
-
}" data-mail-id="${esc(item.id)}">${
|
|
30965
|
-
unread ? "Mark read" : "Mark unread"
|
|
30966
|
-
}</button>
|
|
30967
|
-
<button class="btn-soft" type="button" data-mail-action="${
|
|
30968
|
-
archived ? "unarchive" : "archive"
|
|
30969
|
-
}" data-mail-id="${esc(item.id)}">${
|
|
30970
|
-
archived ? "Unarchive" : "Archive"
|
|
30971
|
-
}</button>
|
|
30972
|
-
<button class="btn-soft" type="button" data-mail-action="copy" data-mail-id="${esc(
|
|
30973
|
-
item.id
|
|
30974
|
-
)}">Copy mail link</button>
|
|
30975
|
-
<button class="btn-ghost" type="button" data-mail-action="delete" data-mail-id="${esc(
|
|
30976
|
-
item.id
|
|
30977
|
-
)}">Delete</button>
|
|
30978
|
-
</div>
|
|
30979
|
-
${
|
|
30980
|
-
item.summary
|
|
30981
|
-
? `<p class="field-hint">${esc(item.summary)}</p>`
|
|
30982
|
-
: ""
|
|
30983
|
-
}
|
|
31481
|
+
</header>
|
|
30984
31482
|
<div
|
|
30985
31483
|
class="mail-detail-body"
|
|
30986
31484
|
data-oysterun-mail-detail-renderer="${esc(item.body_format)}"
|
|
@@ -31023,6 +31521,7 @@ Waiting for Claude login output…</pre
|
|
|
31023
31521
|
null;
|
|
31024
31522
|
detailRoot.innerHTML = renderMailDetail(item);
|
|
31025
31523
|
hydrateRichContent(detailRoot);
|
|
31524
|
+
hydrateMailHtmlFrames(detailRoot);
|
|
31026
31525
|
}
|
|
31027
31526
|
return;
|
|
31028
31527
|
}
|
|
@@ -31292,11 +31791,25 @@ Waiting for Claude login output…</pre
|
|
|
31292
31791
|
|
|
31293
31792
|
function handleMailClick(event) {
|
|
31294
31793
|
const target = event.target instanceof Element ? event.target : null;
|
|
31295
|
-
if (!target
|
|
31794
|
+
if (!target) return false;
|
|
31795
|
+
const topbarMenuButton = target.closest(
|
|
31796
|
+
"#topbar-mail-actions-btn[data-mail-menu-action='open']"
|
|
31797
|
+
);
|
|
31798
|
+
if (topbarMenuButton) {
|
|
31799
|
+
event.preventDefault();
|
|
31800
|
+
event.stopPropagation();
|
|
31801
|
+
openMailRowActionMenu(
|
|
31802
|
+
topbarMenuButton,
|
|
31803
|
+
topbarMenuButton.getAttribute("data-mail-id") || ""
|
|
31804
|
+
);
|
|
31805
|
+
return true;
|
|
31806
|
+
}
|
|
31807
|
+
if (!$("mail-view")?.contains(target)) return false;
|
|
31296
31808
|
const filterButton = target.closest("[data-mail-filter]");
|
|
31297
31809
|
if (filterButton) {
|
|
31298
31810
|
event.preventDefault();
|
|
31299
31811
|
event.stopPropagation();
|
|
31812
|
+
closeMailRowActionMenu();
|
|
31300
31813
|
void navigateToRoute(
|
|
31301
31814
|
buildMailRoute({
|
|
31302
31815
|
filter: filterButton.getAttribute("data-mail-filter") || "inbox",
|
|
@@ -31304,10 +31817,21 @@ Waiting for Claude login output…</pre
|
|
|
31304
31817
|
);
|
|
31305
31818
|
return true;
|
|
31306
31819
|
}
|
|
31820
|
+
const menuButton = target.closest("[data-mail-menu-action='open']");
|
|
31821
|
+
if (menuButton) {
|
|
31822
|
+
event.preventDefault();
|
|
31823
|
+
event.stopPropagation();
|
|
31824
|
+
openMailRowActionMenu(
|
|
31825
|
+
menuButton,
|
|
31826
|
+
menuButton.getAttribute("data-mail-id") || ""
|
|
31827
|
+
);
|
|
31828
|
+
return true;
|
|
31829
|
+
}
|
|
31307
31830
|
const actionButton = target.closest("[data-mail-action][data-mail-id]");
|
|
31308
31831
|
if (!actionButton) return false;
|
|
31309
31832
|
event.preventDefault();
|
|
31310
31833
|
event.stopPropagation();
|
|
31834
|
+
closeMailRowActionMenu();
|
|
31311
31835
|
void performMailAction(
|
|
31312
31836
|
actionButton.getAttribute("data-mail-id") || "",
|
|
31313
31837
|
actionButton.getAttribute("data-mail-action") || ""
|
|
@@ -36412,6 +36936,7 @@ Waiting for Claude login output…</pre
|
|
|
36412
36936
|
|
|
36413
36937
|
function renderSessionLoopRow(row) {
|
|
36414
36938
|
const enabled = row.enabled === true;
|
|
36939
|
+
const pending = sessionLoopState.pendingTargets?.[row.id] === true;
|
|
36415
36940
|
const expanded = sessionLoopState.editingId === row.id;
|
|
36416
36941
|
const intervalLabel = row.interval_token
|
|
36417
36942
|
? formatSessionLoopIntervalToken(row.interval_token)
|
|
@@ -36422,6 +36947,7 @@ Waiting for Claude login output…</pre
|
|
|
36422
36947
|
data-loop-row-id="${esc(row.id)}"
|
|
36423
36948
|
data-oysterun-session-loop-row="true"
|
|
36424
36949
|
data-oysterun-session-loop-enabled="${String(enabled)}"
|
|
36950
|
+
data-oysterun-session-loop-pending="${String(pending)}"
|
|
36425
36951
|
data-oysterun-session-loop-storage-owner="${esc(
|
|
36426
36952
|
row.storage_owner || "agent_folder_oysterun_loops_json"
|
|
36427
36953
|
)}"
|
|
@@ -36465,10 +36991,18 @@ Waiting for Claude login output…</pre
|
|
|
36465
36991
|
type="button"
|
|
36466
36992
|
role="switch"
|
|
36467
36993
|
aria-checked="${enabled ? "true" : "false"}"
|
|
36468
|
-
|
|
36994
|
+
aria-disabled="${pending ? "true" : "false"}"
|
|
36995
|
+
title="${
|
|
36996
|
+
pending ? "Updating..." : enabled ? "Enabled" : "Disabled"
|
|
36997
|
+
}"
|
|
36998
|
+
${pending ? "disabled" : ""}
|
|
36469
36999
|
data-loop-action="toggle-row"
|
|
36470
37000
|
data-loop-id="${esc(row.id)}"
|
|
36471
37001
|
data-oysterun-session-loop-row-toggle="${esc(row.id)}"
|
|
37002
|
+
data-oysterun-session-loop-row-toggle-pending="${String(pending)}"
|
|
37003
|
+
data-oysterun-session-loop-row-toggle-desired="${
|
|
37004
|
+
enabled ? "false" : "true"
|
|
37005
|
+
}"
|
|
36472
37006
|
>
|
|
36473
37007
|
<span aria-hidden="true"></span>
|
|
36474
37008
|
</button>
|
|
@@ -36635,12 +37169,23 @@ Waiting for Claude login output…</pre
|
|
|
36635
37169
|
const liveSession = getSelectedLiveSession();
|
|
36636
37170
|
const row = findSessionLoopRow(scheduleId);
|
|
36637
37171
|
if (!liveSession || !row) return;
|
|
37172
|
+
if (sessionLoopState.pendingTargets?.[scheduleId] === true) return;
|
|
37173
|
+
sessionLoopState = {
|
|
37174
|
+
...sessionLoopState,
|
|
37175
|
+
pendingTargets: {
|
|
37176
|
+
...(sessionLoopState.pendingTargets || {}),
|
|
37177
|
+
[scheduleId]: true,
|
|
37178
|
+
},
|
|
37179
|
+
error: "",
|
|
37180
|
+
};
|
|
37181
|
+
renderSessionLoopSection(liveSession);
|
|
36638
37182
|
try {
|
|
36639
37183
|
await api(
|
|
36640
37184
|
"PATCH",
|
|
36641
37185
|
`/session/loops/${encodeURIComponent(scheduleId)}`,
|
|
36642
37186
|
{
|
|
36643
37187
|
session_id: liveSession.sessionId,
|
|
37188
|
+
desired_enabled: enabled,
|
|
36644
37189
|
enabled,
|
|
36645
37190
|
runtime_only: true,
|
|
36646
37191
|
}
|
|
@@ -36654,6 +37199,16 @@ Waiting for Claude login output…</pre
|
|
|
36654
37199
|
error: err.message || String(err),
|
|
36655
37200
|
};
|
|
36656
37201
|
renderSessionLoopSection(liveSession);
|
|
37202
|
+
} finally {
|
|
37203
|
+
const nextPendingTargets = {
|
|
37204
|
+
...(sessionLoopState.pendingTargets || {}),
|
|
37205
|
+
};
|
|
37206
|
+
delete nextPendingTargets[scheduleId];
|
|
37207
|
+
sessionLoopState = {
|
|
37208
|
+
...sessionLoopState,
|
|
37209
|
+
pendingTargets: nextPendingTargets,
|
|
37210
|
+
};
|
|
37211
|
+
renderSessionLoopSection(getSelectedLiveSession());
|
|
36657
37212
|
}
|
|
36658
37213
|
}
|
|
36659
37214
|
|
|
@@ -36730,6 +37285,8 @@ Waiting for Claude login output…</pre
|
|
|
36730
37285
|
return true;
|
|
36731
37286
|
}
|
|
36732
37287
|
if (action === "toggle-row") {
|
|
37288
|
+
if (sessionLoopState.pendingTargets?.[scheduleId] === true)
|
|
37289
|
+
return true;
|
|
36733
37290
|
const row = findSessionLoopRow(scheduleId);
|
|
36734
37291
|
if (row) {
|
|
36735
37292
|
void toggleSessionLoop(scheduleId, row.enabled !== true);
|
|
@@ -45386,6 +45943,94 @@ Waiting for Claude login output…</pre
|
|
|
45386
45943
|
return false;
|
|
45387
45944
|
}
|
|
45388
45945
|
|
|
45946
|
+
function resizeMailHtmlFrame(frame) {
|
|
45947
|
+
if (!frame) return;
|
|
45948
|
+
let doc;
|
|
45949
|
+
try {
|
|
45950
|
+
doc = frame.contentDocument;
|
|
45951
|
+
} catch {
|
|
45952
|
+
return;
|
|
45953
|
+
}
|
|
45954
|
+
if (!doc) return;
|
|
45955
|
+
const bodyHeight = doc.body?.scrollHeight || 0;
|
|
45956
|
+
const documentHeight = doc.documentElement?.scrollHeight || 0;
|
|
45957
|
+
const height = Math.max(360, bodyHeight, documentHeight);
|
|
45958
|
+
frame.style.height = `${Math.ceil(height)}px`;
|
|
45959
|
+
}
|
|
45960
|
+
|
|
45961
|
+
function normalizeMailHtmlFrameLinks(frame) {
|
|
45962
|
+
let doc;
|
|
45963
|
+
try {
|
|
45964
|
+
doc = frame.contentDocument;
|
|
45965
|
+
} catch {
|
|
45966
|
+
return;
|
|
45967
|
+
}
|
|
45968
|
+
if (!doc?.body) return;
|
|
45969
|
+
doc.querySelectorAll("a[href]").forEach((anchor) => {
|
|
45970
|
+
const rawHref = anchor.getAttribute("href") || "";
|
|
45971
|
+
const unsupportedText =
|
|
45972
|
+
getUnsupportedLocalPathFailClosedText(rawHref);
|
|
45973
|
+
if (unsupportedText) {
|
|
45974
|
+
anchor.replaceWith(doc.createTextNode(unsupportedText));
|
|
45975
|
+
return;
|
|
45976
|
+
}
|
|
45977
|
+
const safeHref = normalizeTrustedMailHref(rawHref);
|
|
45978
|
+
if (!safeHref) {
|
|
45979
|
+
anchor.removeAttribute("href");
|
|
45980
|
+
anchor.setAttribute("aria-disabled", "true");
|
|
45981
|
+
return;
|
|
45982
|
+
}
|
|
45983
|
+
anchor.setAttribute("href", safeHref);
|
|
45984
|
+
applyTrustedMailAnchorPolicy(anchor);
|
|
45985
|
+
if (anchor.dataset.boundMailHtmlLink === "true") return;
|
|
45986
|
+
anchor.dataset.boundMailHtmlLink = "true";
|
|
45987
|
+
anchor.addEventListener("click", (event) => {
|
|
45988
|
+
const parsed = parseInteractiveRichHref(
|
|
45989
|
+
anchor.getAttribute("href") || anchor.href || ""
|
|
45990
|
+
);
|
|
45991
|
+
if (!parsed) return;
|
|
45992
|
+
event.preventDefault();
|
|
45993
|
+
event.stopPropagation();
|
|
45994
|
+
void handleInteractiveRichLinkClick(anchor).catch((err) => {
|
|
45995
|
+
showBanner(err.message || "Could not open link.", true);
|
|
45996
|
+
});
|
|
45997
|
+
});
|
|
45998
|
+
});
|
|
45999
|
+
}
|
|
46000
|
+
|
|
46001
|
+
function hydrateMailHtmlFrame(frame) {
|
|
46002
|
+
if (!frame || frame.dataset.boundMailHtmlFrame === "true") return;
|
|
46003
|
+
frame.dataset.boundMailHtmlFrame = "true";
|
|
46004
|
+
const applyFramePolicy = () => {
|
|
46005
|
+
normalizeMailHtmlFrameLinks(frame);
|
|
46006
|
+
resizeMailHtmlFrame(frame);
|
|
46007
|
+
let doc;
|
|
46008
|
+
try {
|
|
46009
|
+
doc = frame.contentDocument;
|
|
46010
|
+
} catch {
|
|
46011
|
+
return;
|
|
46012
|
+
}
|
|
46013
|
+
doc?.querySelectorAll("img,video").forEach((media) => {
|
|
46014
|
+
if (media.dataset.boundMailHtmlResize === "true") return;
|
|
46015
|
+
media.dataset.boundMailHtmlResize = "true";
|
|
46016
|
+
media.addEventListener("load", () => resizeMailHtmlFrame(frame));
|
|
46017
|
+
media.addEventListener("error", () => resizeMailHtmlFrame(frame));
|
|
46018
|
+
});
|
|
46019
|
+
window.setTimeout(() => resizeMailHtmlFrame(frame), 100);
|
|
46020
|
+
window.setTimeout(() => resizeMailHtmlFrame(frame), 600);
|
|
46021
|
+
window.setTimeout(() => resizeMailHtmlFrame(frame), 1600);
|
|
46022
|
+
};
|
|
46023
|
+
frame.addEventListener("load", applyFramePolicy);
|
|
46024
|
+
window.setTimeout(applyFramePolicy, 0);
|
|
46025
|
+
}
|
|
46026
|
+
|
|
46027
|
+
function hydrateMailHtmlFrames(root) {
|
|
46028
|
+
if (!root) return;
|
|
46029
|
+
root
|
|
46030
|
+
.querySelectorAll("iframe[data-oysterun-mail-html-frame='true']")
|
|
46031
|
+
.forEach((frame) => hydrateMailHtmlFrame(frame));
|
|
46032
|
+
}
|
|
46033
|
+
|
|
45389
46034
|
function hydrateRichContent(root) {
|
|
45390
46035
|
if (!root) return;
|
|
45391
46036
|
root
|