bosun 0.28.2 → 0.28.4

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.
@@ -5,43 +5,29 @@
5
5
  display: flex;
6
6
  align-items: center;
7
7
  justify-content: space-between;
8
- height: var(--header-height);
8
+ height: calc(44px + var(--content-safe-top));
9
9
  padding-top: var(--content-safe-top);
10
- padding-left: calc(18px + var(--safe-left));
11
- padding-right: calc(18px + var(--safe-right));
12
- background: var(--glass-bg);
10
+ padding-left: calc(16px + var(--safe-left));
11
+ padding-right: calc(16px + var(--safe-right));
12
+ background: var(--bg-primary);
13
13
  border-bottom: 1px solid var(--border);
14
- box-shadow: var(--shadow-sm);
15
- backdrop-filter: var(--glass-blur);
16
- -webkit-backdrop-filter: var(--glass-blur);
17
14
  flex-shrink: 0;
18
15
  z-index: 10;
19
16
  position: relative;
17
+ min-width: 0;
20
18
  }
21
19
 
22
20
  .app-header::after {
23
- content: "";
24
- position: absolute;
25
- bottom: 0;
26
- left: 0;
27
- right: 0;
28
- height: 1px;
29
- background: linear-gradient(
30
- 90deg,
31
- transparent 0%,
32
- rgba(59, 130, 246, 0.4) 30%,
33
- rgba(139, 92, 246, 0.35) 60%,
34
- transparent 100%
35
- );
36
- pointer-events: none;
21
+ display: none;
37
22
  }
38
23
 
39
24
  .app-header-left {
40
25
  display: flex;
41
26
  align-items: center;
42
- gap: 12px;
27
+ gap: 8px;
43
28
  min-width: 0;
44
29
  flex: 1;
30
+ overflow: hidden;
45
31
  }
46
32
 
47
33
  .app-header-brand {
@@ -199,10 +185,7 @@
199
185
  overflow-y: auto;
200
186
  overflow-x: hidden;
201
187
  scrollbar-gutter: stable;
202
- padding-top: 16px;
203
- padding-right: calc(16px + var(--safe-right));
204
- padding-bottom: calc(var(--nav-height, 60px) + var(--safe-bottom, 0px) + 24px);
205
- padding-left: calc(16px + var(--safe-left));
188
+ padding: 12px calc(12px + var(--safe-right)) calc(var(--nav-height, 56px) + var(--safe-bottom, 0px) + 16px) calc(12px + var(--safe-left));
206
189
  -webkit-overflow-scrolling: touch;
207
190
  scroll-behavior: smooth;
208
191
  touch-action: pan-y;
@@ -246,33 +229,31 @@
246
229
  to { opacity: 1; transform: translateY(0); }
247
230
  }
248
231
 
249
- /* ─── Bottom Navigation — Floating Pill ─── */
232
+ /* ─── Bottom Navigation — Clean pill bar ─── */
250
233
  .bottom-nav {
251
234
  position: fixed;
252
- bottom: calc(10px + var(--safe-bottom));
253
- left: calc(16px + var(--safe-left));
254
- right: calc(16px + var(--safe-right));
235
+ bottom: calc(8px + var(--safe-bottom));
236
+ left: calc(12px + var(--safe-left));
237
+ right: calc(12px + var(--safe-right));
255
238
  height: var(--nav-height);
256
- background: var(--glass-bg);
257
- border: 1px solid var(--glass-border);
239
+ background: var(--bg-primary);
240
+ border: 1px solid var(--border);
258
241
  border-radius: var(--radius-xl);
259
242
  display: flex;
260
243
  align-items: center;
261
244
  justify-content: space-around;
262
245
  z-index: 500;
263
- box-shadow: var(--shadow-md);
264
- backdrop-filter: var(--glass-blur);
265
- -webkit-backdrop-filter: var(--glass-blur);
266
- animation: navSlideUp 0.35s cubic-bezier(0.34, 1.56, 0.64, 1) 0.2s both;
246
+ box-shadow: 0 4px 20px rgba(0,0,0,0.25);
247
+ animation: navSlideUp 0.3s cubic-bezier(0.25, 1, 0.5, 1) 0.15s both;
267
248
  padding-bottom: 0;
268
249
  pointer-events: auto;
269
250
  }
