viveworker 0.4.7 → 0.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/package.json +1 -1
- package/scripts/a2a-executor.mjs +157 -19
- package/scripts/a2a-handler.mjs +2 -1
- package/scripts/a2a-relay-client.mjs +9 -0
- package/scripts/moltbook-api.mjs +209 -0
- package/scripts/moltbook-cli.mjs +12 -397
- package/scripts/viveworker-bridge.mjs +459 -47
- package/web/app.css +123 -1
- package/web/app.js +243 -36
- package/web/i18n.js +53 -3
package/web/app.css
CHANGED
|
@@ -524,7 +524,9 @@ code {
|
|
|
524
524
|
|
|
525
525
|
.settings-nav-row + .settings-nav-row,
|
|
526
526
|
.settings-info-row + .settings-info-row,
|
|
527
|
-
.settings-choice-row + .settings-choice-row
|
|
527
|
+
.settings-choice-row + .settings-choice-row,
|
|
528
|
+
.settings-radio-row + .settings-radio-row,
|
|
529
|
+
.settings-info-row + .settings-radio-row {
|
|
528
530
|
border-top: 1px solid rgba(255, 255, 255, 0.06);
|
|
529
531
|
}
|
|
530
532
|
|
|
@@ -533,6 +535,80 @@ code {
|
|
|
533
535
|
background: rgba(255, 255, 255, 0.035);
|
|
534
536
|
}
|
|
535
537
|
|
|
538
|
+
.settings-group__description {
|
|
539
|
+
margin: 0;
|
|
540
|
+
padding: 0.72rem 1rem;
|
|
541
|
+
font-size: 0.83rem;
|
|
542
|
+
line-height: 1.45;
|
|
543
|
+
color: var(--muted);
|
|
544
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
.settings-radio-row {
|
|
548
|
+
display: flex;
|
|
549
|
+
align-items: center;
|
|
550
|
+
gap: 0.78rem;
|
|
551
|
+
padding: 0.82rem 1rem;
|
|
552
|
+
cursor: pointer;
|
|
553
|
+
-webkit-tap-highlight-color: transparent;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
.settings-radio-row:active {
|
|
557
|
+
background: rgba(255, 255, 255, 0.035);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
.settings-radio-row input[type="radio"] {
|
|
561
|
+
appearance: none;
|
|
562
|
+
-webkit-appearance: none;
|
|
563
|
+
width: 1.25rem;
|
|
564
|
+
height: 1.25rem;
|
|
565
|
+
border: 2px solid rgba(156, 181, 197, 0.32);
|
|
566
|
+
border-radius: 50%;
|
|
567
|
+
background: transparent;
|
|
568
|
+
flex-shrink: 0;
|
|
569
|
+
position: relative;
|
|
570
|
+
cursor: pointer;
|
|
571
|
+
transition: border-color 160ms ease;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
.settings-radio-row input[type="radio"]:checked {
|
|
575
|
+
border-color: rgba(121, 196, 255, 0.92);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
.settings-radio-row input[type="radio"]:checked::after {
|
|
579
|
+
content: "";
|
|
580
|
+
position: absolute;
|
|
581
|
+
top: 50%;
|
|
582
|
+
left: 50%;
|
|
583
|
+
transform: translate(-50%, -50%);
|
|
584
|
+
width: 0.52rem;
|
|
585
|
+
height: 0.52rem;
|
|
586
|
+
border-radius: 50%;
|
|
587
|
+
background: rgba(121, 196, 255, 0.92);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
.settings-radio-row input[type="radio"]:disabled {
|
|
591
|
+
opacity: 0.35;
|
|
592
|
+
cursor: not-allowed;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
.settings-radio-row__label {
|
|
596
|
+
font-size: 0.94rem;
|
|
597
|
+
line-height: 1.25;
|
|
598
|
+
color: var(--text);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
.settings-radio-row__label.muted {
|
|
602
|
+
color: var(--muted);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
.settings-radio-row__badge {
|
|
606
|
+
margin-left: auto;
|
|
607
|
+
font-size: 0.74rem;
|
|
608
|
+
letter-spacing: 0.02em;
|
|
609
|
+
color: rgba(121, 196, 255, 0.82);
|
|
610
|
+
}
|
|
611
|
+
|
|
536
612
|
.settings-row__icon {
|
|
537
613
|
width: 1.95rem;
|
|
538
614
|
height: 1.95rem;
|
|
@@ -2354,6 +2430,24 @@ code {
|
|
|
2354
2430
|
border-color: var(--accent, #6ea8ff);
|
|
2355
2431
|
}
|
|
2356
2432
|
|
|
2433
|
+
.a2a-task-response {
|
|
2434
|
+
width: 100%;
|
|
2435
|
+
padding: 0.85rem 0.95rem;
|
|
2436
|
+
border-radius: 14px;
|
|
2437
|
+
border: 1px solid var(--line);
|
|
2438
|
+
background: var(--surface, #1a1a2e);
|
|
2439
|
+
color: var(--fg);
|
|
2440
|
+
font-family: "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
|
|
2441
|
+
font-size: 0.85rem;
|
|
2442
|
+
line-height: 1.55;
|
|
2443
|
+
white-space: pre-wrap;
|
|
2444
|
+
word-break: break-word;
|
|
2445
|
+
overflow-x: auto;
|
|
2446
|
+
max-height: 24rem;
|
|
2447
|
+
overflow-y: auto;
|
|
2448
|
+
margin: 0;
|
|
2449
|
+
}
|
|
2450
|
+
|
|
2357
2451
|
.compose-greeting {
|
|
2358
2452
|
display: flex;
|
|
2359
2453
|
align-items: center;
|
|
@@ -2655,6 +2749,34 @@ code {
|
|
|
2655
2749
|
line-height: 1.45;
|
|
2656
2750
|
}
|
|
2657
2751
|
|
|
2752
|
+
.reply-mode-switch--settings {
|
|
2753
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
2754
|
+
align-items: start;
|
|
2755
|
+
}
|
|
2756
|
+
|
|
2757
|
+
.reply-mode-switch--settings__toggle {
|
|
2758
|
+
grid-column: 2;
|
|
2759
|
+
grid-row: 1;
|
|
2760
|
+
display: flex;
|
|
2761
|
+
flex-direction: column;
|
|
2762
|
+
align-items: center;
|
|
2763
|
+
gap: 0.32rem;
|
|
2764
|
+
}
|
|
2765
|
+
|
|
2766
|
+
.reply-mode-switch--settings .reply-mode-switch__hint {
|
|
2767
|
+
grid-column: 1;
|
|
2768
|
+
grid-row: 1;
|
|
2769
|
+
}
|
|
2770
|
+
|
|
2771
|
+
.reply-mode-switch__input:checked ~ .reply-mode-switch--settings__toggle .reply-mode-switch__track {
|
|
2772
|
+
background: rgba(67, 160, 255, 0.28);
|
|
2773
|
+
border-color: rgba(121, 196, 255, 0.34);
|
|
2774
|
+
}
|
|
2775
|
+
|
|
2776
|
+
.reply-mode-switch__input:checked ~ .reply-mode-switch--settings__toggle .reply-mode-switch__thumb {
|
|
2777
|
+
transform: translateX(1.06rem);
|
|
2778
|
+
}
|
|
2779
|
+
|
|
2658
2780
|
@keyframes detail-loading-pulse {
|
|
2659
2781
|
0% {
|
|
2660
2782
|
background-position: 100% 0;
|
package/web/app.js
CHANGED
|
@@ -5,7 +5,7 @@ const INSTALL_BANNER_DISMISS_KEY = "viveworker-install-banner-dismissed-v2";
|
|
|
5
5
|
const PUSH_BANNER_DISMISS_KEY = "viveworker-push-banner-dismissed-v1";
|
|
6
6
|
const INITIAL_DETECTED_LOCALE = detectBrowserLocale();
|
|
7
7
|
const TIMELINE_MESSAGE_KINDS = new Set(["user_message", "assistant_commentary", "assistant_final"]);
|
|
8
|
-
const TIMELINE_OPERATIONAL_KINDS = new Set(["approval", "plan", "plan_ready", "choice"
|
|
8
|
+
const TIMELINE_OPERATIONAL_KINDS = new Set(["approval", "plan", "plan_ready", "choice"]);
|
|
9
9
|
const THREAD_FILTER_INTERACTION_DEFER_MS = 8000;
|
|
10
10
|
const MAX_COMPLETION_REPLY_IMAGE_COUNT = 4;
|
|
11
11
|
const NOTIFICATION_INTENT_CACHE = "viveworker-notification-intent-v1";
|
|
@@ -612,12 +612,19 @@ function filteredDiffEntries() {
|
|
|
612
612
|
}
|
|
613
613
|
|
|
614
614
|
function syncTimelineThreadFilter() {
|
|
615
|
-
const threads = Array.isArray(state.timeline?.threads) ? state.timeline.threads : [];
|
|
616
615
|
if (!state.timelineThreadFilter || state.timelineThreadFilter === "all") {
|
|
617
616
|
state.timelineThreadFilter = "all";
|
|
618
617
|
return;
|
|
619
618
|
}
|
|
620
|
-
|
|
619
|
+
const provider = state.providerFilter || "all";
|
|
620
|
+
let validThreadIds;
|
|
621
|
+
if (provider === "all") {
|
|
622
|
+
const threads = Array.isArray(state.timeline?.threads) ? state.timeline.threads : [];
|
|
623
|
+
validThreadIds = new Set(threads.map((t) => t.id));
|
|
624
|
+
} else {
|
|
625
|
+
validThreadIds = new Set(timelineThreadsForProvider(provider).map((t) => t.id));
|
|
626
|
+
}
|
|
627
|
+
if (!validThreadIds.has(state.timelineThreadFilter)) {
|
|
621
628
|
state.timelineThreadFilter = "all";
|
|
622
629
|
}
|
|
623
630
|
}
|
|
@@ -630,16 +637,47 @@ function syncTimelineKindFilter() {
|
|
|
630
637
|
}
|
|
631
638
|
|
|
632
639
|
function timelineKindFilterOptions() {
|
|
633
|
-
|
|
634
|
-
|
|
640
|
+
const provider = state.providerFilter || "all";
|
|
641
|
+
const allOption = { id: "all", label: L("timeline.kindFilter.all"), icon: "filter" };
|
|
642
|
+
|
|
643
|
+
if (provider === "moltbook") {
|
|
644
|
+
return [
|
|
645
|
+
allOption,
|
|
646
|
+
{ id: "moltbook_reply_drafts", label: L("timeline.kindFilter.moltbookReplyDrafts"), icon: "moltbook-reply" },
|
|
647
|
+
{ id: "moltbook_post_drafts", label: L("timeline.kindFilter.moltbookPostDrafts"), icon: "moltbook-draft" },
|
|
648
|
+
{ id: "moltbook_comments", label: L("timeline.kindFilter.moltbookComments"), icon: "moltbook-comment" },
|
|
649
|
+
];
|
|
650
|
+
}
|
|
651
|
+
if (provider === "a2a") {
|
|
652
|
+
return [
|
|
653
|
+
allOption,
|
|
654
|
+
{ id: "a2a_requests", label: L("timeline.kindFilter.a2aRequests"), icon: "item" },
|
|
655
|
+
{ id: "a2a_results", label: L("timeline.kindFilter.a2aResults"), icon: "completion-item" },
|
|
656
|
+
];
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
const codexClaudeOptions = [
|
|
660
|
+
allOption,
|
|
635
661
|
{ id: "messages", label: L("timeline.kindFilter.messages"), icon: "timeline" },
|
|
636
662
|
{ id: "files", label: L("timeline.kindFilter.files"), icon: "file-event" },
|
|
637
663
|
{ id: "approvals", label: L("timeline.kindFilter.approvals"), icon: "approval" },
|
|
638
664
|
{ id: "plans", label: L("timeline.kindFilter.plans"), icon: "plan" },
|
|
639
665
|
{ id: "choices", label: L("timeline.kindFilter.choices"), icon: "choice" },
|
|
640
|
-
{ id: "
|
|
641
|
-
|
|
666
|
+
{ id: "final_answers", label: L("timeline.kindFilter.finalAnswers"), icon: "assistant-final" },
|
|
667
|
+
];
|
|
668
|
+
|
|
669
|
+
if (provider === "codex" || provider === "claude") {
|
|
670
|
+
return codexClaudeOptions;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// "all" — union of everything
|
|
674
|
+
return [
|
|
675
|
+
...codexClaudeOptions,
|
|
676
|
+
{ id: "moltbook_reply_drafts", label: L("timeline.kindFilter.moltbookReplyDrafts"), icon: "moltbook-reply" },
|
|
677
|
+
{ id: "moltbook_post_drafts", label: L("timeline.kindFilter.moltbookPostDrafts"), icon: "moltbook-draft" },
|
|
642
678
|
{ id: "moltbook_comments", label: L("timeline.kindFilter.moltbookComments"), icon: "moltbook-comment" },
|
|
679
|
+
{ id: "a2a_requests", label: L("timeline.kindFilter.a2aRequests"), icon: "item" },
|
|
680
|
+
{ id: "a2a_results", label: L("timeline.kindFilter.a2aResults"), icon: "completion-item" },
|
|
643
681
|
];
|
|
644
682
|
}
|
|
645
683
|
|
|
@@ -665,10 +703,20 @@ function timelineEntryMatchesKindFilter(entry, filterId) {
|
|
|
665
703
|
return kind === "choice";
|
|
666
704
|
case "completions":
|
|
667
705
|
return kind === "completion";
|
|
706
|
+
case "final_answers":
|
|
707
|
+
return kind === "assistant_final";
|
|
668
708
|
case "moltbook_drafts":
|
|
669
709
|
return kind === "moltbook_draft";
|
|
710
|
+
case "moltbook_reply_drafts":
|
|
711
|
+
return kind === "moltbook_draft" && entry?.draftType === "reply";
|
|
712
|
+
case "moltbook_post_drafts":
|
|
713
|
+
return kind === "moltbook_draft" && entry?.draftType !== "reply";
|
|
670
714
|
case "moltbook_comments":
|
|
671
715
|
return kind === "moltbook_reply";
|
|
716
|
+
case "a2a_requests":
|
|
717
|
+
return kind === "a2a_task";
|
|
718
|
+
case "a2a_results":
|
|
719
|
+
return kind === "a2a_task_result";
|
|
672
720
|
default:
|
|
673
721
|
return true;
|
|
674
722
|
}
|
|
@@ -689,10 +737,19 @@ function completedThreads() {
|
|
|
689
737
|
if (!items.length) {
|
|
690
738
|
return [];
|
|
691
739
|
}
|
|
740
|
+
const provider = state.providerFilter || "all";
|
|
692
741
|
const byThread = new Map();
|
|
693
742
|
for (const item of items) {
|
|
694
743
|
const threadId = normalizeClientText(item.threadId || "");
|
|
695
|
-
if (!threadId
|
|
744
|
+
if (!threadId) {
|
|
745
|
+
continue;
|
|
746
|
+
}
|
|
747
|
+
// Skip Moltbook threads unless Moltbook tab is active
|
|
748
|
+
if (provider !== "moltbook" && isMoltbookThreadId(threadId, item)) {
|
|
749
|
+
continue;
|
|
750
|
+
}
|
|
751
|
+
// Filter by provider
|
|
752
|
+
if (provider !== "all" && normalizeProviderClient(item.provider) !== provider) {
|
|
696
753
|
continue;
|
|
697
754
|
}
|
|
698
755
|
const latestAtMs = Number(item.createdAtMs || 0);
|
|
@@ -1375,7 +1432,6 @@ function buildDetailLoadingSnapshot(itemRef = state.currentItem) {
|
|
|
1375
1432
|
readOnly:
|
|
1376
1433
|
entry?.status === "completed" ||
|
|
1377
1434
|
TIMELINE_MESSAGE_KINDS.has(itemRef.kind) ||
|
|
1378
|
-
itemRef.kind === "completion" ||
|
|
1379
1435
|
(itemRef.kind === "choice" && item.supported === false),
|
|
1380
1436
|
loading: true,
|
|
1381
1437
|
};
|
|
@@ -1779,11 +1835,13 @@ function renderProviderFilter() {
|
|
|
1779
1835
|
`;
|
|
1780
1836
|
}
|
|
1781
1837
|
|
|
1838
|
+
const COMPLETED_CARD_KINDS = new Set(["assistant_final", "approval", "moltbook_reply", "moltbook_draft", "a2a_task_result", "thread_share"]);
|
|
1839
|
+
|
|
1782
1840
|
function renderItemCard(entry, sourceTab, desktop) {
|
|
1783
|
-
if (entry.status === "completed" && entry.item.kind
|
|
1841
|
+
if (entry.status === "completed" && COMPLETED_CARD_KINDS.has(entry.item.kind)) {
|
|
1784
1842
|
return renderCompletedCompletionCard(entry, sourceTab);
|
|
1785
1843
|
}
|
|
1786
|
-
const kindInfo = kindMeta(entry.item.kind);
|
|
1844
|
+
const kindInfo = kindMeta(entry.item.kind, entry.item);
|
|
1787
1845
|
const cardTitle = cardTitleForEntry(entry);
|
|
1788
1846
|
const statusText = entry.status === "completed" ? L("common.completed") : L("common.actionNeeded");
|
|
1789
1847
|
const intentText = itemIntentText(entry.item.kind, entry.status, entry.item.provider);
|
|
@@ -1852,10 +1910,12 @@ function cardTitleForEntry(entry) {
|
|
|
1852
1910
|
|
|
1853
1911
|
function renderCompletedCompletionCard(entry, sourceTab) {
|
|
1854
1912
|
const item = entry.item;
|
|
1855
|
-
const kindInfo = kindMeta(item.kind);
|
|
1913
|
+
const kindInfo = kindMeta(item.kind, item);
|
|
1856
1914
|
const summaryText = item.summary || fallbackSummaryForKind(item.kind, entry.status, item.provider);
|
|
1857
1915
|
const threadLabel = timelineEntryThreadLabel(item, true);
|
|
1858
1916
|
const timestampLabel = formatTimelineTimestamp(item.createdAtMs);
|
|
1917
|
+
const pillLabel = item.kind === "completion" ? L("common.task") : kindInfo.label;
|
|
1918
|
+
const pillTone = item.kind === "completion" ? "completion" : kindInfo.tone;
|
|
1859
1919
|
|
|
1860
1920
|
return `
|
|
1861
1921
|
<button
|
|
@@ -1867,7 +1927,7 @@ function renderCompletedCompletionCard(entry, sourceTab) {
|
|
|
1867
1927
|
>
|
|
1868
1928
|
<div class="item-card__header">
|
|
1869
1929
|
<div class="item-card__meta">
|
|
1870
|
-
<span class="type-pill type-pill
|
|
1930
|
+
<span class="type-pill type-pill--${escapeHtml(pillTone)}">${escapeHtml(pillLabel)}</span>
|
|
1871
1931
|
${renderProviderBadge(item.provider)}
|
|
1872
1932
|
</div>
|
|
1873
1933
|
<div class="item-card__header-right">
|
|
@@ -1957,17 +2017,47 @@ function renderDiffPanel({ entries, desktop }) {
|
|
|
1957
2017
|
`;
|
|
1958
2018
|
}
|
|
1959
2019
|
|
|
2020
|
+
function timelineThreadsForProvider(provider) {
|
|
2021
|
+
const entries = Array.isArray(state.timeline?.entries) ? state.timeline.entries : [];
|
|
2022
|
+
const byThread = new Map();
|
|
2023
|
+
for (const entry of entries) {
|
|
2024
|
+
const threadId = entry.threadId || "";
|
|
2025
|
+
if (!threadId) continue;
|
|
2026
|
+
if (normalizeProviderClient(entry.provider) !== provider) continue;
|
|
2027
|
+
const latestAtMs = Number(entry.createdAtMs) || 0;
|
|
2028
|
+
const label = entry.threadLabel || "";
|
|
2029
|
+
const existing = byThread.get(threadId);
|
|
2030
|
+
if (!existing || latestAtMs > existing.latestAtMs) {
|
|
2031
|
+
byThread.set(threadId, { id: threadId, label, latestAtMs });
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
return [...byThread.values()]
|
|
2035
|
+
.sort((a, b) => b.latestAtMs - a.latestAtMs)
|
|
2036
|
+
.map((t) => ({ id: t.id, label: dropdownThreadLabel(t.id, t.label) }));
|
|
2037
|
+
}
|
|
2038
|
+
|
|
1960
2039
|
function renderTimelineThreadDropdown() {
|
|
1961
|
-
const
|
|
2040
|
+
const provider = state.providerFilter || "all";
|
|
2041
|
+
const kindFilterHtml = renderTimelineKindFilterControls();
|
|
2042
|
+
|
|
2043
|
+
let threads;
|
|
2044
|
+
if (provider === "all") {
|
|
2045
|
+
// "All" view — use the server-provided thread list
|
|
2046
|
+
threads = (Array.isArray(state.timeline?.threads) ? state.timeline.threads : []).map((thread) => ({
|
|
2047
|
+
id: thread.id,
|
|
2048
|
+
label: dropdownThreadLabel(thread.id, thread.label || ""),
|
|
2049
|
+
}));
|
|
2050
|
+
} else {
|
|
2051
|
+
// Provider-specific view — build from entries matching this provider
|
|
2052
|
+
threads = timelineThreadsForProvider(provider);
|
|
2053
|
+
}
|
|
2054
|
+
|
|
1962
2055
|
return renderThreadDropdown({
|
|
1963
2056
|
inputId: "timeline-thread-select",
|
|
1964
2057
|
dataAttribute: "data-timeline-thread-select",
|
|
1965
2058
|
selectedThreadId: state.timelineThreadFilter,
|
|
1966
|
-
controlsHtml:
|
|
1967
|
-
threads
|
|
1968
|
-
id: thread.id,
|
|
1969
|
-
label: dropdownThreadLabel(thread.id, thread.label || ""),
|
|
1970
|
-
})),
|
|
2059
|
+
controlsHtml: kindFilterHtml,
|
|
2060
|
+
threads,
|
|
1971
2061
|
});
|
|
1972
2062
|
}
|
|
1973
2063
|
|
|
@@ -2072,10 +2162,11 @@ function renderTimelineKindFilterControls() {
|
|
|
2072
2162
|
|
|
2073
2163
|
function renderTimelineEntry(entry, { desktop }) {
|
|
2074
2164
|
const item = entry.item;
|
|
2075
|
-
const kindInfo = kindMeta(item.kind);
|
|
2165
|
+
const kindInfo = kindMeta(item.kind, item);
|
|
2076
2166
|
const kindClassName = escapeHtml(kindInfo.tone || "neutral");
|
|
2077
2167
|
const kindNameClass = escapeHtml(String(item.kind || "item").replace(/_/gu, "-"));
|
|
2078
|
-
const
|
|
2168
|
+
const isMoltbookOrA2A = item.kind === "moltbook_reply" || item.kind === "moltbook_draft" || item.kind === "a2a_task" || item.kind === "a2a_task_result" || item.kind === "thread_share";
|
|
2169
|
+
const isMessageLike = TIMELINE_MESSAGE_KINDS.has(item.kind) || isMoltbookOrA2A;
|
|
2079
2170
|
const isFileEvent = item.kind === "file_event";
|
|
2080
2171
|
const imageUrls = Array.isArray(item.imageUrls) ? item.imageUrls.filter(Boolean) : [];
|
|
2081
2172
|
const fileRefs = normalizeClientFileRefs(item.fileRefs);
|
|
@@ -2932,6 +3023,9 @@ function settingsPageMeta(page) {
|
|
|
2932
3023
|
description: L("settings.a2aRelay.copy"),
|
|
2933
3024
|
icon: "link",
|
|
2934
3025
|
};
|
|
3026
|
+
case "a2aExecutor":
|
|
3027
|
+
// Executor settings integrated into a2aRelay page — redirect.
|
|
3028
|
+
return settingsPageMeta("a2aRelay");
|
|
2935
3029
|
default:
|
|
2936
3030
|
return settingsPageMeta("notifications");
|
|
2937
3031
|
}
|
|
@@ -3064,6 +3158,7 @@ function renderSettingsSubpage(context, { mobile }) {
|
|
|
3064
3158
|
content = renderSettingsMoltbookPage(context);
|
|
3065
3159
|
break;
|
|
3066
3160
|
case "a2aRelay":
|
|
3161
|
+
case "a2aExecutor":
|
|
3067
3162
|
content = renderSettingsA2aRelayPage(context);
|
|
3068
3163
|
break;
|
|
3069
3164
|
default:
|
|
@@ -3334,6 +3429,21 @@ function renderSettingsA2aRelayPage(context) {
|
|
|
3334
3429
|
const profileUrl = `${relay.relayUrl}/${relay.userId}`;
|
|
3335
3430
|
const userIdLink = `<a href="${escapeHtml(profileUrl)}" target="_blank" rel="noopener">${escapeHtml(relay.userId)}</a>`;
|
|
3336
3431
|
const relayHost = (() => { try { return new URL(relay.relayUrl).host; } catch { return relay.relayUrl; } })();
|
|
3432
|
+
const publicChecked = relay.acceptPublicTasks === true;
|
|
3433
|
+
|
|
3434
|
+
// Executor preference section
|
|
3435
|
+
const executors = state.session?.a2aExecutors || { codex: false, claude: false };
|
|
3436
|
+
const currentExec = state.session?.a2aExecutorPreference || "ask";
|
|
3437
|
+
const bothAvailable = executors.codex && executors.claude;
|
|
3438
|
+
const execOptions = [
|
|
3439
|
+
{ id: "ask", label: L("settings.a2aExecutor.ask") },
|
|
3440
|
+
];
|
|
3441
|
+
if (executors.codex) execOptions.push({ id: "codex", label: L("settings.a2aExecutor.codex"), detected: true });
|
|
3442
|
+
if (executors.claude) execOptions.push({ id: "claude", label: L("settings.a2aExecutor.claude"), detected: true });
|
|
3443
|
+
if (bothAvailable) {
|
|
3444
|
+
execOptions.push({ id: "auto", label: L("settings.a2aExecutor.auto") });
|
|
3445
|
+
}
|
|
3446
|
+
|
|
3337
3447
|
return `
|
|
3338
3448
|
<div class="settings-page">
|
|
3339
3449
|
${renderSettingsGroup("", [
|
|
@@ -3345,6 +3455,28 @@ function renderSettingsA2aRelayPage(context) {
|
|
|
3345
3455
|
? renderSettingsInfoRow(L("settings.row.a2aLastPoll"), new Date(relay.lastPollAtMs).toLocaleString(state.locale))
|
|
3346
3456
|
: "",
|
|
3347
3457
|
].filter(Boolean))}
|
|
3458
|
+
<section class="settings-group">
|
|
3459
|
+
<p class="settings-group__title">${escapeHtml(L("settings.a2aRelay.publicTasks.title"))}</p>
|
|
3460
|
+
<label class="reply-mode-switch reply-mode-switch--settings" data-a2a-public-toggle>
|
|
3461
|
+
<input type="checkbox" class="reply-mode-switch__input" ${publicChecked ? "checked" : ""} data-a2a-public-checkbox />
|
|
3462
|
+
<span class="reply-mode-switch--settings__toggle">
|
|
3463
|
+
<span class="reply-mode-switch__track" aria-hidden="true"><span class="reply-mode-switch__thumb"></span></span>
|
|
3464
|
+
<span class="reply-mode-switch__state">${escapeHtml(publicChecked ? L("settings.claudeAway.on") : L("settings.claudeAway.off"))}</span>
|
|
3465
|
+
</span>
|
|
3466
|
+
<span class="reply-mode-switch__hint">${escapeHtml(L("settings.a2aRelay.publicTasks.description"))}</span>
|
|
3467
|
+
</label>
|
|
3468
|
+
</section>
|
|
3469
|
+
${renderSettingsGroup(L("settings.a2aExecutor.title"), [
|
|
3470
|
+
`<p class="settings-group__description">${escapeHtml(L("settings.a2aExecutor.copy"))}</p>`,
|
|
3471
|
+
...execOptions.map((opt) => `
|
|
3472
|
+
<label class="settings-radio-row" data-a2a-executor-option="${escapeHtml(opt.id)}">
|
|
3473
|
+
<input type="radio" name="a2aExecutor" value="${escapeHtml(opt.id)}"
|
|
3474
|
+
${currentExec === opt.id ? "checked" : ""} />
|
|
3475
|
+
<span class="settings-radio-row__label">${escapeHtml(opt.label)}</span>
|
|
3476
|
+
${opt.detected ? `<span class="settings-radio-row__badge">✓ ${escapeHtml(L("settings.a2aExecutor.detected"))}</span>` : ""}
|
|
3477
|
+
</label>
|
|
3478
|
+
`),
|
|
3479
|
+
])}
|
|
3348
3480
|
</div>
|
|
3349
3481
|
`;
|
|
3350
3482
|
}
|
|
@@ -3455,8 +3587,8 @@ function renderDetailContent(detail, { mobile }) {
|
|
|
3455
3587
|
}
|
|
3456
3588
|
|
|
3457
3589
|
function renderStandardDetailDesktop(detail) {
|
|
3458
|
-
const kindInfo = kindMeta(detail.kind);
|
|
3459
|
-
const spaciousBodyDetail = TIMELINE_MESSAGE_KINDS.has(detail.kind)
|
|
3590
|
+
const kindInfo = kindMeta(detail.kind, detail);
|
|
3591
|
+
const spaciousBodyDetail = TIMELINE_MESSAGE_KINDS.has(detail.kind);
|
|
3460
3592
|
const plainIntro = renderDetailPlainIntro(detail);
|
|
3461
3593
|
return `
|
|
3462
3594
|
<div class="detail-shell">
|
|
@@ -3470,7 +3602,7 @@ function renderStandardDetailDesktop(detail) {
|
|
|
3470
3602
|
${renderA2ATaskDetail(detail)}
|
|
3471
3603
|
${renderThreadShareDetail(detail)}
|
|
3472
3604
|
${
|
|
3473
|
-
detail.kind === "moltbook_draft" || detail.kind === "moltbook_reply" || detail.kind === "a2a_task" || detail.kind === "thread_share"
|
|
3605
|
+
detail.kind === "moltbook_draft" || detail.kind === "moltbook_reply" || detail.kind === "a2a_task" || detail.kind === "a2a_task_result" || detail.kind === "thread_share"
|
|
3474
3606
|
? ""
|
|
3475
3607
|
: plainIntro
|
|
3476
3608
|
? plainIntro
|
|
@@ -3493,8 +3625,8 @@ function renderStandardDetailDesktop(detail) {
|
|
|
3493
3625
|
}
|
|
3494
3626
|
|
|
3495
3627
|
function renderStandardDetailMobile(detail) {
|
|
3496
|
-
const kindInfo = kindMeta(detail.kind);
|
|
3497
|
-
const spaciousBodyDetail = TIMELINE_MESSAGE_KINDS.has(detail.kind)
|
|
3628
|
+
const kindInfo = kindMeta(detail.kind, detail);
|
|
3629
|
+
const spaciousBodyDetail = TIMELINE_MESSAGE_KINDS.has(detail.kind);
|
|
3498
3630
|
const plainIntro = renderDetailPlainIntro(detail, { mobile: true });
|
|
3499
3631
|
return `
|
|
3500
3632
|
<div class="mobile-detail-screen">
|
|
@@ -3508,7 +3640,7 @@ function renderStandardDetailMobile(detail) {
|
|
|
3508
3640
|
${renderA2ATaskDetail(detail, { mobile: true })}
|
|
3509
3641
|
${renderThreadShareDetail(detail, { mobile: true })}
|
|
3510
3642
|
${
|
|
3511
|
-
detail.kind === "moltbook_draft" || detail.kind === "moltbook_reply" || detail.kind === "a2a_task" || detail.kind === "thread_share"
|
|
3643
|
+
detail.kind === "moltbook_draft" || detail.kind === "moltbook_reply" || detail.kind === "a2a_task" || detail.kind === "a2a_task_result" || detail.kind === "thread_share"
|
|
3512
3644
|
? ""
|
|
3513
3645
|
: plainIntro
|
|
3514
3646
|
? plainIntro
|
|
@@ -4066,7 +4198,7 @@ function renderMoltbookDraftComposer(detail, options = {}) {
|
|
|
4066
4198
|
}
|
|
4067
4199
|
|
|
4068
4200
|
function renderA2ATaskDetail(detail, options = {}) {
|
|
4069
|
-
if (detail.kind !== "a2a_task") return "";
|
|
4201
|
+
if (detail.kind !== "a2a_task" && detail.kind !== "a2a_task_result") return "";
|
|
4070
4202
|
const enabled = detail.a2aTaskEnabled !== false && detail.readOnly !== true;
|
|
4071
4203
|
const instruction = detail.instruction || "";
|
|
4072
4204
|
const callerIp = detail.callerInfo?.ip || "";
|
|
@@ -4084,10 +4216,32 @@ function renderA2ATaskDetail(detail, options = {}) {
|
|
|
4084
4216
|
rejected: "a2a.task.statusRejected",
|
|
4085
4217
|
}[detail.taskStatus] || "a2a.task.statusSubmitted";
|
|
4086
4218
|
|
|
4087
|
-
const statusBadge = !enabled
|
|
4219
|
+
const statusBadge = !enabled && detail.kind === "a2a_task_result"
|
|
4088
4220
|
? `<span class="eyebrow-pill eyebrow-pill--subtle">${escapeHtml(L(statusKey))}</span>`
|
|
4089
4221
|
: "";
|
|
4090
4222
|
|
|
4223
|
+
// Show executor selector when "ask" mode is active and both CLIs are available.
|
|
4224
|
+
const executors = state.session?.a2aExecutors || { codex: false, claude: false };
|
|
4225
|
+
const executorPref = state.session?.a2aExecutorPreference || "auto";
|
|
4226
|
+
const showExecutorPicker = enabled && executorPref === "ask" && executors.codex && executors.claude;
|
|
4227
|
+
const executorPicker = showExecutorPicker
|
|
4228
|
+
? `
|
|
4229
|
+
<div class="reply-composer__instruction">
|
|
4230
|
+
<label class="field-label">${escapeHtml(L("a2a.task.executor"))}</label>
|
|
4231
|
+
<div class="a2a-executor-picker">
|
|
4232
|
+
<label class="a2a-executor-picker__option">
|
|
4233
|
+
<input type="radio" name="executor" value="codex" checked />
|
|
4234
|
+
<span>${escapeHtml(L("a2a.executor.codex"))}</span>
|
|
4235
|
+
</label>
|
|
4236
|
+
<label class="a2a-executor-picker__option">
|
|
4237
|
+
<input type="radio" name="executor" value="claude" />
|
|
4238
|
+
<span>${escapeHtml(L("a2a.executor.claude"))}</span>
|
|
4239
|
+
</label>
|
|
4240
|
+
</div>
|
|
4241
|
+
</div>
|
|
4242
|
+
`
|
|
4243
|
+
: "";
|
|
4244
|
+
|
|
4091
4245
|
const buttons = enabled
|
|
4092
4246
|
? `
|
|
4093
4247
|
<div class="actions actions--stack${options.mobile ? " actions--sticky" : ""}">
|
|
@@ -4111,6 +4265,13 @@ function renderA2ATaskDetail(detail, options = {}) {
|
|
|
4111
4265
|
<label class="field-label">${escapeHtml(L("a2a.task.instruction"))}</label>
|
|
4112
4266
|
<textarea name="instruction" class="reply-composer__textarea" rows="6" ${enabled ? "" : "readonly"}>${escapeHtml(instruction)}</textarea>
|
|
4113
4267
|
</div>
|
|
4268
|
+
${executorPicker}
|
|
4269
|
+
${!enabled && detail.messageText ? `
|
|
4270
|
+
<div class="reply-composer__instruction">
|
|
4271
|
+
<label class="field-label">${escapeHtml(L("a2a.task.response"))}</label>
|
|
4272
|
+
<pre class="a2a-task-response">${escapeHtml(detail.messageText)}</pre>
|
|
4273
|
+
</div>
|
|
4274
|
+
` : ""}
|
|
4114
4275
|
${buttonsWrapped}
|
|
4115
4276
|
</form>
|
|
4116
4277
|
</section>
|
|
@@ -4168,7 +4329,7 @@ function renderThreadShareDetail(detail, options = {}) {
|
|
|
4168
4329
|
}
|
|
4169
4330
|
|
|
4170
4331
|
function renderCompletionReplyComposer(detail, options = {}) {
|
|
4171
|
-
if (detail.kind !== "completion" || detail.reply?.enabled !== true) {
|
|
4332
|
+
if ((detail.kind !== "completion" && detail.kind !== "assistant_final") || detail.reply?.enabled !== true) {
|
|
4172
4333
|
return "";
|
|
4173
4334
|
}
|
|
4174
4335
|
|
|
@@ -4238,7 +4399,7 @@ function renderCompletionReplyComposer(detail, options = {}) {
|
|
|
4238
4399
|
</div>
|
|
4239
4400
|
`
|
|
4240
4401
|
: `
|
|
4241
|
-
<form class="reply-composer__form" data-completion-reply-form data-token="${escapeHtml(detail.token)}" data-provider="${escapeHtml(normalizeProviderClient(detail?.provider))}">
|
|
4402
|
+
<form class="reply-composer__form" data-completion-reply-form data-token="${escapeHtml(detail.token)}" data-provider="${escapeHtml(normalizeProviderClient(detail?.provider))}" data-reply-kind="${escapeHtml(detail.kind)}">
|
|
4242
4403
|
<label class="field reply-field">
|
|
4243
4404
|
<span class="field-label">${escapeHtml(L("reply.fieldLabel"))}</span>
|
|
4244
4405
|
<div class="reply-field__shell">
|
|
@@ -4816,6 +4977,11 @@ function bindShellInteractions() {
|
|
|
4816
4977
|
return;
|
|
4817
4978
|
}
|
|
4818
4979
|
state.providerFilter = next;
|
|
4980
|
+
// Reset thread/kind filters — each provider has its own set of valid options
|
|
4981
|
+
state.timelineThreadFilter = "all";
|
|
4982
|
+
state.timelineKindFilter = "all";
|
|
4983
|
+
state.timelineKindFilterOpen = false;
|
|
4984
|
+
state.completedThreadFilter = "all";
|
|
4819
4985
|
alignCurrentItemToVisibleEntries();
|
|
4820
4986
|
await renderShell();
|
|
4821
4987
|
});
|
|
@@ -5161,6 +5327,33 @@ function bindShellInteractions() {
|
|
|
5161
5327
|
});
|
|
5162
5328
|
}
|
|
5163
5329
|
|
|
5330
|
+
for (const checkbox of document.querySelectorAll("[data-a2a-public-checkbox]")) {
|
|
5331
|
+
checkbox.addEventListener("change", async () => {
|
|
5332
|
+
const next = checkbox.checked === true;
|
|
5333
|
+
try {
|
|
5334
|
+
await apiPost("/api/a2a/public-tasks", { accept: next });
|
|
5335
|
+
state.a2aRelayStatus = await apiGet("/api/a2a/relay-status");
|
|
5336
|
+
} catch (error) {
|
|
5337
|
+
state.pushError = error.message || String(error);
|
|
5338
|
+
}
|
|
5339
|
+
await renderShell();
|
|
5340
|
+
});
|
|
5341
|
+
}
|
|
5342
|
+
|
|
5343
|
+
for (const radio of document.querySelectorAll("[data-a2a-executor-option] input[type='radio']")) {
|
|
5344
|
+
radio.addEventListener("change", async () => {
|
|
5345
|
+
if (!radio.checked) return;
|
|
5346
|
+
const preference = radio.value || "auto";
|
|
5347
|
+
try {
|
|
5348
|
+
await apiPost("/api/settings/a2a-executor", { preference });
|
|
5349
|
+
await refreshSession();
|
|
5350
|
+
} catch (error) {
|
|
5351
|
+
state.pushError = error.message || String(error);
|
|
5352
|
+
}
|
|
5353
|
+
await renderShell();
|
|
5354
|
+
});
|
|
5355
|
+
}
|
|
5356
|
+
|
|
5164
5357
|
for (const button of document.querySelectorAll("[data-locale-option]")) {
|
|
5165
5358
|
button.addEventListener("click", async () => {
|
|
5166
5359
|
state.pushError = "";
|
|
@@ -5322,12 +5515,16 @@ function bindShellInteractions() {
|
|
|
5322
5515
|
});
|
|
5323
5516
|
if (textarea) textarea.readOnly = true;
|
|
5324
5517
|
const instruction = normalizeClientText(new FormData(a2aTaskForm).get("instruction"));
|
|
5518
|
+
const executorRadio = a2aTaskForm.querySelector("input[name='executor']:checked");
|
|
5519
|
+
const executor = executorRadio ? executorRadio.value : "";
|
|
5325
5520
|
try {
|
|
5521
|
+
const decisionBody = { action: submittedAction, instruction };
|
|
5522
|
+
if (executor) decisionBody.executor = executor;
|
|
5326
5523
|
const res = await fetch(`/api/items/a2a-task/${encodeURIComponent(token)}/decision`, {
|
|
5327
5524
|
method: "POST",
|
|
5328
5525
|
headers: { "content-type": "application/json" },
|
|
5329
5526
|
credentials: "same-origin",
|
|
5330
|
-
body: JSON.stringify(
|
|
5527
|
+
body: JSON.stringify(decisionBody),
|
|
5331
5528
|
});
|
|
5332
5529
|
if (!res.ok) {
|
|
5333
5530
|
const errBody = await res.json().catch(() => ({}));
|
|
@@ -5482,7 +5679,8 @@ function bindShellInteractions() {
|
|
|
5482
5679
|
requestBody.append("image", attachment.file, attachment.name || attachment.file.name);
|
|
5483
5680
|
}
|
|
5484
5681
|
}
|
|
5485
|
-
|
|
5682
|
+
const replyKind = replyForm.dataset.replyKind || "completion";
|
|
5683
|
+
await apiPost(`/api/items/${encodeURIComponent(replyKind)}/${encodeURIComponent(token)}/reply`, requestBody);
|
|
5486
5684
|
setCompletionReplyDraft(token, {
|
|
5487
5685
|
text: "",
|
|
5488
5686
|
sentText: text,
|
|
@@ -5880,10 +6078,10 @@ function inboxSubtabForItemKind(kind, sourceSubtab = "") {
|
|
|
5880
6078
|
if (normalizeClientText(sourceSubtab || "") === "completed") {
|
|
5881
6079
|
return "completed";
|
|
5882
6080
|
}
|
|
5883
|
-
return kind === "completion" ? "completed" : "pending";
|
|
6081
|
+
return kind === "completion" || kind === "assistant_final" ? "completed" : "pending";
|
|
5884
6082
|
}
|
|
5885
6083
|
|
|
5886
|
-
function kindMeta(kind) {
|
|
6084
|
+
function kindMeta(kind, item) {
|
|
5887
6085
|
switch (kind) {
|
|
5888
6086
|
case "user_message":
|
|
5889
6087
|
return { label: L("common.userMessage"), tone: "neutral", icon: "user-message" };
|
|
@@ -5905,10 +6103,17 @@ function kindMeta(kind) {
|
|
|
5905
6103
|
case "file_event":
|
|
5906
6104
|
return { label: L("common.fileEvent"), tone: "neutral", icon: "file-event" };
|
|
5907
6105
|
case "moltbook_reply":
|
|
6106
|
+
return { label: L("common.moltbookReply"), tone: "neutral", icon: "moltbook-comment" };
|
|
5908
6107
|
case "moltbook_draft":
|
|
5909
|
-
return
|
|
6108
|
+
return item?.draftType === "reply"
|
|
6109
|
+
? { label: L("common.moltbookDraftReply"), tone: "neutral", icon: "moltbook-reply" }
|
|
6110
|
+
: { label: L("common.moltbookDraft"), tone: "neutral", icon: "moltbook-draft" };
|
|
5910
6111
|
case "thread_share":
|
|
5911
6112
|
return { label: L("common.threadShare"), tone: "neutral", icon: "link" };
|
|
6113
|
+
case "a2a_task":
|
|
6114
|
+
return { label: L("common.a2aTaskRequest"), tone: "neutral", icon: "item" };
|
|
6115
|
+
case "a2a_task_result":
|
|
6116
|
+
return { label: L("common.a2aTaskResult"), tone: "completion", icon: "completion-item" };
|
|
5912
6117
|
default:
|
|
5913
6118
|
return { label: L("common.item"), tone: "neutral", icon: "item" };
|
|
5914
6119
|
}
|
|
@@ -6263,6 +6468,8 @@ function renderIcon(name) {
|
|
|
6263
6468
|
return `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="m9.5 12.5 5.9-5.9a3 3 0 1 1 4.2 4.2l-7.7 7.7a5 5 0 1 1-7.1-7.1l8.1-8.1"/></svg>`;
|
|
6264
6469
|
case "moltbook-draft":
|
|
6265
6470
|
return `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M15.2 3.8 20.2 8.8 8.5 20.5 3.5 20.5 3.5 15.5Z"/><path d="M12.5 6.5l5 5"/></svg>`;
|
|
6471
|
+
case "moltbook-reply":
|
|
6472
|
+
return `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M9 4 4 9l5 5"/><path d="M4 9h11a4 4 0 0 1 4 4v3"/></svg>`;
|
|
6266
6473
|
case "moltbook-comment":
|
|
6267
6474
|
return `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M4.5 5.5h15a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H11l-4 3.5v-3.5H4.5a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2Z"/><path d="M8 10h8"/><path d="M8 13h5"/></svg>`;
|
|
6268
6475
|
case "filter":
|