@co0ontty/wand 1.36.0 → 1.39.0

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.
@@ -112,9 +112,21 @@
112
112
  --ease-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55);
113
113
  }
114
114
 
115
- /* 尊重用户的减少动画偏好 */
115
+ /* 尊重用户的减少动画偏好。
116
+ 但 Android WebView 例外: Chromium 在 Android 上会把系统 Developer
117
+ Options 里的 "Animator duration scale" / "Transition animation scale"
118
+ (设为 0 = 关) 直接映射成 prefers-reduced-motion: reduce — 这俩开关其实
119
+ 是为 Android 原生 UI 转场设计的, 不少老用户为求"启动快"长期关着,
120
+ 省电模式也会强制关掉。结果就是 Wand APK 内所有入场动画 (queueBarEnter、
121
+ messageSlideUser 等) 被压成 0.01ms, 用户看不到"消息已加入排队"这种
122
+ 关键反馈, 跟浏览器版表现不一致。
123
+ html.is-wand-app 由 scripts.js 在 UA 含 WandApp/* 时挂到 <html> 上 ——
124
+ Wand APK 内自己定义动画策略, 不跟 Android 系统级开关绑死; 浏览器 /
125
+ 普通 PWA / 桌面端仍然完整尊重用户偏好 (排除 .is-wand-app 后规则不变)。 */
116
126
  @media (prefers-reduced-motion: reduce) {
117
- *, *::before, *::after {
127
+ html:not(.is-wand-app) *,
128
+ html:not(.is-wand-app) *::before,
129
+ html:not(.is-wand-app) *::after {
118
130
  animation-duration: 0.01ms !important;
119
131
  animation-iteration-count: 1 !important;
120
132
  transition-duration: 0.01ms !important;
@@ -1339,6 +1351,14 @@
1339
1351
  text-align: center;
1340
1352
  font-style: italic;
1341
1353
  }
1354
+ .sidebar-history-section-label {
1355
+ padding: 8px 10px 4px 10px;
1356
+ font-size: 0.6875rem;
1357
+ font-weight: 600;
1358
+ letter-spacing: 0.04em;
1359
+ text-transform: uppercase;
1360
+ opacity: 0.5;
1361
+ }
1342
1362
  .claude-history-directory-header {
1343
1363
  margin-top: 6px;
1344
1364
  cursor: pointer;
@@ -4380,7 +4400,7 @@
4380
4400
  的 WebView,会把 color-mix(...) 当作 invalid 整条扔掉,导致背景/边框消失。
4381
4401
  下面凡是 color-mix 的属性都先写一条 rgba()/纯色 fallback,再被 color-mix
4382
4402
  覆盖;旧浏览器看到 fallback、新浏览器自动用 color-mix。同一文件里下方
4383
- .chat-handoff-tag / .subagent-reply / .subagent-reply-cycle 等也是同思路。 */
4403
+ .chat-handoff-tag / .subagent-reply / .subagent-reply-toggle 等也是同思路。 */
4384
4404
  .chat-handoff {
4385
4405
  align-self: flex-start;
4386
4406
  margin: 4px 0 2px 4px;
@@ -4466,15 +4486,18 @@
4466
4486
  padding: 14px 16px;
4467
4487
  }
4468
4488
 
4489
+ /* 短内容(error)形态:图标 + body 并列。用 flex 而不是 inline-block + display:inline,
4490
+ 后者在 body 内含块级 markdown(段落 / 代码块)时会塌掉。 */
4491
+ .subagent-reply:not(.collapsible) {
4492
+ display: flex;
4493
+ align-items: flex-start;
4494
+ gap: 6px;
4495
+ }
4469
4496
  .subagent-reply-icon {
4470
- display: inline-block;
4497
+ flex: 0 0 auto;
4471
4498
  color: var(--danger, #e2574c);
4472
- margin-right: 6px;
4473
4499
  font-weight: 700;
4474
- }
4475
-
4476
- .subagent-reply-body {
4477
- display: inline;
4500
+ line-height: 1.55;
4478
4501
  }
4479
4502
 
4480
4503
  .subagent-reply pre,
@@ -4495,98 +4518,250 @@
4495
4518
  min-width: 0;
4496
4519
  }
4497
4520
 
4498
- /* ===== subagent 回复三态折叠 =====
4499
- preview(默认)→ 限高 ~5 + 渐隐 mask + 内部可滚
4500
- expanded 拉到一个比较大的上限,内部可滚
4501
- collapsed → 完全收起,只剩底部一条工具栏,按钮还能再点回来 */
4502
- .subagent-reply.collapsible {
4503
- position: relative;
4504
- padding-right: 14px;
4505
- padding-bottom: 28px;
4506
- }
4507
-
4508
- .subagent-reply-scroll {
4521
+ /* ===== subagent panel(整段输出统一折叠面板)=====
4522
+ 结构:header(handoff + 展开按钮)+ body(max-height 22em 滚动)+ footer(同款按钮)
4523
+ 状态:data-expanded="false" 预览 / "true" 展开(body 拉到 70vh 仍可滚)
4524
+ 色彩:跟随 --agent-color(外层 inline style 注入),同 agent 跨 turn 颜色稳定 */
4525
+ .subagent-panel {
4526
+ margin: 8px 0;
4527
+ border: 1px solid color-mix(in srgb, var(--agent-color, var(--accent)) 25%, transparent);
4528
+ border-left: 3px solid color-mix(in srgb, var(--agent-color, var(--accent)) 55%, transparent);
4529
+ border-radius: 10px;
4509
4530
  overflow: hidden;
4510
- transition: max-height 0.32s var(--ease-out-expo, cubic-bezier(0.16, 1, 0.3, 1));
4511
- min-width: 0;
4512
- max-width: 100%;
4531
+ background: color-mix(in srgb, var(--agent-color, var(--accent)) 3%, var(--bg-surface));
4532
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
4513
4533
  }
4514
- .subagent-reply-scroll > :first-child { margin-top: 0; }
4515
- .subagent-reply-scroll > :last-child { margin-bottom: 0; }
4516
4534
 
4517
- .subagent-reply.collapsible[data-collapse-mode="preview"] .subagent-reply-scroll {
4518
- max-height: 7.5em; /* ~5 行 */
4519
- overflow-y: auto;
4520
- -webkit-mask-image: linear-gradient(to bottom, #000 70%, transparent 100%);
4521
- mask-image: linear-gradient(to bottom, #000 70%, transparent 100%);
4535
+ .subagent-panel-header {
4536
+ display: flex;
4537
+ align-items: center;
4538
+ gap: 8px;
4539
+ padding: 8px 12px;
4540
+ background: color-mix(in srgb, var(--agent-color, var(--accent)) 10%, var(--bg-surface));
4541
+ border-bottom: 1px solid color-mix(in srgb, var(--agent-color, var(--accent)) 16%, transparent);
4542
+ cursor: pointer;
4543
+ user-select: none;
4544
+ font-size: 0.78rem;
4545
+ line-height: 1.35;
4546
+ transition: background 0.15s ease;
4547
+ }
4548
+ .subagent-panel-header:hover {
4549
+ background: color-mix(in srgb, var(--agent-color, var(--accent)) 14%, var(--bg-surface));
4550
+ }
4551
+ .subagent-panel-header:focus-visible {
4552
+ outline: 2px solid color-mix(in srgb, var(--agent-color, var(--accent)) 55%, transparent);
4553
+ outline-offset: -2px;
4522
4554
  }
4523
4555
 
4524
- .subagent-reply.collapsible[data-collapse-mode="expanded"] .subagent-reply-scroll {
4525
- max-height: 360px;
4526
- overflow-y: auto;
4556
+ .subagent-panel-avatar {
4557
+ flex: 0 0 auto;
4558
+ width: 22px;
4559
+ height: 22px;
4560
+ border-radius: 5px;
4561
+ overflow: hidden;
4562
+ background: color-mix(in srgb, var(--agent-color, var(--accent)) 18%, transparent);
4563
+ display: inline-flex;
4564
+ align-items: center;
4565
+ justify-content: center;
4566
+ }
4567
+ .subagent-panel-avatar svg,
4568
+ .subagent-panel-avatar img {
4569
+ width: 100%;
4570
+ height: 100%;
4571
+ display: block;
4527
4572
  }
4528
4573
 
4529
- .subagent-reply.collapsible[data-collapse-mode="collapsed"] {
4530
- padding-top: 6px;
4531
- padding-bottom: 26px;
4574
+ .subagent-panel-arrow {
4575
+ flex: 0 0 auto;
4576
+ color: color-mix(in srgb, var(--agent-color, var(--accent)) 65%, var(--text-primary));
4577
+ opacity: 0.8;
4578
+ font-weight: 600;
4532
4579
  }
4533
- .subagent-reply.collapsible[data-collapse-mode="collapsed"] .subagent-reply-scroll {
4534
- max-height: 0;
4580
+
4581
+ .subagent-panel-attribution {
4582
+ flex: 1 1 auto;
4583
+ min-width: 0;
4584
+ color: var(--text-primary);
4535
4585
  overflow: hidden;
4536
- margin: 0;
4586
+ text-overflow: ellipsis;
4587
+ white-space: nowrap;
4588
+ }
4589
+ .subagent-panel-name {
4590
+ color: color-mix(in srgb, var(--agent-color, var(--accent)) 88%, var(--text-primary));
4591
+ font-weight: 600;
4592
+ }
4593
+ .subagent-panel-tag {
4594
+ display: inline-block;
4595
+ margin: 0 6px;
4596
+ padding: 0 6px;
4597
+ font-size: 0.62rem;
4598
+ font-weight: 500;
4599
+ letter-spacing: 0.04em;
4600
+ color: var(--agent-color, var(--accent));
4601
+ background: color-mix(in srgb, var(--agent-color, var(--accent)) 12%, transparent);
4602
+ border: 1px solid color-mix(in srgb, var(--agent-color, var(--accent)) 30%, transparent);
4603
+ border-radius: 4px;
4604
+ vertical-align: 1px;
4605
+ line-height: 1.4;
4606
+ white-space: nowrap;
4607
+ /* 注意:不要加 text-transform: uppercase。之前用 lowercase "subagent" + uppercase 强转
4608
+ 出来 "SUBAGENT",结果中文 UI 里冒出来一个英文大写词跟用户配置语言(中文)对不上。
4609
+ 现在文案直接走 i18n(t("subagent.tag") = "子代理" / "Subagent"),无需大小写强制。 */
4610
+ }
4611
+ .subagent-panel-task-desc {
4612
+ color: var(--text-muted);
4613
+ font-weight: 400;
4537
4614
  }
4538
4615
 
4539
- /* 三态循环按钮:固定在气泡右下角,三种模式下都可见 */
4540
- .subagent-reply-cycle {
4541
- position: absolute;
4542
- right: 8px;
4543
- bottom: 6px;
4616
+ .subagent-panel-toggle {
4617
+ flex: 0 0 auto;
4544
4618
  display: inline-flex;
4545
4619
  align-items: center;
4546
- gap: 3px;
4547
- padding: 2px 8px;
4620
+ gap: 4px;
4621
+ padding: 3px 10px;
4548
4622
  font-size: 0.7rem;
4549
4623
  font-weight: 500;
4550
- line-height: 1.4;
4551
- color: var(--accent);
4552
- color: var(--agent-color, var(--accent));
4553
- background: rgba(255, 248, 240, 0.95);
4554
- background: color-mix(in srgb, var(--agent-color, var(--accent)) 8%, var(--bg-surface, #fff));
4555
- border: 1px solid rgba(197, 101, 61, 0.28);
4556
- border: 1px solid color-mix(in srgb, var(--agent-color, var(--accent)) 28%, transparent);
4624
+ line-height: 1.3;
4625
+ color: color-mix(in srgb, var(--agent-color, var(--accent)) 78%, var(--text-primary));
4626
+ background: color-mix(in srgb, var(--agent-color, var(--accent)) 8%, var(--bg-surface));
4627
+ border: 1px solid color-mix(in srgb, var(--agent-color, var(--accent)) 30%, transparent);
4557
4628
  border-radius: 999px;
4558
4629
  cursor: pointer;
4559
4630
  user-select: none;
4560
- transition: background 0.15s ease, transform 0.1s ease, border-color 0.15s ease;
4631
+ transition: background 0.15s ease, border-color 0.15s ease, transform 0.1s ease;
4561
4632
  }
4562
- .subagent-reply-cycle:hover {
4563
- background: rgba(248, 226, 210, 1);
4564
- background: color-mix(in srgb, var(--agent-color, var(--accent)) 16%, var(--bg-surface, #fff));
4565
- border-color: rgba(197, 101, 61, 0.45);
4633
+ .subagent-panel-toggle:hover {
4634
+ background: color-mix(in srgb, var(--agent-color, var(--accent)) 18%, var(--bg-surface));
4566
4635
  border-color: color-mix(in srgb, var(--agent-color, var(--accent)) 45%, transparent);
4567
4636
  }
4568
- .subagent-reply-cycle:active {
4637
+ .subagent-panel-toggle:active {
4569
4638
  transform: translateY(1px);
4570
4639
  }
4571
- .subagent-reply-cycle-icon {
4572
- font-size: 0.7rem;
4573
- line-height: 1;
4640
+ .subagent-panel-toggle-icon {
4641
+ transition: transform 0.2s var(--ease-out-expo, cubic-bezier(0.16, 1, 0.3, 1));
4642
+ }
4643
+ .subagent-panel[data-expanded="true"] .subagent-panel-toggle-icon {
4644
+ transform: rotate(180deg);
4574
4645
  }
4575
4646
 
4576
- /* 内部滚动条做小一点,别抢戏 */
4577
- .subagent-reply-scroll::-webkit-scrollbar {
4578
- width: 6px;
4579
- height: 6px;
4647
+ /* body:默认 max-height 22em(≈14 行),内部滚动;展开后拉到 70vh 仍内部可滚,
4648
+ 避免一个超长 subagent 把整页撑爆。展开过渡只动 max-height,body 内的卡片
4649
+ 不动,不会有抖动。 */
4650
+ .subagent-panel-body {
4651
+ padding: 10px 14px;
4652
+ overflow-y: auto;
4653
+ overflow-x: hidden;
4654
+ min-width: 0;
4655
+ max-width: 100%;
4656
+ transition: max-height 0.28s var(--ease-out-expo, cubic-bezier(0.16, 1, 0.3, 1));
4657
+ scrollbar-gutter: stable;
4580
4658
  }
4581
- .subagent-reply-scroll::-webkit-scrollbar-thumb {
4582
- background: rgba(197, 101, 61, 0.35);
4583
- background: color-mix(in srgb, var(--agent-color, var(--accent)) 35%, transparent);
4584
- border-radius: 3px;
4659
+ .subagent-panel[data-expanded="false"] .subagent-panel-body {
4660
+ max-height: 22em;
4661
+ }
4662
+ .subagent-panel[data-expanded="true"] .subagent-panel-body {
4663
+ max-height: 70vh;
4585
4664
  }
4586
- .subagent-reply-scroll::-webkit-scrollbar-track {
4665
+ .subagent-panel-body > :first-child { margin-top: 0; }
4666
+ .subagent-panel-body > :last-child { margin-bottom: 0; }
4667
+
4668
+ /* body 里的工具卡 / 文本:缩一点字号 + 减小 margin,让 22em 能装下更多内容 */
4669
+ .subagent-panel-body .tool-use-card,
4670
+ .subagent-panel-body .tool-group,
4671
+ .subagent-panel-body .inline-tool,
4672
+ .subagent-panel-body .inline-terminal,
4673
+ .subagent-panel-body .inline-diff {
4674
+ margin: 4px 0;
4675
+ }
4676
+ .subagent-panel-body .markdown-content {
4677
+ font-size: 0.875rem;
4678
+ }
4679
+
4680
+ /* body 滚动条:弱化但仍可见,对应 agent 色 */
4681
+ .subagent-panel-body::-webkit-scrollbar {
4682
+ width: 7px;
4683
+ height: 7px;
4684
+ }
4685
+ .subagent-panel-body::-webkit-scrollbar-thumb {
4686
+ background: color-mix(in srgb, var(--agent-color, var(--accent)) 32%, transparent);
4687
+ border-radius: 4px;
4688
+ }
4689
+ .subagent-panel-body::-webkit-scrollbar-thumb:hover {
4690
+ background: color-mix(in srgb, var(--agent-color, var(--accent)) 50%, transparent);
4691
+ }
4692
+ .subagent-panel-body::-webkit-scrollbar-track {
4587
4693
  background: transparent;
4588
4694
  }
4589
4695
 
4696
+ /* footer:跟 header 对称,永远可见在 panel 底部。滚到 body 最下时用户能就近点。
4697
+ hint 是个软提示"— 协作猫 —",告诉用户 panel 边界,避免与下一段父消息混淆。 */
4698
+ .subagent-panel-footer {
4699
+ display: flex;
4700
+ align-items: center;
4701
+ gap: 10px;
4702
+ padding: 6px 12px;
4703
+ background: color-mix(in srgb, var(--agent-color, var(--accent)) 6%, var(--bg-surface));
4704
+ border-top: 1px solid color-mix(in srgb, var(--agent-color, var(--accent)) 14%, transparent);
4705
+ font-size: 0.7rem;
4706
+ }
4707
+ .subagent-panel-footer-hint {
4708
+ flex: 1 1 auto;
4709
+ min-width: 0;
4710
+ color: var(--text-muted);
4711
+ opacity: 0.7;
4712
+ font-family: var(--font-mono);
4713
+ letter-spacing: 0.04em;
4714
+ overflow: hidden;
4715
+ text-overflow: ellipsis;
4716
+ white-space: nowrap;
4717
+ }
4718
+
4719
+ /* ===== panel 内最终回复的简化标记块(外层 panel 已经管折叠,这里只剩"任务完成"标记)===== */
4720
+ .subagent-reply.collapsible {
4721
+ padding: 0;
4722
+ overflow: hidden;
4723
+ }
4724
+ .subagent-reply.final {
4725
+ margin: 6px 0 0;
4726
+ padding: 10px 12px;
4727
+ border-radius: 8px;
4728
+ border-left: 3px solid color-mix(in srgb, var(--agent-color, var(--accent)) 60%, transparent);
4729
+ background: color-mix(in srgb, var(--agent-color, var(--accent)) 5%, var(--bg-surface));
4730
+ }
4731
+ .subagent-reply.final.error {
4732
+ border-left-color: var(--danger, #e2574c);
4733
+ background: color-mix(in srgb, var(--danger, #e2574c) 5%, var(--bg-surface));
4734
+ }
4735
+ .subagent-reply-marker {
4736
+ display: inline-flex;
4737
+ align-items: center;
4738
+ gap: 4px;
4739
+ margin-bottom: 4px;
4740
+ font-size: 0.68rem;
4741
+ font-weight: 600;
4742
+ letter-spacing: 0.04em;
4743
+ text-transform: uppercase;
4744
+ color: color-mix(in srgb, var(--agent-color, var(--accent)) 78%, var(--text-primary));
4745
+ }
4746
+ .subagent-reply-marker.error {
4747
+ color: var(--danger, #e2574c);
4748
+ }
4749
+ .subagent-reply-marker.pending {
4750
+ color: var(--text-muted);
4751
+ text-transform: none;
4752
+ letter-spacing: 0;
4753
+ font-weight: 500;
4754
+ }
4755
+ .subagent-reply-marker-icon {
4756
+ font-weight: 700;
4757
+ }
4758
+ .subagent-reply.final .subagent-reply-content > :first-child { margin-top: 0; }
4759
+ .subagent-reply.final .subagent-reply-content > :last-child { margin-bottom: 0; }
4760
+
4761
+ /* (旧的 .subagent-reply-header / .subagent-reply-toggle / .subagent-reply-body /
4762
+ .subagent-reply-fade / .subagent-reply-body-inline 系列已移除——现在外层
4763
+ .subagent-panel 接管整段折叠 + 滚动,内层最终回复退化为简化标记块。) */
4764
+
4590
4765
  /* ===== 消息使用量信息 ===== */
4591
4766
  .message-usage {
4592
4767
  margin-top: 8px;
@@ -10723,6 +10898,26 @@
10723
10898
  .tool-use-file { max-width: 100%; }
10724
10899
  .tool-use-body { padding: 10px 12px; }
10725
10900
  .subagent-reply { padding: 9px 12px; }
10901
+ .subagent-reply.collapsible { padding: 0; }
10902
+ .subagent-reply.final { padding: 9px 11px; }
10903
+ /* subagent-panel:窄屏头部不省略 attribution(可换行多行 vs 单行省略),
10904
+ body 高度收紧一点,footer hint 隐掉只留按钮。 */
10905
+ .subagent-panel { margin: 6px 0; }
10906
+ .subagent-panel-header {
10907
+ padding: 7px 10px;
10908
+ gap: 6px;
10909
+ font-size: 0.74rem;
10910
+ }
10911
+ .subagent-panel-attribution {
10912
+ white-space: normal;
10913
+ line-height: 1.4;
10914
+ }
10915
+ .subagent-panel-tag { margin: 0 4px; padding: 0 4px; }
10916
+ .subagent-panel-body { padding: 9px 11px; }
10917
+ .subagent-panel[data-expanded="false"] .subagent-panel-body { max-height: 18em; }
10918
+ .subagent-panel[data-expanded="true"] .subagent-panel-body { max-height: 60vh; }
10919
+ .subagent-panel-footer { padding: 5px 10px; }
10920
+ .subagent-panel-footer-hint { display: none; }
10726
10921
  .markdown-content .code-block { margin: 8px 0; }
10727
10922
  .markdown-content pre,
10728
10923
  .markdown-content .code-block pre,
@@ -15186,39 +15381,10 @@
15186
15381
  letter-spacing: 0.02em;
15187
15382
  white-space: nowrap;
15188
15383
  }
15189
- /* Switch row inside quick-commit modal — same iOS rhythm as settings */
15190
- .qc-checkbox-row {
15191
- display: flex;
15192
- align-items: center;
15193
- justify-content: space-between;
15194
- gap: 12px;
15195
- padding: 11px 14px;
15196
- background: rgba(255, 255, 255, 0.55);
15197
- border: 1px solid rgba(125, 91, 57, 0.08);
15198
- border-radius: 12px;
15199
- box-shadow: 0 1px 1px rgba(125, 91, 57, 0.02);
15200
- transition: background 0.16s ease, border-color 0.16s ease;
15201
- user-select: none;
15202
- }
15203
- .qc-checkbox-row:hover {
15204
- background: rgba(255, 255, 255, 0.78);
15205
- border-color: rgba(125, 91, 57, 0.16);
15206
- }
15207
- .qc-checkbox-row:has(.switch-toggle:checked) {
15208
- background: linear-gradient(180deg, #fff7ef 0%, #fff1de 100%);
15209
- border-color: rgba(197, 101, 61, 0.3);
15210
- }
15211
- .qc-checkbox-label {
15212
- flex: 1;
15213
- min-width: 0;
15214
- font-size: 0.8125rem;
15215
- font-weight: 600;
15216
- color: var(--text-primary);
15217
- cursor: pointer;
15218
- line-height: 1.4;
15219
- }
15220
15384
  .qc-switch {
15221
15385
  flex-shrink: 0;
15386
+ display: inline-flex;
15387
+ align-items: center;
15222
15388
  cursor: pointer;
15223
15389
  }
15224
15390
  .qc-message-row,
@@ -15236,6 +15402,62 @@
15236
15402
  align-items: center;
15237
15403
  justify-content: space-between;
15238
15404
  gap: 8px;
15405
+ flex-wrap: wrap;
15406
+ }
15407
+ .qc-ai-controls {
15408
+ display: inline-flex;
15409
+ align-items: center;
15410
+ justify-content: flex-end;
15411
+ gap: 7px;
15412
+ margin-left: auto;
15413
+ flex: 0 0 auto;
15414
+ }
15415
+ .qc-ai-tag-toggle {
15416
+ display: inline-flex;
15417
+ align-items: center;
15418
+ gap: 6px;
15419
+ min-height: 30px;
15420
+ padding: 3px 7px 3px 9px;
15421
+ border: 1px solid rgba(125, 91, 57, 0.12);
15422
+ border-radius: 999px;
15423
+ background: rgba(255, 255, 255, 0.58);
15424
+ color: var(--text-muted);
15425
+ font-size: 0.74rem;
15426
+ font-weight: 700;
15427
+ line-height: 1;
15428
+ user-select: none;
15429
+ cursor: pointer;
15430
+ transition: background 0.16s ease, border-color 0.16s ease, color 0.16s ease, box-shadow 0.16s ease;
15431
+ }
15432
+ .qc-ai-tag-toggle:hover {
15433
+ background: rgba(255, 255, 255, 0.82);
15434
+ border-color: rgba(125, 91, 57, 0.20);
15435
+ }
15436
+ .qc-ai-tag-toggle:has(.switch-toggle:checked) {
15437
+ color: rgba(170, 79, 42, 0.98);
15438
+ background: linear-gradient(180deg, #fff8f1 0%, #fff1e3 100%);
15439
+ border-color: rgba(197, 101, 61, 0.32);
15440
+ box-shadow: 0 1px 4px rgba(197, 101, 61, 0.10);
15441
+ }
15442
+ .qc-ai-tag-toggle:has(.switch-toggle:disabled) {
15443
+ cursor: default;
15444
+ opacity: 0.68;
15445
+ }
15446
+ .qc-ai-tag-label {
15447
+ white-space: nowrap;
15448
+ }
15449
+ .qc-switch--compact .switch-slider {
15450
+ width: 34px;
15451
+ min-width: 34px;
15452
+ height: 20px;
15453
+ border-radius: 999px;
15454
+ }
15455
+ .qc-switch--compact .switch-slider::after {
15456
+ width: 16px;
15457
+ height: 16px;
15458
+ }
15459
+ .qc-switch--compact .switch-toggle:checked + .switch-slider::after {
15460
+ transform: translateX(14px);
15239
15461
  }
15240
15462
  .qc-message-row textarea {
15241
15463
  resize: vertical;
@@ -15540,6 +15762,10 @@
15540
15762
  .qc-files-wrap { max-height: 160px; }
15541
15763
  .qc-section { padding: 10px 12px; }
15542
15764
  .qc-dropdown-menu { min-width: 180px; }
15765
+ .qc-ai-controls {
15766
+ width: 100%;
15767
+ justify-content: flex-end;
15768
+ }
15543
15769
  }
15544
15770
 
15545
15771
  /* ============================================================ */
@@ -2,12 +2,26 @@ import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
5
- // Cache the CSS content
5
+ // mtime 做缓存键,磁盘上 CSS 一变(npm run build / 手工 edit dist/)下次请求
6
+ // 就会自动 re-read。否则进程启动时缓存的 CSS 会粘住整个生命周期,UI 改动看不到效果,
7
+ // 必须重启 wand 才能生效——开发 / 修 UI 的时候这点尤其难受。
8
+ // 同步 stat 的成本:本地 fs,~几十微秒,相对一次 HTML 渲染可忽略。
6
9
  let _cssCache = null;
10
+ let _cssCacheMtimeMs = 0;
7
11
  export function getCSSStyles() {
8
- if (!_cssCache) {
9
- const cssPath = path.join(__dirname, "content", "styles.css");
10
- _cssCache = fs.readFileSync(cssPath, "utf-8");
12
+ const cssPath = path.join(__dirname, "content", "styles.css");
13
+ try {
14
+ const stat = fs.statSync(cssPath);
15
+ if (_cssCache === null || stat.mtimeMs !== _cssCacheMtimeMs) {
16
+ _cssCache = fs.readFileSync(cssPath, "utf-8");
17
+ _cssCacheMtimeMs = stat.mtimeMs;
18
+ }
19
+ }
20
+ catch {
21
+ // 文件丢了就退化到旧缓存(如果有),还没缓存过就抛出原错误让 server 知道。
22
+ if (_cssCache === null) {
23
+ _cssCache = fs.readFileSync(cssPath, "utf-8");
24
+ }
11
25
  }
12
26
  return _cssCache;
13
27
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@co0ontty/wand",
3
- "version": "1.36.0",
3
+ "version": "1.39.0",
4
4
  "description": "A web terminal for local CLI tools like Claude.",
5
5
  "type": "module",
6
6
  "bin": {