270
251
 
271
252
  .bottom-nav.compact {
272
- height: calc(var(--nav-height) - 8px);
273
- padding: 4px 8px;
253
+ height: calc(var(--nav-height) - 4px);
254
+ padding: 2px 6px;
274
255
  justify-content: space-between;
275
- gap: 4px;
256
+ gap: 2px;
276
257
  }
277
258
 
278
259
  @keyframes navSlideUp {
@@ -655,6 +636,10 @@
655
636
  }
656
637
 
657
638
  @media (min-width: 1200px) {
639
+ :root {
640
+ --sidebar-width: 220px;
641
+ }
642
+
658
643
  body {
659
644
  overflow: hidden;
660
645
  }
@@ -691,9 +676,10 @@
691
676
  background: var(--bg-secondary);
692
677
  border: 1px solid var(--border);
693
678
  border-radius: var(--radius-lg);
694
- padding: 16px 12px;
695
- gap: 16px;
679
+ padding: 18px 16px;
680
+ gap: 14px;
696
681
  box-shadow: var(--shadow-sm);
682
+ min-width: 0;
697
683
  }
698
684
 
699
685
  .session-rail {
@@ -738,9 +724,7 @@
738
724
  margin-bottom: var(--space-md);
739
725
  position: sticky;
740
726
  top: 0;
741
- background: var(--glass-bg);
742
- backdrop-filter: var(--glass-blur);
743
- -webkit-backdrop-filter: var(--glass-blur);
727
+ background: var(--bg-primary);
744
728
  z-index: 5;
745
729
  }
746
730
 
@@ -809,9 +793,7 @@
809
793
  .drawer-overlay {
810
794
  position: fixed;
811
795
  inset: 0;
812
- background: rgba(0, 0, 0, 0.45);
813
- backdrop-filter: blur(4px);
814
- -webkit-backdrop-filter: blur(4px);
796
+ background: rgba(0, 0, 0, 0.5);
815
797
  z-index: 900;
816
798
  animation: fadeIn 0.18s ease-out;
817
799
  }
@@ -889,9 +871,7 @@
889
871
  gap: 8px;
890
872
  padding: 6px 16px;
891
873
  align-items: center;
892
- background: var(--glass-bg);
893
- backdrop-filter: var(--glass-blur);
894
- -webkit-backdrop-filter: var(--glass-blur);
874
+ background: var(--bg-primary);
895
875
  border-bottom: 1px solid var(--border);
896
876
  }
897
877
 
@@ -922,11 +902,12 @@
922
902
  }
923
903
 
924
904
  /* ─── Sidebar styling ─── */
925
- .sidebar-brand {
926
- display: flex;
927
- align-items: center;
928
- gap: 10px;
929
- }
905
+ .sidebar-brand {
906
+ display: flex;
907
+ align-items: center;
908
+ gap: 10px;
909
+ min-width: 0;
910
+ }
930
911
 
931
912
  .sidebar-logo {
932
913
  width: 40px;
@@ -946,71 +927,70 @@
946
927
  height: 20px;
947
928
  }
948
929
 
949
- .sidebar-title {
950
- font-size: 14px;
951
- font-weight: 600;
952
- color: var(--text-bright);
953
- }
930
+ .sidebar-title {
931
+ font-size: 15px;
932
+ font-weight: 600;
933
+ color: var(--text-bright);
934
+ white-space: nowrap;
935
+ overflow: hidden;
936
+ text-overflow: ellipsis;
937
+ }
954
938
 
