oysterun 1.4.5 → 1.4.7
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 +792 -116
- package/dev/client/web-chat/dist/assets/{ReactPrism-Pt9CJmFr.js → ReactPrism-DQpy9C6y.js} +1 -1
- package/dev/client/web-chat/dist/assets/{ReactPrism-Pt9CJmFr.js.map → ReactPrism-DQpy9C6y.js.map} +1 -1
- package/dev/client/web-chat/dist/assets/{index-BUELz8_v.js → index-5-_pCTeV.js} +2 -2
- package/dev/client/web-chat/dist/assets/{index-BUELz8_v.js.map → index-5-_pCTeV.js.map} +1 -1
- package/dev/client/web-chat/dist/assets/{index-BFyCCLfm.js → index-DKEDScEA.js} +90 -90
- package/dev/client/web-chat/dist/assets/index-DKEDScEA.js.map +1 -0
- package/dev/client/web-chat/dist/assets/{index-DjA8TMy2.js → index-DogixscE.js} +1 -1
- package/dev/client/web-chat/dist/assets/{index-DjA8TMy2.js.map → index-DogixscE.js.map} +1 -1
- package/dev/client/web-chat/dist/assets/{pdf-B5HuyJzk.js → pdf-AYwu3-03.js} +3 -3
- package/dev/client/web-chat/dist/assets/{pdf-B5HuyJzk.js.map → pdf-AYwu3-03.js.map} +1 -1
- package/dev/client/web-chat/dist/assets/{web-BuBqjNYh.js → web-BGIphkU6.js} +1 -1
- package/dev/client/web-chat/dist/assets/{web-BuBqjNYh.js.map → web-BGIphkU6.js.map} +1 -1
- package/dev/client/web-chat/dist/assets/{web-DU_hq0TE.js → web-CXqN5ZBB.js} +1 -1
- package/dev/client/web-chat/dist/assets/{web-DU_hq0TE.js.map → web-CXqN5ZBB.js.map} +1 -1
- package/dev/client/web-chat/dist/index.html +1 -1
- package/host-service/adapters/claude-code-adapter.mjs +21 -2
- package/host-service/adapters/codex-app-server-adapter.mjs +27 -3
- package/host-service/assets/product-skills/Oysterun/modules/oysterun-mail/SKILL.md +20 -1
- package/host-service/assets/product-skills/Oysterun/modules/oysterun-scheduler/SKILL.md +52 -0
- package/host-service/assets/product-skills/oysterun-mail/SKILL.md +20 -1
- package/host-service/assets/product-skills/oysterun-scheduler/SKILL.md +52 -0
- package/host-service/cli/product-cli.mjs +46 -3
- package/host-service/mail-store.mjs +13 -2
- package/host-service/package.json +1 -1
- package/host-service/scheduler-runner.mjs +2 -0
- package/host-service/scheduler-service.mjs +163 -17
- package/host-service/server.mjs +304 -72
- package/host-service/session-loop-definitions.mjs +36 -1
- package/host-service/session-manager.mjs +98 -3
- package/package.json +1 -1
- package/tool_scripts/oysterun_service_common.sh +75 -0
- package/tool_scripts/start_oysterun.sh +17 -42
- package/dev/client/web-chat/dist/assets/index-BFyCCLfm.js.map +0 -1
|
@@ -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
|
};
|
|
@@ -12526,6 +12765,7 @@ Waiting for Claude login output…</pre
|
|
|
12526
12765
|
const SESSION_UPLOADS_DISABLED_MESSAGE =
|
|
12527
12766
|
"File uploads are unavailable in this chat.";
|
|
12528
12767
|
let pendingAttachments = [];
|
|
12768
|
+
let routeCInterruptRequestInFlight = false;
|
|
12529
12769
|
const uploadPreviewObjectUrlCache = new Map();
|
|
12530
12770
|
const uploadPreviewObjectUrlRequests = new Map();
|
|
12531
12771
|
let currentStreamAgentId = null;
|
|
@@ -12545,6 +12785,7 @@ Waiting for Claude login output…</pre
|
|
|
12545
12785
|
let sessionLoopState = createSessionLoopState();
|
|
12546
12786
|
let hostSchedulerState = createHostSchedulerState();
|
|
12547
12787
|
let mailState = createMailState();
|
|
12788
|
+
let mailRowActionMenuState = null;
|
|
12548
12789
|
let schedulerSetupCopyState = createSchedulerSetupCopyState();
|
|
12549
12790
|
let hostSchedulerActionMenuState = null;
|
|
12550
12791
|
let sessionLoopActionMenuState = null;
|
|
@@ -27748,8 +27989,8 @@ Waiting for Claude login output…</pre
|
|
|
27748
27989
|
if (screen === "mail") {
|
|
27749
27990
|
if (normalized.mailId) {
|
|
27750
27991
|
return {
|
|
27751
|
-
title: "
|
|
27752
|
-
subtitle: "
|
|
27992
|
+
title: "Email",
|
|
27993
|
+
subtitle: "",
|
|
27753
27994
|
};
|
|
27754
27995
|
}
|
|
27755
27996
|
return {
|
|
@@ -27838,6 +28079,7 @@ Waiting for Claude login output…</pre
|
|
|
27838
28079
|
const isAgentProfile = screen === "agent-profile";
|
|
27839
28080
|
const isBrowser = screen === "browser";
|
|
27840
28081
|
const currentRoute = normalizeClientRoute(getCurrentRoute());
|
|
28082
|
+
const isMailDetail = screen === "mail" && Boolean(currentRoute.mailId);
|
|
27841
28083
|
const isExplorer = screen === "explorer";
|
|
27842
28084
|
const isSessionSetupFolderPicker =
|
|
27843
28085
|
screen === "folder-picker" &&
|
|
@@ -27872,6 +28114,30 @@ Waiting for Claude login output…</pre
|
|
|
27872
28114
|
setVisible("topbar-scheduler-new-btn", isSchedulerList);
|
|
27873
28115
|
setVisible("topbar-session-loop-new-btn", isSessionLoop);
|
|
27874
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
|
+
}
|
|
27875
28141
|
const topbarExplorerAddFolderButton = $(
|
|
27876
28142
|
"topbar-explorer-add-folder-btn"
|
|
27877
28143
|
);
|
|
@@ -28059,6 +28325,7 @@ Waiting for Claude login output…</pre
|
|
|
28059
28325
|
$("topbar")?.classList.toggle("scheduler-mode", isSchedulerList);
|
|
28060
28326
|
$("topbar")?.classList.toggle("explorer-mode", isExplorer);
|
|
28061
28327
|
$("topbar")?.classList.toggle("session-loop-mode", isSessionLoop);
|
|
28328
|
+
$("topbar")?.classList.toggle("mail-detail-mode", isMailDetail);
|
|
28062
28329
|
$("topbar")?.classList.toggle("browser-mode", isBrowser);
|
|
28063
28330
|
$("topbar")?.classList.toggle(
|
|
28064
28331
|
"scheduler-setup-mode",
|
|
@@ -30520,6 +30787,10 @@ Waiting for Claude login output…</pre
|
|
|
30520
30787
|
badge.textContent = count > 99 ? "99+" : String(count);
|
|
30521
30788
|
badge.classList.toggle("hidden", count <= 0);
|
|
30522
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
|
+
);
|
|
30523
30794
|
}
|
|
30524
30795
|
|
|
30525
30796
|
function renderMailFilterBar() {
|
|
@@ -30587,6 +30858,122 @@ Waiting for Claude login output…</pre
|
|
|
30587
30858
|
`;
|
|
30588
30859
|
}
|
|
30589
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
|
+
|
|
30590
30977
|
function renderMailRow(item) {
|
|
30591
30978
|
const mailId = item.id;
|
|
30592
30979
|
const unread = !item.read_at;
|
|
@@ -30628,55 +31015,148 @@ Waiting for Claude login output…</pre
|
|
|
30628
31015
|
</span>
|
|
30629
31016
|
</span>
|
|
30630
31017
|
</button>
|
|
30631
|
-
<div class="
|
|
30632
|
-
<button
|
|
30633
|
-
class="web-site-row-action"
|
|
30634
|
-
type="button"
|
|
30635
|
-
title="${unread ? "Mark read" : "Mark unread"}"
|
|
30636
|
-
aria-label="${unread ? "Mark read" : "Mark unread"}"
|
|
30637
|
-
data-mail-action="${unread ? "read" : "unread"}"
|
|
30638
|
-
data-mail-id="${esc(mailId)}"
|
|
30639
|
-
${getMailActionBusyAttr(mailId)}
|
|
30640
|
-
>
|
|
30641
|
-
${unread ? "Read" : "Unread"}
|
|
30642
|
-
</button>
|
|
30643
|
-
<button
|
|
30644
|
-
class="web-site-row-action"
|
|
30645
|
-
type="button"
|
|
30646
|
-
title="${archived ? "Unarchive" : "Archive"}"
|
|
30647
|
-
aria-label="${archived ? "Unarchive" : "Archive"}"
|
|
30648
|
-
data-mail-action="${archived ? "unarchive" : "archive"}"
|
|
30649
|
-
data-mail-id="${esc(mailId)}"
|
|
30650
|
-
${getMailActionBusyAttr(mailId)}
|
|
30651
|
-
>
|
|
30652
|
-
${archived ? "Inbox" : "Archive"}
|
|
30653
|
-
</button>
|
|
30654
|
-
<button
|
|
30655
|
-
class="web-site-row-action"
|
|
30656
|
-
type="button"
|
|
30657
|
-
title="Copy mail link"
|
|
30658
|
-
aria-label="Copy mail link"
|
|
30659
|
-
data-mail-action="copy"
|
|
30660
|
-
data-mail-id="${esc(mailId)}"
|
|
30661
|
-
>
|
|
30662
|
-
Copy
|
|
30663
|
-
</button>
|
|
31018
|
+
<div class="mail-row-actions" data-oysterun-mail-row-actions="true">
|
|
30664
31019
|
<button
|
|
30665
|
-
class="
|
|
31020
|
+
class="mail-row-menu-button"
|
|
30666
31021
|
type="button"
|
|
30667
|
-
title="
|
|
30668
|
-
aria-label="
|
|
30669
|
-
data-mail-action="
|
|
31022
|
+
title="Mail actions"
|
|
31023
|
+
aria-label="Mail actions for ${esc(item.title)}"
|
|
31024
|
+
data-mail-menu-action="open"
|
|
30670
31025
|
data-mail-id="${esc(mailId)}"
|
|
30671
31026
|
${getMailActionBusyAttr(mailId)}
|
|
30672
31027
|
>
|
|
30673
|
-
|
|
31028
|
+
<span aria-hidden="true"></span>
|
|
30674
31029
|
</button>
|
|
30675
31030
|
</div>
|
|
30676
31031
|
</article>
|
|
30677
31032
|
`;
|
|
30678
31033
|
}
|
|
30679
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
|
+
|
|
30680
31160
|
function normalizeTrustedMailHref(rawHref) {
|
|
30681
31161
|
const href = String(rawHref || "").trim();
|
|
30682
31162
|
if (!href || href.startsWith("#")) return href;
|
|
@@ -30889,15 +31369,57 @@ Waiting for Claude login output…</pre
|
|
|
30889
31369
|
return doc.body.innerHTML;
|
|
30890
31370
|
}
|
|
30891
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
|
+
|
|
30892
31408
|
function renderMailBody(item) {
|
|
30893
31409
|
if (item.body_format === "html") {
|
|
30894
31410
|
return `
|
|
30895
31411
|
<div
|
|
30896
|
-
class="
|
|
30897
|
-
data-oysterun-mail-body-format="
|
|
30898
|
-
data-oysterun-mail-html-
|
|
31412
|
+
class="mail-html-frame-shell"
|
|
31413
|
+
data-oysterun-mail-body-format="html"
|
|
31414
|
+
data-oysterun-mail-html-sandboxed="true"
|
|
30899
31415
|
>
|
|
30900
|
-
|
|
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>
|
|
30901
31423
|
</div>
|
|
30902
31424
|
`;
|
|
30903
31425
|
}
|
|
@@ -30935,51 +31457,28 @@ Waiting for Claude login output…</pre
|
|
|
30935
31457
|
const unread = !item.read_at;
|
|
30936
31458
|
const createdLabel = formatMailTimestamp(item.created_at);
|
|
30937
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);
|
|
30938
31468
|
return `
|
|
30939
31469
|
<article
|
|
30940
31470
|
class="mail-detail"
|
|
30941
31471
|
data-oysterun-mail-detail-id="${esc(item.id)}"
|
|
30942
31472
|
data-oysterun-mail-detail-read="${unread ? "false" : "true"}"
|
|
30943
31473
|
data-oysterun-mail-detail-archived="${archived ? "true" : "false"}"
|
|
31474
|
+
data-oysterun-mail-detail-layout="title_meta_body"
|
|
30944
31475
|
>
|
|
30945
|
-
<
|
|
30946
|
-
<
|
|
30947
|
-
|
|
30948
|
-
|
|
30949
|
-
<div class="meta-text">
|
|
30950
|
-
${esc(getMailSourceLabel(item))}
|
|
30951
|
-
${createdLabel ? ` · ${esc(createdLabel)}` : ""}
|
|
30952
|
-
${tags ? ` · ${esc(tags)}` : ""}
|
|
30953
|
-
</div>
|
|
30954
|
-
</div>
|
|
30955
|
-
<div class="page-header-actions">
|
|
30956
|
-
<span class="pill">${unread ? "Unread" : "Read"}</span>
|
|
30957
|
-
${archived ? '<span class="pill">Archived</span>' : ""}
|
|
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("")}
|
|
30958
31480
|
</div>
|
|
30959
|
-
</
|
|
30960
|
-
<div class="toolbar" data-oysterun-mail-detail-actions="true">
|
|
30961
|
-
<button class="btn-soft" type="button" data-mail-action="${
|
|
30962
|
-
unread ? "read" : "unread"
|
|
30963
|
-
}" data-mail-id="${esc(item.id)}">${
|
|
30964
|
-
unread ? "Mark read" : "Mark unread"
|
|
30965
|
-
}</button>
|
|
30966
|
-
<button class="btn-soft" type="button" data-mail-action="${
|
|
30967
|
-
archived ? "unarchive" : "archive"
|
|
30968
|
-
}" data-mail-id="${esc(item.id)}">${
|
|
30969
|
-
archived ? "Unarchive" : "Archive"
|
|
30970
|
-
}</button>
|
|
30971
|
-
<button class="btn-soft" type="button" data-mail-action="copy" data-mail-id="${esc(
|
|
30972
|
-
item.id
|
|
30973
|
-
)}">Copy mail link</button>
|
|
30974
|
-
<button class="btn-ghost" type="button" data-mail-action="delete" data-mail-id="${esc(
|
|
30975
|
-
item.id
|
|
30976
|
-
)}">Delete</button>
|
|
30977
|
-
</div>
|
|
30978
|
-
${
|
|
30979
|
-
item.summary
|
|
30980
|
-
? `<p class="field-hint">${esc(item.summary)}</p>`
|
|
30981
|
-
: ""
|
|
30982
|
-
}
|
|
31481
|
+
</header>
|
|
30983
31482
|
<div
|
|
30984
31483
|
class="mail-detail-body"
|
|
30985
31484
|
data-oysterun-mail-detail-renderer="${esc(item.body_format)}"
|
|
@@ -31022,6 +31521,7 @@ Waiting for Claude login output…</pre
|
|
|
31022
31521
|
null;
|
|
31023
31522
|
detailRoot.innerHTML = renderMailDetail(item);
|
|
31024
31523
|
hydrateRichContent(detailRoot);
|
|
31524
|
+
hydrateMailHtmlFrames(detailRoot);
|
|
31025
31525
|
}
|
|
31026
31526
|
return;
|
|
31027
31527
|
}
|
|
@@ -31291,11 +31791,25 @@ Waiting for Claude login output…</pre
|
|
|
31291
31791
|
|
|
31292
31792
|
function handleMailClick(event) {
|
|
31293
31793
|
const target = event.target instanceof Element ? event.target : null;
|
|
31294
|
-
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;
|
|
31295
31808
|
const filterButton = target.closest("[data-mail-filter]");
|
|
31296
31809
|
if (filterButton) {
|
|
31297
31810
|
event.preventDefault();
|
|
31298
31811
|
event.stopPropagation();
|
|
31812
|
+
closeMailRowActionMenu();
|
|
31299
31813
|
void navigateToRoute(
|
|
31300
31814
|
buildMailRoute({
|
|
31301
31815
|
filter: filterButton.getAttribute("data-mail-filter") || "inbox",
|
|
@@ -31303,10 +31817,21 @@ Waiting for Claude login output…</pre
|
|
|
31303
31817
|
);
|
|
31304
31818
|
return true;
|
|
31305
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
|
+
}
|
|
31306
31830
|
const actionButton = target.closest("[data-mail-action][data-mail-id]");
|
|
31307
31831
|
if (!actionButton) return false;
|
|
31308
31832
|
event.preventDefault();
|
|
31309
31833
|
event.stopPropagation();
|
|
31834
|
+
closeMailRowActionMenu();
|
|
31310
31835
|
void performMailAction(
|
|
31311
31836
|
actionButton.getAttribute("data-mail-id") || "",
|
|
31312
31837
|
actionButton.getAttribute("data-mail-action") || ""
|
|
@@ -36411,6 +36936,7 @@ Waiting for Claude login output…</pre
|
|
|
36411
36936
|
|
|
36412
36937
|
function renderSessionLoopRow(row) {
|
|
36413
36938
|
const enabled = row.enabled === true;
|
|
36939
|
+
const pending = sessionLoopState.pendingTargets?.[row.id] === true;
|
|
36414
36940
|
const expanded = sessionLoopState.editingId === row.id;
|
|
36415
36941
|
const intervalLabel = row.interval_token
|
|
36416
36942
|
? formatSessionLoopIntervalToken(row.interval_token)
|
|
@@ -36421,6 +36947,7 @@ Waiting for Claude login output…</pre
|
|
|
36421
36947
|
data-loop-row-id="${esc(row.id)}"
|
|
36422
36948
|
data-oysterun-session-loop-row="true"
|
|
36423
36949
|
data-oysterun-session-loop-enabled="${String(enabled)}"
|
|
36950
|
+
data-oysterun-session-loop-pending="${String(pending)}"
|
|
36424
36951
|
data-oysterun-session-loop-storage-owner="${esc(
|
|
36425
36952
|
row.storage_owner || "agent_folder_oysterun_loops_json"
|
|
36426
36953
|
)}"
|
|
@@ -36464,10 +36991,18 @@ Waiting for Claude login output…</pre
|
|
|
36464
36991
|
type="button"
|
|
36465
36992
|
role="switch"
|
|
36466
36993
|
aria-checked="${enabled ? "true" : "false"}"
|
|
36467
|
-
|
|
36994
|
+
aria-disabled="${pending ? "true" : "false"}"
|
|
36995
|
+
title="${
|
|
36996
|
+
pending ? "Updating..." : enabled ? "Enabled" : "Disabled"
|
|
36997
|
+
}"
|
|
36998
|
+
${pending ? "disabled" : ""}
|
|
36468
36999
|
data-loop-action="toggle-row"
|
|
36469
37000
|
data-loop-id="${esc(row.id)}"
|
|
36470
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
|
+
}"
|
|
36471
37006
|
>
|
|
36472
37007
|
<span aria-hidden="true"></span>
|
|
36473
37008
|
</button>
|
|
@@ -36634,12 +37169,23 @@ Waiting for Claude login output…</pre
|
|
|
36634
37169
|
const liveSession = getSelectedLiveSession();
|
|
36635
37170
|
const row = findSessionLoopRow(scheduleId);
|
|
36636
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);
|
|
36637
37182
|
try {
|
|
36638
37183
|
await api(
|
|
36639
37184
|
"PATCH",
|
|
36640
37185
|
`/session/loops/${encodeURIComponent(scheduleId)}`,
|
|
36641
37186
|
{
|
|
36642
37187
|
session_id: liveSession.sessionId,
|
|
37188
|
+
desired_enabled: enabled,
|
|
36643
37189
|
enabled,
|
|
36644
37190
|
runtime_only: true,
|
|
36645
37191
|
}
|
|
@@ -36653,6 +37199,16 @@ Waiting for Claude login output…</pre
|
|
|
36653
37199
|
error: err.message || String(err),
|
|
36654
37200
|
};
|
|
36655
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());
|
|
36656
37212
|
}
|
|
36657
37213
|
}
|
|
36658
37214
|
|
|
@@ -36729,6 +37285,8 @@ Waiting for Claude login output…</pre
|
|
|
36729
37285
|
return true;
|
|
36730
37286
|
}
|
|
36731
37287
|
if (action === "toggle-row") {
|
|
37288
|
+
if (sessionLoopState.pendingTargets?.[scheduleId] === true)
|
|
37289
|
+
return true;
|
|
36732
37290
|
const row = findSessionLoopRow(scheduleId);
|
|
36733
37291
|
if (row) {
|
|
36734
37292
|
void toggleSessionLoop(scheduleId, row.enabled !== true);
|
|
@@ -45385,6 +45943,94 @@ Waiting for Claude login output…</pre
|
|
|
45385
45943
|
return false;
|
|
45386
45944
|
}
|
|
45387
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
|
+
|
|
45388
46034
|
function hydrateRichContent(root) {
|
|
45389
46035
|
if (!root) return;
|
|
45390
46036
|
root
|
|
@@ -45847,6 +46493,9 @@ Waiting for Claude login output…</pre
|
|
|
45847
46493
|
async function doInterruptSession() {
|
|
45848
46494
|
const liveSession = getSelectedLiveSession();
|
|
45849
46495
|
if (!liveSession) return;
|
|
46496
|
+
if (routeCInterruptRequestInFlight) return;
|
|
46497
|
+
routeCInterruptRequestInFlight = true;
|
|
46498
|
+
updateComposerAvailability();
|
|
45850
46499
|
try {
|
|
45851
46500
|
await api("POST", "/session/interrupt", {
|
|
45852
46501
|
session_id: liveSession.sessionId,
|
|
@@ -45854,6 +46503,9 @@ Waiting for Claude login output…</pre
|
|
|
45854
46503
|
appendSystem(`Interrupted ${liveSession.sessionId}.`);
|
|
45855
46504
|
} catch (err) {
|
|
45856
46505
|
showBanner(err.message, true);
|
|
46506
|
+
} finally {
|
|
46507
|
+
routeCInterruptRequestInFlight = false;
|
|
46508
|
+
updateComposerAvailability();
|
|
45857
46509
|
}
|
|
45858
46510
|
}
|
|
45859
46511
|
|
|
@@ -47005,6 +47657,30 @@ Waiting for Claude login output…</pre
|
|
|
47005
47657
|
return;
|
|
47006
47658
|
}
|
|
47007
47659
|
|
|
47660
|
+
if (text.startsWith("!!")) {
|
|
47661
|
+
sendBtn.disabled =
|
|
47662
|
+
routeCInterruptRequestInFlight ||
|
|
47663
|
+
!hasActiveSession() ||
|
|
47664
|
+
!getSelectedLiveSession();
|
|
47665
|
+
sendBtn.dataset.oysterunRoutecInterruptInFlight = String(
|
|
47666
|
+
routeCInterruptRequestInFlight
|
|
47667
|
+
);
|
|
47668
|
+
sendBtn.dataset.oysterunRoutecInterruptOneShotDisabled = String(
|
|
47669
|
+
routeCInterruptRequestInFlight
|
|
47670
|
+
);
|
|
47671
|
+
setSendButtonState(
|
|
47672
|
+
routeCInterruptRequestInFlight
|
|
47673
|
+
? "Interrupting..."
|
|
47674
|
+
: "Stop response",
|
|
47675
|
+
true
|
|
47676
|
+
);
|
|
47677
|
+
updateComposerDebug();
|
|
47678
|
+
return;
|
|
47679
|
+
}
|
|
47680
|
+
|
|
47681
|
+
delete sendBtn.dataset.oysterunRoutecInterruptInFlight;
|
|
47682
|
+
delete sendBtn.dataset.oysterunRoutecInterruptOneShotDisabled;
|
|
47683
|
+
|
|
47008
47684
|
if (hasAttachments && matchedCommand) {
|
|
47009
47685
|
sendBtn.disabled = true;
|
|
47010
47686
|
setSendButtonState("Attachments only work with normal chat");
|