taskplane 0.6.1 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -5
- package/dashboard/public/app.js +227 -0
- package/dashboard/public/index.html +19 -0
- package/dashboard/public/style.css +319 -0
- package/dashboard/server.cjs +219 -1
- package/extensions/taskplane/config-loader.ts +7 -1
- package/extensions/taskplane/config-schema.ts +19 -2
- package/extensions/taskplane/config.ts +23 -1
- package/extensions/taskplane/engine.ts +913 -46
- package/extensions/taskplane/execution.ts +1 -0
- package/extensions/taskplane/extension.ts +975 -54
- package/extensions/taskplane/formatting.ts +713 -712
- package/extensions/taskplane/index.ts +1 -0
- package/extensions/taskplane/merge.ts +236 -48
- package/extensions/taskplane/messages.ts +10 -0
- package/extensions/taskplane/persistence.ts +183 -3
- package/extensions/taskplane/resume.ts +243 -24
- package/extensions/taskplane/settings-tui.ts +10 -3
- package/extensions/taskplane/supervisor-primer.md +626 -0
- package/extensions/taskplane/supervisor.ts +3659 -0
- package/extensions/taskplane/types.ts +330 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -109,12 +109,13 @@ pi
|
|
|
109
109
|
Inside the pi session:
|
|
110
110
|
|
|
111
111
|
```
|
|
112
|
-
/orch
|
|
113
|
-
/orch all
|
|
114
|
-
/orch
|
|
112
|
+
/orch # Detect project state — guides onboarding or offers to start a batch
|
|
113
|
+
/orch-plan all # Preview waves, lanes, and dependencies
|
|
114
|
+
/orch all # Execute all pending tasks in parallel
|
|
115
|
+
/orch-status # Monitor batch progress
|
|
115
116
|
```
|
|
116
117
|
|
|
117
|
-
The default scaffold includes two independent example tasks, so `/orch all` gives you an immediate orchestrator + dashboard experience.
|
|
118
|
+
`/orch` with no arguments is the universal entry point — it detects your project state and activates the supervisor for guided interaction (onboarding, batch planning, health checks, or retrospective). The default scaffold includes two independent example tasks, so `/orch all` gives you an immediate orchestrator + dashboard experience.
|
|
118
119
|
|
|
119
120
|
### 4. Optional: run one task directly
|
|
120
121
|
|
|
@@ -148,7 +149,7 @@ Orchestrator lanes execute tasks through task-runner under the hood, so `/task`
|
|
|
148
149
|
| `/task-status` | Show current task progress |
|
|
149
150
|
| `/task-pause` | Pause after current worker iteration finishes |
|
|
150
151
|
| `/task-resume` | Resume a paused task |
|
|
151
|
-
| `/orch <areas\|paths\|all
|
|
152
|
+
| `/orch [<areas\|paths\|all>]` | No args: detect state & guide (onboarding, batch planning, etc.); with args: execute tasks via isolated worktrees |
|
|
152
153
|
| `/orch-plan <areas\|paths\|all>` | Preview execution plan without running |
|
|
153
154
|
| `/orch-status` | Show batch progress |
|
|
154
155
|
| `/orch-pause` | Pause batch after current tasks finish |
|
package/dashboard/public/app.js
CHANGED
|
@@ -722,6 +722,231 @@ function ensureContentPanels() {
|
|
|
722
722
|
}
|
|
723
723
|
}
|
|
724
724
|
|
|
725
|
+
// ─── Supervisor Panel ───────────────────────────────────────────────────────
|
|
726
|
+
|
|
727
|
+
const $supervisorPanel = $("supervisor-panel");
|
|
728
|
+
const $supervisorStatusBadge = $("supervisor-status-badge");
|
|
729
|
+
const $supervisorCollapseBtn = $("supervisor-collapse-btn");
|
|
730
|
+
const $supervisorPanelBody = $("supervisor-panel-body");
|
|
731
|
+
const $supervisorStatusSection = $("supervisor-status-section");
|
|
732
|
+
const $supervisorConversationSection = $("supervisor-conversation-section");
|
|
733
|
+
const $supervisorActionsSection = $("supervisor-actions-section");
|
|
734
|
+
const $supervisorSummarySection = $("supervisor-summary-section");
|
|
735
|
+
|
|
736
|
+
let supervisorCollapsed = false;
|
|
737
|
+
|
|
738
|
+
// Toggle collapse on header click
|
|
739
|
+
$("supervisor-panel-toggle").addEventListener("click", (e) => {
|
|
740
|
+
// Don't toggle when clicking the collapse button itself (it has its own handler)
|
|
741
|
+
if (e.target.id === "supervisor-collapse-btn") return;
|
|
742
|
+
toggleSupervisorPanel();
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
$supervisorCollapseBtn.addEventListener("click", toggleSupervisorPanel);
|
|
746
|
+
|
|
747
|
+
function toggleSupervisorPanel() {
|
|
748
|
+
supervisorCollapsed = !supervisorCollapsed;
|
|
749
|
+
$supervisorPanelBody.style.display = supervisorCollapsed ? "none" : "";
|
|
750
|
+
$supervisorCollapseBtn.textContent = supervisorCollapsed ? "▸" : "▾";
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
/** Determine supervisor status from lock data. */
|
|
754
|
+
function supervisorStatusInfo(lock) {
|
|
755
|
+
if (!lock) return { status: "inactive", label: "Inactive", cls: "supervisor-inactive" };
|
|
756
|
+
if (lock.stale) return { status: "stale", label: "Stale", cls: "supervisor-stale" };
|
|
757
|
+
return { status: "active", label: "Active", cls: "supervisor-active" };
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/** Format a timestamp for the supervisor timeline. */
|
|
761
|
+
function formatSupervisorTime(ts) {
|
|
762
|
+
if (!ts) return "";
|
|
763
|
+
const d = new Date(ts);
|
|
764
|
+
return d.toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", second: "2-digit" });
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
/** Render the supervisor status indicator section. */
|
|
768
|
+
function renderSupervisorStatus(supervisor) {
|
|
769
|
+
const lock = supervisor.lock;
|
|
770
|
+
const info = supervisorStatusInfo(lock);
|
|
771
|
+
|
|
772
|
+
// Update the header badge
|
|
773
|
+
$supervisorStatusBadge.textContent = info.label;
|
|
774
|
+
$supervisorStatusBadge.className = `supervisor-status-badge ${info.cls}`;
|
|
775
|
+
|
|
776
|
+
let html = '<div class="supervisor-status-row">';
|
|
777
|
+
html += `<span class="supervisor-status-dot ${info.cls}"></span>`;
|
|
778
|
+
html += `<span class="supervisor-status-label">${info.label}</span>`;
|
|
779
|
+
|
|
780
|
+
if (lock) {
|
|
781
|
+
if (lock.autonomy) {
|
|
782
|
+
html += `<span class="supervisor-autonomy-badge">${escapeHtml(lock.autonomy)}</span>`;
|
|
783
|
+
}
|
|
784
|
+
if (lock.heartbeat) {
|
|
785
|
+
html += `<span class="supervisor-heartbeat" title="Last heartbeat">♡ ${relativeTime(lock.heartbeat)}</span>`;
|
|
786
|
+
}
|
|
787
|
+
if (lock.sessionId) {
|
|
788
|
+
html += `<span class="supervisor-session-id" title="Session: ${escapeHtml(lock.sessionId)}">${escapeHtml(lock.sessionId)}</span>`;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
html += '</div>';
|
|
793
|
+
$supervisorStatusSection.innerHTML = html;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
/** Render the conversation history section. */
|
|
797
|
+
function renderSupervisorConversation(supervisor) {
|
|
798
|
+
const conversation = supervisor.conversation || [];
|
|
799
|
+
|
|
800
|
+
if (conversation.length === 0) {
|
|
801
|
+
$supervisorConversationSection.innerHTML = '';
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
let html = '<div class="supervisor-subsection-title">Conversation</div>';
|
|
806
|
+
html += '<div class="supervisor-conversation-list">';
|
|
807
|
+
|
|
808
|
+
for (const entry of conversation) {
|
|
809
|
+
const time = formatSupervisorTime(entry.ts || entry.timestamp);
|
|
810
|
+
const role = entry.role || "unknown";
|
|
811
|
+
const content = entry.content || entry.message || "";
|
|
812
|
+
const roleCls = role === "operator" ? "conv-role-operator" : "conv-role-supervisor";
|
|
813
|
+
const roleLabel = role === "operator" ? "Operator" : "Supervisor";
|
|
814
|
+
|
|
815
|
+
html += `<div class="supervisor-conv-entry ${roleCls}">`;
|
|
816
|
+
html += ` <div class="supervisor-conv-header">`;
|
|
817
|
+
html += ` <span class="supervisor-conv-role">${roleLabel}</span>`;
|
|
818
|
+
if (time) html += `<span class="supervisor-conv-time">${time}</span>`;
|
|
819
|
+
html += ` </div>`;
|
|
820
|
+
html += ` <div class="supervisor-conv-content">${escapeHtml(content)}</div>`;
|
|
821
|
+
html += `</div>`;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
html += '</div>';
|
|
825
|
+
$supervisorConversationSection.innerHTML = html;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
/** Merge supervisor actions and Tier 0 recovery events into a unified timeline.
|
|
829
|
+
* Actions from actions.jsonl and recovery events from events.jsonl are combined
|
|
830
|
+
* and sorted chronologically (per R002: show both Tier 0 and supervisor actions).
|
|
831
|
+
*/
|
|
832
|
+
function buildRecoveryTimeline(supervisor) {
|
|
833
|
+
const actions = (supervisor.actions || []).map(a => ({
|
|
834
|
+
ts: a.ts || a.timestamp || 0,
|
|
835
|
+
tier: a.tier,
|
|
836
|
+
type: a.type || a.action || "unknown",
|
|
837
|
+
target: a.target || a.lane || a.taskId || "",
|
|
838
|
+
outcome: a.outcome || a.result || "",
|
|
839
|
+
reason: a.reason || "",
|
|
840
|
+
source: "action"
|
|
841
|
+
}));
|
|
842
|
+
|
|
843
|
+
// Include Tier 0 recovery events from events.jsonl
|
|
844
|
+
const events = (supervisor.events || [])
|
|
845
|
+
.filter(e => e.tier === 0 || e.type === "recovery" || e.type === "tier0_recovery")
|
|
846
|
+
.map(e => ({
|
|
847
|
+
ts: e.ts || e.timestamp || 0,
|
|
848
|
+
tier: e.tier != null ? e.tier : 0,
|
|
849
|
+
type: e.type || "event",
|
|
850
|
+
target: e.target || e.lane || e.taskId || "",
|
|
851
|
+
outcome: e.outcome || e.result || "",
|
|
852
|
+
reason: e.reason || e.message || "",
|
|
853
|
+
source: "event"
|
|
854
|
+
}));
|
|
855
|
+
|
|
856
|
+
const timeline = [...actions, ...events];
|
|
857
|
+
timeline.sort((a, b) => {
|
|
858
|
+
const tA = typeof a.ts === "string" ? new Date(a.ts).getTime() : a.ts;
|
|
859
|
+
const tB = typeof b.ts === "string" ? new Date(b.ts).getTime() : b.ts;
|
|
860
|
+
return tA - tB;
|
|
861
|
+
});
|
|
862
|
+
|
|
863
|
+
return timeline;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
/** Render the recovery action timeline section. */
|
|
867
|
+
function renderSupervisorActions(supervisor) {
|
|
868
|
+
const timeline = buildRecoveryTimeline(supervisor);
|
|
869
|
+
|
|
870
|
+
if (timeline.length === 0) {
|
|
871
|
+
$supervisorActionsSection.innerHTML = '';
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
let html = '<div class="supervisor-subsection-title">Recovery Actions</div>';
|
|
876
|
+
html += '<div class="supervisor-timeline">';
|
|
877
|
+
|
|
878
|
+
for (const entry of timeline) {
|
|
879
|
+
const time = formatSupervisorTime(entry.ts);
|
|
880
|
+
const tier = entry.tier != null ? `T${entry.tier}` : "";
|
|
881
|
+
const type = entry.type;
|
|
882
|
+
const target = entry.target;
|
|
883
|
+
const outcome = entry.outcome;
|
|
884
|
+
const reason = entry.reason;
|
|
885
|
+
|
|
886
|
+
const outcomeCls = outcome === "success" || outcome === "recovered"
|
|
887
|
+
? "action-success"
|
|
888
|
+
: outcome === "failed" || outcome === "error"
|
|
889
|
+
? "action-failed"
|
|
890
|
+
: "action-pending";
|
|
891
|
+
|
|
892
|
+
html += `<div class="supervisor-action-entry">`;
|
|
893
|
+
html += ` <div class="supervisor-action-left">`;
|
|
894
|
+
html += ` <span class="supervisor-action-time">${time}</span>`;
|
|
895
|
+
html += ` <span class="supervisor-action-dot ${outcomeCls}"></span>`;
|
|
896
|
+
html += ` </div>`;
|
|
897
|
+
html += ` <div class="supervisor-action-right">`;
|
|
898
|
+
html += ` <div class="supervisor-action-header">`;
|
|
899
|
+
if (tier) html += `<span class="supervisor-action-tier">${tier}</span>`;
|
|
900
|
+
html += ` <span class="supervisor-action-type">${escapeHtml(type)}</span>`;
|
|
901
|
+
if (target) html += `<span class="supervisor-action-target">${escapeHtml(target)}</span>`;
|
|
902
|
+
if (outcome) html += `<span class="supervisor-action-outcome ${outcomeCls}">${escapeHtml(outcome)}</span>`;
|
|
903
|
+
html += ` </div>`;
|
|
904
|
+
if (reason) {
|
|
905
|
+
html += `<div class="supervisor-action-reason">${escapeHtml(reason)}</div>`;
|
|
906
|
+
}
|
|
907
|
+
html += ` </div>`;
|
|
908
|
+
html += `</div>`;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
html += '</div>';
|
|
912
|
+
$supervisorActionsSection.innerHTML = html;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
/** Render the batch summary section (from summary.md). */
|
|
916
|
+
function renderSupervisorSummary(supervisor) {
|
|
917
|
+
const summary = supervisor.summary;
|
|
918
|
+
|
|
919
|
+
if (!summary) {
|
|
920
|
+
$supervisorSummarySection.innerHTML = '';
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
let html = '<div class="supervisor-subsection-title">Batch Summary</div>';
|
|
925
|
+
html += '<div class="supervisor-summary-content">';
|
|
926
|
+
// Render the summary markdown using the STATUS.md renderer (reuse)
|
|
927
|
+
const { html: renderedMd } = renderStatusMd(summary);
|
|
928
|
+
html += renderedMd;
|
|
929
|
+
html += '</div>';
|
|
930
|
+
$supervisorSummarySection.innerHTML = html;
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
/** Main supervisor panel render function. */
|
|
934
|
+
function renderSupervisor(data) {
|
|
935
|
+
const supervisor = data.supervisor;
|
|
936
|
+
|
|
937
|
+
if (!supervisor) {
|
|
938
|
+
$supervisorPanel.style.display = "none";
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
$supervisorPanel.style.display = "";
|
|
943
|
+
|
|
944
|
+
renderSupervisorStatus(supervisor);
|
|
945
|
+
renderSupervisorConversation(supervisor);
|
|
946
|
+
renderSupervisorActions(supervisor);
|
|
947
|
+
renderSupervisorSummary(supervisor);
|
|
948
|
+
}
|
|
949
|
+
|
|
725
950
|
// ─── Full Render ────────────────────────────────────────────────────────────
|
|
726
951
|
|
|
727
952
|
// ─── Current data (stored for conversation viewer) ──────────────────────────
|
|
@@ -738,6 +963,7 @@ function render(data) {
|
|
|
738
963
|
if (!batch) {
|
|
739
964
|
renderHeader(null);
|
|
740
965
|
renderSummary(null);
|
|
966
|
+
renderSupervisor(data);
|
|
741
967
|
// Refresh history list (batch may have just finished)
|
|
742
968
|
if (!noBatchRendered) loadHistoryList();
|
|
743
969
|
renderNoBatch();
|
|
@@ -763,6 +989,7 @@ function render(data) {
|
|
|
763
989
|
const repos = buildRepoSet(batch);
|
|
764
990
|
updateRepoFilter(repos);
|
|
765
991
|
|
|
992
|
+
renderSupervisor(data);
|
|
766
993
|
renderLanesTasks(batch, tmux);
|
|
767
994
|
renderMergeAgents(batch, tmux);
|
|
768
995
|
renderErrors(batch);
|
|
@@ -51,6 +51,25 @@
|
|
|
51
51
|
</div>
|
|
52
52
|
</div>
|
|
53
53
|
|
|
54
|
+
<!-- Supervisor Panel (hidden when no supervisor data) -->
|
|
55
|
+
<div class="panel supervisor-panel" id="supervisor-panel" style="display:none;">
|
|
56
|
+
<div class="panel-header supervisor-panel-header" id="supervisor-panel-toggle">
|
|
57
|
+
<span>Supervisor</span>
|
|
58
|
+
<span class="supervisor-status-badge" id="supervisor-status-badge"></span>
|
|
59
|
+
<button class="supervisor-collapse-btn" id="supervisor-collapse-btn" title="Toggle supervisor panel">▾</button>
|
|
60
|
+
</div>
|
|
61
|
+
<div class="panel-body supervisor-panel-body" id="supervisor-panel-body">
|
|
62
|
+
<!-- Status Section -->
|
|
63
|
+
<div class="supervisor-section" id="supervisor-status-section"></div>
|
|
64
|
+
<!-- Conversation Section -->
|
|
65
|
+
<div class="supervisor-section" id="supervisor-conversation-section"></div>
|
|
66
|
+
<!-- Actions Timeline Section -->
|
|
67
|
+
<div class="supervisor-section" id="supervisor-actions-section"></div>
|
|
68
|
+
<!-- Batch Summary Section -->
|
|
69
|
+
<div class="supervisor-section" id="supervisor-summary-section"></div>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
54
73
|
<!-- Lanes + Tasks (integrated) -->
|
|
55
74
|
<div class="panel" id="lanes-tasks-panel">
|
|
56
75
|
<div class="panel-header">Lanes & Tasks</div>
|
|
@@ -1038,6 +1038,325 @@ body {
|
|
|
1038
1038
|
border-bottom: none;
|
|
1039
1039
|
}
|
|
1040
1040
|
|
|
1041
|
+
/* ─── Supervisor Panel ──────────────────────────────────────────────────── */
|
|
1042
|
+
|
|
1043
|
+
.supervisor-panel {
|
|
1044
|
+
border-color: var(--border);
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
.supervisor-panel-header {
|
|
1048
|
+
display: flex;
|
|
1049
|
+
align-items: center;
|
|
1050
|
+
gap: 10px;
|
|
1051
|
+
cursor: pointer;
|
|
1052
|
+
user-select: none;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
.supervisor-panel-header:hover {
|
|
1056
|
+
background: var(--bg-surface-hover);
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
.supervisor-collapse-btn {
|
|
1060
|
+
margin-left: auto;
|
|
1061
|
+
background: none;
|
|
1062
|
+
border: none;
|
|
1063
|
+
color: var(--text-muted);
|
|
1064
|
+
font-size: 0.9rem;
|
|
1065
|
+
cursor: pointer;
|
|
1066
|
+
padding: 0 4px;
|
|
1067
|
+
line-height: 1;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
.supervisor-collapse-btn:hover {
|
|
1071
|
+
color: var(--text);
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
.supervisor-panel-body {
|
|
1075
|
+
padding: 0;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
.supervisor-section {
|
|
1079
|
+
padding: 0;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
.supervisor-section:empty {
|
|
1083
|
+
display: none;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
/* Supervisor status badge (in panel header) */
|
|
1087
|
+
.supervisor-status-badge {
|
|
1088
|
+
font-family: var(--font-mono);
|
|
1089
|
+
font-size: 0.7rem;
|
|
1090
|
+
font-weight: 600;
|
|
1091
|
+
padding: 2px 8px;
|
|
1092
|
+
border-radius: 10px;
|
|
1093
|
+
text-transform: uppercase;
|
|
1094
|
+
letter-spacing: 0.04em;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
.supervisor-status-badge.supervisor-active {
|
|
1098
|
+
background: rgba(63,185,80,0.15);
|
|
1099
|
+
color: var(--green);
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
.supervisor-status-badge.supervisor-stale {
|
|
1103
|
+
background: rgba(210,153,34,0.15);
|
|
1104
|
+
color: var(--yellow);
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
.supervisor-status-badge.supervisor-inactive {
|
|
1108
|
+
background: rgba(139,148,158,0.1);
|
|
1109
|
+
color: var(--text-muted);
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
/* Status row inside the panel */
|
|
1113
|
+
.supervisor-status-row {
|
|
1114
|
+
display: flex;
|
|
1115
|
+
align-items: center;
|
|
1116
|
+
gap: 10px;
|
|
1117
|
+
padding: 10px 14px;
|
|
1118
|
+
border-bottom: 1px solid var(--border-subtle);
|
|
1119
|
+
flex-wrap: wrap;
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
.supervisor-status-dot {
|
|
1123
|
+
width: 8px;
|
|
1124
|
+
height: 8px;
|
|
1125
|
+
border-radius: 50%;
|
|
1126
|
+
flex-shrink: 0;
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
.supervisor-status-dot.supervisor-active {
|
|
1130
|
+
background: var(--green);
|
|
1131
|
+
animation: pulse 2s infinite;
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
.supervisor-status-dot.supervisor-stale {
|
|
1135
|
+
background: var(--yellow);
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
.supervisor-status-dot.supervisor-inactive {
|
|
1139
|
+
background: var(--text-faint);
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
.supervisor-status-label {
|
|
1143
|
+
font-weight: 600;
|
|
1144
|
+
font-size: 0.85rem;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
.supervisor-autonomy-badge {
|
|
1148
|
+
font-family: var(--font-mono);
|
|
1149
|
+
font-size: 0.7rem;
|
|
1150
|
+
font-weight: 500;
|
|
1151
|
+
padding: 1px 7px;
|
|
1152
|
+
border-radius: 8px;
|
|
1153
|
+
background: rgba(188,140,255,0.12);
|
|
1154
|
+
color: var(--magenta);
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
.supervisor-heartbeat {
|
|
1158
|
+
font-family: var(--font-mono);
|
|
1159
|
+
font-size: 0.75rem;
|
|
1160
|
+
color: var(--text-muted);
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
.supervisor-session-id {
|
|
1164
|
+
font-family: var(--font-mono);
|
|
1165
|
+
font-size: 0.72rem;
|
|
1166
|
+
color: var(--text-faint);
|
|
1167
|
+
overflow: hidden;
|
|
1168
|
+
text-overflow: ellipsis;
|
|
1169
|
+
max-width: 200px;
|
|
1170
|
+
white-space: nowrap;
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
/* Subsection titles */
|
|
1174
|
+
.supervisor-subsection-title {
|
|
1175
|
+
font-size: 0.72rem;
|
|
1176
|
+
font-weight: 600;
|
|
1177
|
+
text-transform: uppercase;
|
|
1178
|
+
letter-spacing: 0.05em;
|
|
1179
|
+
color: var(--text-faint);
|
|
1180
|
+
padding: 8px 14px 4px;
|
|
1181
|
+
border-top: 1px solid var(--border-subtle);
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
/* ── Conversation List ─────────────────────────────────────────────────── */
|
|
1185
|
+
|
|
1186
|
+
.supervisor-conversation-list {
|
|
1187
|
+
max-height: 250px;
|
|
1188
|
+
overflow-y: auto;
|
|
1189
|
+
padding: 4px 14px 8px;
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
.supervisor-conv-entry {
|
|
1193
|
+
padding: 6px 10px;
|
|
1194
|
+
margin-bottom: 4px;
|
|
1195
|
+
border-radius: var(--radius-sm);
|
|
1196
|
+
font-size: 0.82rem;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
.supervisor-conv-entry.conv-role-operator {
|
|
1200
|
+
background: rgba(88,166,255,0.06);
|
|
1201
|
+
border-left: 3px solid var(--accent-dim);
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
.supervisor-conv-entry.conv-role-supervisor {
|
|
1205
|
+
background: rgba(63,185,80,0.06);
|
|
1206
|
+
border-left: 3px solid var(--green-dim);
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
.supervisor-conv-header {
|
|
1210
|
+
display: flex;
|
|
1211
|
+
align-items: center;
|
|
1212
|
+
gap: 8px;
|
|
1213
|
+
margin-bottom: 2px;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
.supervisor-conv-role {
|
|
1217
|
+
font-weight: 600;
|
|
1218
|
+
font-size: 0.75rem;
|
|
1219
|
+
text-transform: uppercase;
|
|
1220
|
+
letter-spacing: 0.04em;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
.conv-role-operator .supervisor-conv-role { color: var(--accent); }
|
|
1224
|
+
.conv-role-supervisor .supervisor-conv-role { color: var(--green); }
|
|
1225
|
+
|
|
1226
|
+
.supervisor-conv-time {
|
|
1227
|
+
font-family: var(--font-mono);
|
|
1228
|
+
font-size: 0.68rem;
|
|
1229
|
+
color: var(--text-faint);
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
.supervisor-conv-content {
|
|
1233
|
+
color: var(--text);
|
|
1234
|
+
line-height: 1.5;
|
|
1235
|
+
white-space: pre-wrap;
|
|
1236
|
+
word-break: break-word;
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
/* ── Recovery Actions Timeline ─────────────────────────────────────────── */
|
|
1240
|
+
|
|
1241
|
+
.supervisor-timeline {
|
|
1242
|
+
max-height: 300px;
|
|
1243
|
+
overflow-y: auto;
|
|
1244
|
+
padding: 4px 14px 8px;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
.supervisor-action-entry {
|
|
1248
|
+
display: flex;
|
|
1249
|
+
gap: 10px;
|
|
1250
|
+
padding: 6px 0;
|
|
1251
|
+
border-bottom: 1px solid var(--border-subtle);
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
.supervisor-action-entry:last-child {
|
|
1255
|
+
border-bottom: none;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
.supervisor-action-left {
|
|
1259
|
+
display: flex;
|
|
1260
|
+
flex-direction: column;
|
|
1261
|
+
align-items: center;
|
|
1262
|
+
gap: 4px;
|
|
1263
|
+
min-width: 60px;
|
|
1264
|
+
flex-shrink: 0;
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
.supervisor-action-time {
|
|
1268
|
+
font-family: var(--font-mono);
|
|
1269
|
+
font-size: 0.68rem;
|
|
1270
|
+
color: var(--text-faint);
|
|
1271
|
+
white-space: nowrap;
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
.supervisor-action-dot {
|
|
1275
|
+
width: 8px;
|
|
1276
|
+
height: 8px;
|
|
1277
|
+
border-radius: 50%;
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
.supervisor-action-dot.action-success { background: var(--green); }
|
|
1281
|
+
.supervisor-action-dot.action-failed { background: var(--red); }
|
|
1282
|
+
.supervisor-action-dot.action-pending { background: var(--yellow); }
|
|
1283
|
+
|
|
1284
|
+
.supervisor-action-right {
|
|
1285
|
+
flex: 1;
|
|
1286
|
+
min-width: 0;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
.supervisor-action-header {
|
|
1290
|
+
display: flex;
|
|
1291
|
+
align-items: center;
|
|
1292
|
+
gap: 6px;
|
|
1293
|
+
flex-wrap: wrap;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
.supervisor-action-tier {
|
|
1297
|
+
font-family: var(--font-mono);
|
|
1298
|
+
font-size: 0.68rem;
|
|
1299
|
+
font-weight: 700;
|
|
1300
|
+
padding: 1px 5px;
|
|
1301
|
+
border-radius: 4px;
|
|
1302
|
+
background: rgba(188,140,255,0.12);
|
|
1303
|
+
color: var(--magenta);
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
.supervisor-action-type {
|
|
1307
|
+
font-weight: 600;
|
|
1308
|
+
font-size: 0.82rem;
|
|
1309
|
+
color: var(--text);
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
.supervisor-action-target {
|
|
1313
|
+
font-family: var(--font-mono);
|
|
1314
|
+
font-size: 0.75rem;
|
|
1315
|
+
color: var(--text-muted);
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
.supervisor-action-outcome {
|
|
1319
|
+
font-family: var(--font-mono);
|
|
1320
|
+
font-size: 0.7rem;
|
|
1321
|
+
font-weight: 600;
|
|
1322
|
+
padding: 1px 6px;
|
|
1323
|
+
border-radius: 8px;
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
.supervisor-action-outcome.action-success {
|
|
1327
|
+
background: rgba(63,185,80,0.15);
|
|
1328
|
+
color: var(--green);
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
.supervisor-action-outcome.action-failed {
|
|
1332
|
+
background: rgba(248,81,73,0.15);
|
|
1333
|
+
color: var(--red);
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
.supervisor-action-outcome.action-pending {
|
|
1337
|
+
background: rgba(210,153,34,0.15);
|
|
1338
|
+
color: var(--yellow);
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
.supervisor-action-reason {
|
|
1342
|
+
font-size: 0.78rem;
|
|
1343
|
+
color: var(--text-muted);
|
|
1344
|
+
margin-top: 2px;
|
|
1345
|
+
line-height: 1.4;
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
/* ── Batch Summary ─────────────────────────────────────────────────────── */
|
|
1349
|
+
|
|
1350
|
+
.supervisor-summary-content {
|
|
1351
|
+
padding: 0 14px 8px;
|
|
1352
|
+
max-height: 300px;
|
|
1353
|
+
overflow-y: auto;
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
.supervisor-summary-content .status-md-content {
|
|
1357
|
+
padding: 4px 0;
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1041
1360
|
/* ─── Scrollbar ────────────────────────────────────────────────────────── */
|
|
1042
1361
|
|
|
1043
1362
|
::-webkit-scrollbar { width: 6px; }
|