955
939
  .sidebar-subtitle {
956
940
  font-size: 11px;
957
941
  color: var(--text-secondary);
958
942
  }
959
943
 
960
- .sidebar-actions {
961
- display: flex;
962
- flex-direction: column;
963
- gap: 8px;
964
- }
965
-
966
- .sidebar-nav {
967
- display: flex;
968
- flex-direction: column;
969
- gap: 6px;
970
- flex: 1;
971
- }
972
-
973
- .sidebar-nav-item {
974
- display: flex;
975
- flex-direction: column;
976
- align-items: center;
977
- justify-content: center;
978
- gap: 4px;
979
- padding: 10px 6px;
980
- border-radius: 14px;
981
- background: transparent;
982
- border: none;
983
- color: var(--text-secondary);
984
- font-size: 10px;
985
- font-weight: 600;
986
- cursor: pointer;
987
- transition: background var(--transition-fast), color var(--transition-fast), transform var(--transition-fast);
988
- }
989
-
990
- .sidebar-nav-item svg {
991
- width: 20px;
992
- height: 20px;
993
- }
944
+ .sidebar-actions {
945
+ display: flex;
946
+ flex-direction: column;
947
+ gap: 8px;
948
+ }
994
949
 
995
- .sidebar-nav-item span {
996
- font-size: 10px;
997
- letter-spacing: 0.02em;
998
- }
950
+ .sidebar-nav {
951
+ display: flex;
952
+ flex-direction: column;
953
+ gap: 6px;
954
+ flex: 1;
955
+ min-width: 0;
956
+ }
999
957
 
1000
- @media (min-width: 1200px) {
1001
958
  .sidebar-nav-item {
959
+ display: flex;
1002
960
  flex-direction: row;
961
+ align-items: center;
1003
962
  justify-content: flex-start;
1004
- padding: 10px 12px;
1005
963
  gap: 10px;
964
+ padding: 10px 12px;
965
+ border-radius: 12px;
966
+ background: transparent;
967
+ border: none;
968
+ color: var(--text-secondary);
1006
969
  font-size: 12px;
970
+ font-weight: 600;
971
+ cursor: pointer;
972
+ transition: background var(--transition-fast), color var(--transition-fast), transform var(--transition-fast);
973
+ width: 100%;
974
+ text-align: left;
975
+ min-width: 0;
976
+ overflow: hidden;
977
+ }
978
+
979
+ .sidebar-nav-item svg {
980
+ width: 18px;
981
+ height: 18px;
982
+ flex-shrink: 0;
1007
983
  }
1008
984
 
1009
985
  .sidebar-nav-item span {
1010
986
  font-size: 12px;
1011
987
  letter-spacing: 0.01em;
988
+ white-space: nowrap;
989
+ overflow: hidden;
990
+ text-overflow: ellipsis;
991
+ flex: 1;
992
+ min-width: 0;
1012
993
  }
1013
- }
1014
994
 
1015
995
  .sidebar-nav-item:hover {
1016
996
  background: var(--accent-subtle);
@@ -110,8 +110,8 @@
110
110
  .session-detail-tabs {
111
111
  display: flex;
112
112
  gap: 2px;
113
- background: var(--glass-bg);
114
- border: 1px solid var(--glass-border);
113
+ background: var(--bg-card);
114
+ border: 1px solid var(--border);
115
115
  border-radius: var(--radius-md);
116
116
  padding: 3px;
117
117
  margin-bottom: var(--space-md);
@@ -133,13 +133,12 @@
133
133
 
134
134
  .session-detail-tab:hover {
135
135
  color: var(--text-primary);
136
- background: var(--glass-highlight);
136
+ background: var(--bg-card-hover);
137
137
  }
138
138
 
139
139
  .session-detail-tab.active {
140
- background: var(--gradient-accent);
140
+ background: var(--accent);
141
141
  color: var(--accent-text);
142
- box-shadow: var(--shadow-glow-sm);
143
142
  }
144
143
 
145
144
  /* Back button (mobile) */
@@ -151,7 +150,7 @@
151
150
  display: flex;
152
151
  align-items: center;
153
152
  padding: 0;
154
- border-bottom: 1px solid var(--border, var(--glass-border));
153
+ border-bottom: 1px solid var(--border, var(--border));
155
154
  background: var(--bg-primary);
156
155
  flex-shrink: 0;
157
156
  }
@@ -507,7 +506,7 @@
507
506
 
508
507
  .chat-header {
509
508
  padding: 12px 16px;
510
- border-bottom: 1px solid var(--glass-border);
509
+ border-bottom: 1px solid var(--border);
511
510
  flex-shrink: 0;
512
511
  display: flex;
513
512
  align-items: center;
@@ -679,8 +678,8 @@
679
678
  }
680
679
 
681
680
  .chat-filter-chip {
682
- border: 1px solid var(--glass-border);
683
- background: var(--glass-bg);
681
+ border: 1px solid var(--border);
682
+ background: var(--bg-card);
684
683
  color: var(--text-secondary);
685
684
  font-size: 11px;
686
685
  padding: 4px 10px;
@@ -796,7 +795,7 @@
796
795
  justify-content: center;
797
796
  padding: var(--space-lg);
798
797
  gap: var(--space-sm);
799
- border: 1px dashed var(--glass-border);
798
+ border: 1px dashed var(--border);
800
799
  border-radius: var(--radius-md);
801
800
  background: rgba(8, 12, 20, 0.35);
802
801
  text-align: center;
@@ -962,7 +961,7 @@
962
961
 
963
962
  .md-blockquote {
964
963
  border-left: 3px solid var(--accent);
965
- background: var(--glass-bg);
964
+ background: var(--bg-card);
966
965
  padding: 6px 12px;
967
966
  margin: 4px 0;
968
967
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
@@ -1003,8 +1002,8 @@ ul.md-list li::before {
1003
1002
  }
1004
1003
 
1005
1004
  .md-inline-code {
1006
- background: var(--glass-bg);
1007
- border: 1px solid var(--glass-border);
1005
+ background: var(--bg-card);
1006
+ border: 1px solid var(--border);
1008
1007
  padding: 1px 6px;
1009
1008
  border-radius: 10px;
1010
1009
  font-family: "SF Mono", "Fira Code", "Consolas", monospace;
@@ -1013,7 +1012,7 @@ ul.md-list li::before {
1013
1012
 
1014
1013
  .md-hr {
1015
1014
  border: none;
1016
- border-top: 1px solid var(--glass-border);
1015
+ border-top: 1px solid var(--border);
1017
1016
  margin: 8px 0;
1018
1017
  }
1019
1018
 
@@ -1088,10 +1087,8 @@ ul.md-list li::before {
1088
1087
 
1089
1088
  /* ═══ Diff Viewer ═══ */
1090
1089
  .diff-viewer {
1091
- background: var(--glass-bg);
1092
- backdrop-filter: blur(12px);
1093
- -webkit-backdrop-filter: blur(12px);
1094
- border: 1px solid var(--glass-border);
1090
+ background: var(--bg-card);
1091
+ border: 1px solid var(--border);
1095
1092
  border-radius: var(--radius-lg);
1096
1093
  overflow: hidden;
1097
1094
  min-height: 200px;
@@ -1120,8 +1117,8 @@ ul.md-list li::before {
1120
1117
  font-size: 13px;
1121
1118
  font-weight: 500;
1122
1119
  color: var(--text-primary);
1123
- border-bottom: 1px solid var(--glass-border);
1124
- background: var(--glass-bg);
1120
+ border-bottom: 1px solid var(--border);
1121
+ background: var(--bg-card);
1125
1122
  }
1126
1123
 
1127
1124
  .diff-stat-add {
@@ -1256,8 +1253,8 @@ ul.md-list li::before {
1256
1253
  right: 0;
1257
1254
  max-height: 240px;
1258
1255
  overflow-y: auto;
1259
- background: var(--bg-card, var(--glass-bg));
1260
- border: 1px solid var(--border, var(--glass-border));
1256
+ background: var(--bg-card, var(--bg-card));
1257
+ border: 1px solid var(--border, var(--border));
1261
1258
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
1262
1259
  box-shadow: var(--shadow-lg, 0 4px 24px rgba(0,0,0,.35));
1263
1260
  z-index: 50;
@@ -1307,10 +1304,8 @@ ul.md-list li::before {
1307
1304
  padding: 32px;
1308
1305
  text-align: center;
1309
1306
  gap: 16px;
1310
- background: var(--glass-bg);
1311
- backdrop-filter: var(--glass-blur);
1312
- -webkit-backdrop-filter: var(--glass-blur);
1313
- border: 1px solid var(--glass-border);
1307
+ background: var(--bg-card);
1308
+ border: 1px solid var(--border);
1314
1309
  border-radius: var(--radius-lg);
1315
1310
  }
1316
1311
 
@@ -1350,8 +1345,8 @@ ul.md-list li::before {
1350
1345
  .chat-input-area {
1351
1346
  position: relative;
1352
1347
  padding: 16px 16px;
1353
- border-top: 1px solid var(--border, var(--glass-border));
1354
- background: var(--bg-surface, var(--glass-bg));
1348
+ border-top: 1px solid var(--border, var(--border));
1349
+ background: var(--bg-surface, var(--bg-card));
1355
1350
  flex-shrink: 0;
1356
1351
  }
1357
1352
 
@@ -1408,8 +1403,8 @@ ul.md-list li::before {
1408
1403
  display: flex;
1409
1404
  align-items: flex-end;
1410
1405
  gap: 8px;
1411
- background: var(--bg-card, var(--glass-bg));
1412
- border: 1px solid var(--border, var(--glass-border));
1406
+ background: var(--bg-card, var(--bg-card));
1407
+ border: 1px solid var(--border, var(--border));
1413
1408
  border-radius: 24px;
1414
1409
  padding: 8px 8px 8px 16px;
1415
1410
  transition: border-color 0.15s, box-shadow 0.15s;
@@ -1481,7 +1476,7 @@ ul.md-list li::before {
1481
1476
 
1482
1477
  /* ═══ Session Rename ═══ */
1483
1478
  .session-item-rename {
1484
- background: var(--bg-input, var(--glass-bg));
1479
+ background: var(--bg-input, var(--bg-card));
1485
1480
  border: 1px solid var(--accent, var(--color-primary, #3b82f6));
1486
1481
  border-radius: var(--radius-sm);
1487
1482
  padding: 2px 6px;
@@ -1572,7 +1567,7 @@ ul.md-list li::before {
1572
1567
  .session-item-wrapper .session-item {
1573
1568
  position: relative;
1574
1569
  z-index: 1;
1575
- background: var(--bg-surface, var(--glass-bg));
1570
+ background: var(--bg-surface, var(--bg-card));
1576
1571
  touch-action: pan-y;
1577
1572
  user-select: none;
1578
1573
  }
@@ -87,15 +87,15 @@
87
87
  --accent-danger: var(--color-error);
88
88
 
89
89
  /* Layout */
90
- --header-height: calc(60px + var(--content-safe-top));
91
- --nav-height: 66px;
92
- --sidebar-width: 88px;
93
- --rail-width: 320px;
94
- --inspector-width: 320px;
90
+ --header-height: calc(44px + var(--content-safe-top));
91
+ --nav-height: 56px;
92
+ --sidebar-width: 72px;
93
+ --rail-width: 300px;
94
+ --inspector-width: 300px;
95
95
  --content-max: 1200px;
96
- --shell-gap: 16px;
97
- --radius-xs: 4px;
98
- --radius-sm: 8px;
96
+ --shell-gap: 0px;
97
+ --radius-xs: 6px;
98
+ --radius-sm: 10px;
99
99
  --radius-md: 14px;
100
100
  --radius-lg: 18px;
101
101
  --radius-xl: 24px;
@@ -51,9 +51,9 @@
51
51
  .ws-switcher-dropdown {
52
52
  position: absolute;
53
53
  top: calc(100% + 4px);
54
- left: 0;
54
+ right: 0;
55
55
  min-width: 260px;
56
- max-width: 340px;
56
+ max-width: min(340px, calc(100vw - 32px));
57
57
  max-height: 400px;
58
58
  overflow-y: auto;
59
59
  background: var(--bg-primary, #1f1e1c);
@@ -195,8 +195,6 @@
195
195
  align-items: center;
196
196
  justify-content: center;
197
197
  background: rgba(0, 0, 0, 0.65);
198
- backdrop-filter: blur(4px);
199
- -webkit-backdrop-filter: blur(4px);
200
198
  animation: wsOverlayIn 0.2s ease-out;
201
199
  }
202
200
 
@@ -64,9 +64,6 @@ export function ControlTab() {
64
64
  const [commandInput, setCommandInput] = useState("");
65
65
  const [startTaskId, setStartTaskId] = useState("");
66
66
  const [retryTaskId, setRetryTaskId] = useState("");
67
- const [retryReason, setRetryReason] = useState("");
68
- const [askInput, setAskInput] = useState("");
69
- const [steerInput, setSteerInput] = useState("");
70
67
  const [quickCmdInput, setQuickCmdInput] = useState("");
71
68
  const [quickCmdPrefix, setQuickCmdPrefix] = useState("shell");
72
69
  const [quickCmdFeedback, setQuickCmdFeedback] = useState("");
@@ -83,6 +80,8 @@ export function ControlTab() {
83
80
  const [tasksLoading, setTasksLoading] = useState(false);
84
81
  const [startTaskError, setStartTaskError] = useState("");
85
82
  const [retryTaskError, setRetryTaskError] = useState("");
83
+ const [planFocus, setPlanFocus] = useState(""); // chip selection — no typing needed
84
+ const [planCount, setPlanCount] = useState("5");
86
85
  const startTaskIdRef = useRef("");
87
86
  const retryTaskIdRef = useRef("");
88
87
 
@@ -502,19 +501,15 @@ export function ControlTab() {
502
501
  try {
503
502
  await apiFetch("/api/tasks/retry", {
504
503
  method: "POST",
505
- body: JSON.stringify({
506
- taskId,
507
- retryReason: retryReason.trim() || undefined,
508
- }),
504
+ body: JSON.stringify({ taskId }),
509
505
  });
510
506
  showToast("Task retried", "success");
511
- setRetryReason("");
512
507
  refreshTaskOptions();
513
508
  scheduleRefresh(150);
514
509
  } catch {
515
510
  /* toast via apiFetch */
516
511
  }
517
- }, [retryTaskId, retryReason, refreshTaskOptions]);
512
+ }, [retryTaskId, refreshTaskOptions]);
518
513
 
519
514
  return html`
520
515
  ${!executor && !config && html`<${Card} title="Loading…"><${SkeletonCard} /><//>`}
@@ -707,58 +702,6 @@ export function ControlTab() {
707
702
  <//>
708
703
  <//>
709
704
 
710
- <${Card} className="agent-control-card">
711
- <${Collapsible} title="Agent Control" defaultOpen=${!isCompact}>
712
- <div class="meta-text mb-sm">Ask or steer the active agent.</div>
713
- <div class="agent-control-grid">
714
- <div>
715
- <div class="form-label">Ask agent</div>
716
- <textarea
717
- class="input mb-sm"
718
- rows="2"
719
- placeholder="Ask the agent…"
720
- value=${askInput}
721
- onInput=${(e) => setAskInput(e.target.value)}
722
- ></textarea>
723
- <div class="btn-row">
724
- <button
725
- class="btn btn-primary btn-sm"
726
- onClick=${() => {
727
- if (askInput.trim()) {
728
- sendCmd(`/ask ${askInput.trim()}`);
729
- setAskInput("");
730
- }
731
- }}
732
- >
733
- 💬 Ask
734
- </button>
735
- </div>
736
- </div>
737
- <div>
738
- <div class="form-label">Steer prompt</div>
739
- <div class="input-row mb-sm">
740
- <input
741
- class="input"
742
- placeholder="Steer prompt (focus on…)"
743
- value=${steerInput}
744
- onInput=${(e) => setSteerInput(e.target.value)}
745
- />
746
- <button
747
- class="btn btn-secondary btn-sm"
748
- onClick=${() => {
749
- if (steerInput.trim()) {
750
- sendCmd(`/steer ${steerInput.trim()}`);
751
- setSteerInput("");
752
- }
753
- }}
754
- >
755
- 🎯 Steer
756
- </button>
757
- </div>
758
- </div>
759
- </div>
760
- <//>
761
- <//>
762
705
  </div>
763
706
 
764
707
  <div class="control-side">
@@ -813,6 +756,7 @@ export function ControlTab() {
813
756
  <div class="field-group">
814
757
  <div class="form-label">Retry task</div>
815
758
  <div class="input-row">
759
+ <div class="input-row">
816
760
  <select
817
761
  class=${retryTaskError ? "input input-error" : "input"}
818
762
  value=${retryTaskId}
@@ -831,27 +775,52 @@ export function ControlTab() {
831
775
  `,
832
776
  )}
833
777
  </select>
834
- <input
835
- class="input"
836
- placeholder="Retry reason (optional)"
837
- value=${retryReason}
838
- onInput=${(e) => setRetryReason(e.target.value)}
839
- />
840
778
  <button
841
779
  class="btn btn-secondary btn-sm"
842
780
  disabled=${!retryTaskId}
843
781
  onClick=${handleRetryTask}
844
782
  >
845
- Retry Task
846
- </button>
847
- <button class="btn btn-ghost btn-sm" onClick=${() => sendCmd("/plan")}>
848
- 📋 Plan
783
+ Retry
849
784
  </button>
850
785
  </div>
851
786
  ${retryTaskError
852
787
  ? html`<div class="form-hint error">${retryTaskError}</div>`
853
788
  : null}
854
789
  </div>
790
+
791
+ <div class="field-group">
792
+ <div class="form-label">Task Planner</div>
793
+ <div class="plan-chips">
794
+ ${["fix bugs", "add tests", "security", "refactor", "add docs", "performance"].map((chip) => html`
795
+ <button
796
+ key=${chip}
797
+ class=${`chip ${planFocus === chip ? "active" : ""}`}
798
+ onClick=${() => { haptic("light"); setPlanFocus(planFocus === chip ? "" : chip); }}
799
+ >${chip}</button>
800
+ `)}
801
+ </div>
802
+ <div class="input-row mt-sm">
803
+ <span class="form-hint" style="flex:1;margin:0">Generate
804
+ <input
805
+ type="number"
806
+ class="input plan-count-input"
807
+ min="1" max="50"
808
+ value=${planCount}
809
+ onInput=${(e) => setPlanCount(e.target.value)}
810
+ />
811
+ tasks${planFocus ? ` · ${planFocus}` : ""}
812
+ </span>
813
+ <button
814
+ class="btn btn-ghost btn-sm"
815
+ onClick=${() => {
816
+ const n = Math.max(1, parseInt(planCount, 10) || 5);
817
+ sendCmd(planFocus ? `/plan ${n} ${planFocus}` : `/plan ${n}`);
818
+ }}
819
+ >
820
+ 📋 Plan
821
+ </button>
822
+ </div>
823
+ </div>
855
824
  <//>
856
825
  <//>
857
826