newmark-agent 0.6.1 → 0.6.3

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.
@@ -212,6 +212,10 @@ try {
212
212
 
213
213
  /* Light theme */
214
214
  [data-theme="light"] {
215
+ --accent: #405bd2;
216
+ --accent2: #147d59;
217
+ --nm-state-warning: #8a5b00;
218
+ --nm-state-danger: #c73545;
215
219
  --bg: #f0f2f8;
216
220
  --bg2: #e4e8f0;
217
221
  --bg3: #d8dce8;
@@ -367,7 +371,7 @@ html, body {
367
371
  50% { transform: scale(1.04); filter: saturate(1.25); }
368
372
  }
369
373
 
370
- ::selection { background: rgba(91,120,255,0.35); color: #fff; }
374
+ ::selection { background: rgba(91,120,255,0.35); color: var(--text-bright); }
371
375
 
372
376
  /* Open-source icon system: lucide-static sprite is copied into dist/ui at build time. */
373
377
  .nm-icon {
@@ -515,9 +519,9 @@ button { border-radius: var(--radius-full) !important; }
515
519
  transition: background var(--duration-fast) var(--ease-out-expo), color var(--duration-fast) var(--ease-out-expo);
516
520
  }
517
521
 
518
- .top-btn:hover { background: rgba(255,255,255,0.08); color: var(--text-bright); }
522
+ .top-btn:hover { background: var(--control-hover-bg); color: var(--text-bright); }
519
523
  .top-btn:active { transform: scale(0.92) translateZ(0); }
520
- .top-btn.close-btn:hover { background: rgba(255,68,68,0.2); color: #ff6666; }
524
+ .top-btn.close-btn:hover { background: rgba(255,68,68,0.2); color: var(--nm-state-danger); }
521
525
 
522
526
  /* ============================================================
523
527
  LAYER 3 - Main Layout
@@ -724,7 +728,7 @@ button.left-nav-icon { width: calc(100% - 12px); }
724
728
  white-space: nowrap;
725
729
  }
726
730
 
727
- .left-nav-icon:hover { background: rgba(255,255,255,0.06); color: var(--text-bright); }
731
+ .left-nav-icon:hover { background: var(--control-hover-bg); color: var(--text-bright); }
728
732
  .left-nav-icon:active { transform: scale(0.96) translateZ(0); }
729
733
  .left-nav-icon .icon { width: 24px; height: 20px; text-align: center; flex-shrink: 0; font-size: 0; }
730
734
  .left-nav-icon span:not(.icon) {
@@ -917,7 +921,7 @@ button.left-ws-item {
917
921
 
918
922
  .ws-pin-btn:hover,
919
923
  .ws-pin-btn.active {
920
- background: rgba(255,255,255,0.08);
924
+ background: var(--control-hover-bg);
921
925
  color: var(--text-bright);
922
926
  border-color: var(--accent);
923
927
  }
@@ -985,7 +989,7 @@ button.left-ws-item {
985
989
  border-top: 1px solid var(--glass-border-1);
986
990
  }
987
991
 
988
- .left-collapse-btn:hover { background: rgba(255,255,255,0.06); color: var(--text-bright); }
992
+ .left-collapse-btn:hover { background: var(--control-hover-bg); color: var(--text-bright); }
989
993
  .left-collapse-btn:active { transform: scale(0.92) translateZ(0); }
990
994
 
991
995
  /* ============================================================
@@ -1102,7 +1106,7 @@ button.left-ws-item {
1102
1106
  }
1103
1107
 
1104
1108
  .conv-archive-btn:hover,
1105
- .conv-rename-btn:hover { background: rgba(255,255,255,0.1); color: var(--text-bright); }
1109
+ .conv-rename-btn:hover { background: var(--control-hover-bg); color: var(--text-bright); }
1106
1110
 
1107
1111
  .conv-archive-btn.archiving { cursor: default; border-color: var(--accent); }
1108
1112
  .conv-archive-spinner {
@@ -1198,7 +1202,7 @@ button.left-ws-item {
1198
1202
 
1199
1203
  .conv-pin-btn:hover,
1200
1204
  .conv-pin-btn.active {
1201
- background: rgba(255,255,255,0.1);
1205
+ background: var(--control-hover-bg);
1202
1206
  color: var(--text-bright);
1203
1207
  border-color: var(--accent);
1204
1208
  }
@@ -1378,7 +1382,7 @@ button.left-ws-item {
1378
1382
  position: relative;
1379
1383
  }
1380
1384
 
1381
- .tab-btn:hover { background: rgba(255,255,255,0.06); color: var(--text-bright); }
1385
+ .tab-btn:hover { background: var(--control-hover-bg); color: var(--text-bright); }
1382
1386
  .tab-btn.active { background: rgba(91,120,255,0.12); color: var(--accent); border-color: rgba(91,120,255,0.2); }
1383
1387
  .tab-btn:active { transform: scale(0.92) translateZ(0); }
1384
1388
  .tab-btn .label { display: none; }
@@ -1474,7 +1478,7 @@ button.left-ws-item {
1474
1478
  transition: background var(--duration-fast) var(--ease-out-expo);
1475
1479
  }
1476
1480
 
1477
- .et-btn:hover { background: rgba(255,255,255,0.08); color: var(--text-bright); }
1481
+ .et-btn:hover { background: var(--control-hover-bg); color: var(--text-bright); }
1478
1482
  .et-btn.active { background:rgba(91,120,255,.16); color:var(--accent2); border-color:rgba(91,120,255,.55); }
1479
1483
  .et-btn .nm-icon { width:15px; height:15px; }
1480
1484
  .et-btn.primary { background: var(--accent); color: #fff; border-color: var(--accent); }
@@ -1518,6 +1522,7 @@ button.left-ws-item {
1518
1522
 
1519
1523
  .browser-url-input {
1520
1524
  flex: 1;
1525
+ min-width: 0;
1521
1526
  padding: 5px 10px;
1522
1527
  border: 1px solid var(--border);
1523
1528
  border-radius: var(--radius-md);
@@ -1535,7 +1540,7 @@ button.left-ws-item {
1535
1540
  min-height: 280px;
1536
1541
  border: 1px solid var(--border);
1537
1542
  border-radius: var(--radius-md);
1538
- background: #fff;
1543
+ background: var(--bg);
1539
1544
  overflow: hidden;
1540
1545
  }
1541
1546
 
@@ -1578,15 +1583,21 @@ button.left-ws-item {
1578
1583
  .md-rendered pre {
1579
1584
  position: relative;
1580
1585
  margin: 8px 0;
1581
- padding: 10px 12px;
1582
- overflow-x: auto;
1586
+ padding: 0;
1587
+ max-width: 100%;
1588
+ min-width: 0;
1589
+ overflow: hidden;
1590
+ text-align: left;
1591
+ white-space: normal;
1583
1592
  border: 1px solid var(--glass-border-1);
1584
1593
  border-radius: var(--radius-sm);
1585
- background: rgba(0,0,0,0.26);
1594
+ background: var(--glass-bg-3);
1586
1595
  }
1587
1596
  .md-rendered pre code {
1588
1597
  display: block;
1589
- padding: 0;
1598
+ padding: 10px 12px;
1599
+ max-width: 100%;
1600
+ overflow-x: auto;
1590
1601
  border: 0;
1591
1602
  background: transparent;
1592
1603
  white-space: pre;
@@ -1847,7 +1858,7 @@ button.left-ws-item {
1847
1858
 
1848
1859
  .plan-status-btn.in-progress {
1849
1860
  border-color: rgba(240,173,78,0.7);
1850
- color: #f0ad4e;
1861
+ color: var(--nm-state-warning);
1851
1862
  }
1852
1863
 
1853
1864
  .plan-status-btn.done {
@@ -1978,7 +1989,7 @@ button.left-ws-item {
1978
1989
  line-height: 1;
1979
1990
  }
1980
1991
 
1981
- .terminal-tab .close-tab:hover { background: rgba(255,80,80,0.3); color: #ff6666; }
1992
+ .terminal-tab .close-tab:hover { background: rgba(255,80,80,0.3); color: var(--nm-state-danger); }
1982
1993
 
1983
1994
  #terminal-body {
1984
1995
  flex: 1;
@@ -2105,7 +2116,7 @@ button.left-ws-item {
2105
2116
  transition: background var(--duration-fast) var(--ease-out-expo), color var(--duration-fast) var(--ease-out-expo);
2106
2117
  }
2107
2118
 
2108
- .shell-btn:hover { background: rgba(255,255,255,0.08); color: var(--text-bright); }
2119
+ .shell-btn:hover { background: var(--control-hover-bg); color: var(--text-bright); }
2109
2120
  .shell-btn:active { transform: scale(0.95) translateZ(0); }
2110
2121
 
2111
2122
  .shell-toggle-btn {
@@ -2171,9 +2182,7 @@ button.left-ws-item {
2171
2182
  background-color: var(--chat-canvas);
2172
2183
  }
2173
2184
  .md-code-copy {
2174
- position: absolute;
2175
- top: 6px;
2176
- right: 7px;
2185
+ flex-shrink: 0;
2177
2186
  border: 1px solid var(--glass-border-1);
2178
2187
  border-radius: 4px;
2179
2188
  background: var(--glass-bg-2);
@@ -2183,6 +2192,10 @@ button.left-ws-item {
2183
2192
  cursor: pointer;
2184
2193
  }
2185
2194
  .md-code-copy:hover { color: var(--text); }
2195
+ .md-code-toolbar { display:flex; align-items:center; justify-content:space-between; gap:12px; padding:6px 10px; border-bottom:1px solid var(--glass-border-1); color:var(--text-dim); font:11px var(--font-ui); }
2196
+ .md-code-toolbar > span { min-width:0; overflow:hidden; text-overflow:ellipsis; }
2197
+ .chat-msg.assistant > .msg-body { padding-right:28px; min-width:0; }
2198
+ .chat-msg.user > .msg-body { padding-left:28px; min-width:0; }
2186
2199
 
2187
2200
  #chat-area {
2188
2201
  flex: 1;
@@ -2372,10 +2385,10 @@ button.left-ws-item {
2372
2385
  }
2373
2386
 
2374
2387
  .chat-msg.error {
2375
- color: #ff8888;
2388
+ color: var(--nm-state-danger);
2376
2389
  }
2377
2390
 
2378
- .chat-msg.guide-rejected::after { border-color: #ff8888; }
2391
+ .chat-msg.guide-rejected::after { border-color: var(--nm-state-danger); }
2379
2392
 
2380
2393
  .guide-receipt-status {
2381
2394
  display: inline-flex;
@@ -2390,9 +2403,9 @@ button.left-ws-item {
2390
2403
  opacity: 0.86;
2391
2404
  }
2392
2405
 
2393
- .guide-receipt-status.deferred { color: #ffd27a; border-color: rgba(255, 210, 122, 0.28); }
2406
+ .guide-receipt-status.deferred { color: var(--nm-state-warning); border-color: rgba(255, 210, 122, 0.28); }
2394
2407
  .guide-receipt-status.applied { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 30%, transparent); }
2395
- .guide-receipt-status.rejected { color: #ff8888; border-color: rgba(255, 136, 136, 0.34); }
2408
+ .guide-receipt-status.rejected { color: var(--nm-state-danger); border-color: rgba(255, 136, 136, 0.34); }
2396
2409
 
2397
2410
  .chat-msg .meta {
2398
2411
  display: flex;
@@ -2413,7 +2426,7 @@ button.left-ws-item {
2413
2426
  .chat-msg.user .msg-role { color: var(--accent); }
2414
2427
  .chat-msg.assistant .msg-role { color: var(--accent2); }
2415
2428
  .chat-msg.workflow .msg-role { color: var(--accent); }
2416
- .chat-msg.error .msg-role { color: #ff8888; }
2429
+ .chat-msg.error .msg-role { color: var(--nm-state-danger); }
2417
2430
  .chat-msg.user .meta { justify-content: flex-end; text-align: right; }
2418
2431
  .chat-msg.user .msg-body { text-align: right; }
2419
2432
  .chat-msg.user .msg-actions { margin-left: 4px; }
@@ -2473,7 +2486,7 @@ button.left-ws-item {
2473
2486
  .message-edit-submit { border-color: color-mix(in srgb, var(--accent) 55%, var(--glass-border-2)); color: var(--accent); }
2474
2487
  .conversation-branch-pager { display:flex; justify-content:flex-end; align-items:center; gap:0; margin-top:7px; color:var(--text-dim); font-size:11px; }
2475
2488
  .branch-page-arrow { cursor:pointer; color:var(--text-dim); padding:1px 3px; transition:color var(--duration-fast) var(--ease-out-expo), background var(--duration-fast) var(--ease-out-expo); border-radius:var(--radius-sm); }
2476
- .branch-page-arrow:hover { color:var(--text-bright); background:rgba(255,255,255,0.06); }
2489
+ .branch-page-arrow:hover { color:var(--text-bright); background:var(--control-hover-bg); }
2477
2490
  .branch-page-arrow:active { transform:scale(0.92) translateZ(0); }
2478
2491
 
2479
2492
  .chat-msg .msg-body .md-rendered {
@@ -2633,8 +2646,8 @@ button.left-ws-item {
2633
2646
  .conversation-work-run-title { flex: 1; min-width: 0; }
2634
2647
  .conversation-work-run-status { color: var(--text-dim); font: 10px var(--font-mono); }
2635
2648
  .conversation-work-change-badge { display:inline-flex; align-items:center; gap:8px; margin-left:auto; padding:5px 10px; border:1px solid var(--border); border-radius:999px; background:var(--panel); color:var(--text-dim); font-size:11px; white-space:nowrap; }
2636
- .conversation-work-change-badge .add { color:#2fd67b; }
2637
- .conversation-work-change-badge .del { color:#ff5e67; }
2649
+ .conversation-work-change-badge .add { color:var(--nm-state-success); }
2650
+ .conversation-work-change-badge .del { color:var(--nm-state-danger); }
2638
2651
  .conversation-work-run-body { border: 0; padding: 4px var(--work-run-right-safe) 8px 0; }
2639
2652
  .conversation-work-run.collapsed .conversation-work-run-body { display: none; }
2640
2653
  .work-run-collapsed-guides { display: none; }
@@ -2646,7 +2659,7 @@ button.left-ws-item {
2646
2659
  .conversation-work-event { display: grid; grid-template-columns: 17px minmax(0,1fr); gap: 7px; align-items: start; color: var(--text-dim); font-size: 11px; line-height: 1.5; }
2647
2660
  .conversation-work-event .nm-icon { margin-top: 1px; color: var(--text-dim); }
2648
2661
  .conversation-work-event.guide { color: var(--text); padding: 3px 0; }
2649
- .conversation-work-event.error { color: #ff8888; }
2662
+ .conversation-work-event.error { color: var(--nm-state-danger); }
2650
2663
  .conversation-work-event-content { min-width: 0; white-space: pre-wrap; word-break: break-word; }
2651
2664
  .conversation-work-event.narrative { display: block; color: var(--text); font-size: 13px; line-height: 1.65; padding: 3px 1px 7px; }
2652
2665
  .conversation-work-event.activity-summary { font-size: 11px; font-weight: 400; color: var(--text-dim); padding: 2px 0; }
@@ -2708,7 +2721,7 @@ button.left-ws-item {
2708
2721
  .conversation-work-file-inline { margin: 1px 0; border: none; border-radius: 0; background: transparent; }
2709
2722
  .conversation-work-file.conversation-work-file-inline > summary { display: grid; grid-template-columns: 17px minmax(0,max-content) auto 10px; gap: 7px; align-items: center; justify-content: start; width: fit-content; max-width: 100%; min-height: 24px; padding: 0; border-radius: var(--radius-sm); color: var(--text-dim); font: 400 11px/1.5 var(--font-ui); transition: background var(--duration-fast) var(--ease-out-expo); list-style: none; cursor: pointer; }
2710
2723
  .conversation-work-file-inline > summary::-webkit-details-marker { display: none; }
2711
- .conversation-work-file-inline > summary:hover { background: rgba(255,255,255,0.04); }
2724
+ .conversation-work-file-inline > summary:hover { background: var(--control-hover-bg); }
2712
2725
  .conversation-work-file-inline > summary .nm-icon { margin-top: 2px; color: var(--text-dim); }
2713
2726
  .conversation-work-file-inline .conversation-work-file-name { font: inherit; }
2714
2727
  .conversation-work-file-inline .conversation-work-file-stats { font: 10px/1.5 var(--font-mono); }
@@ -2717,13 +2730,13 @@ button.left-ws-item {
2717
2730
  .conversation-work-file-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: 12px var(--font-mono); }
2718
2731
  .conversation-work-file-stats { display: inline-flex; gap: 7px; font: 11px var(--font-mono); }
2719
2732
  .conversation-work-file-add { color: var(--accent2); }
2720
- .conversation-work-file-del { color: #ff6666; }
2733
+ .conversation-work-file-del { color: var(--nm-state-danger); }
2721
2734
  .conversation-work-file-diff { max-height: 340px; overflow: auto; border-top: 1px solid var(--glass-border-1); background: rgba(0,0,0,.14); font: 11px/1.55 var(--font-mono); }
2722
2735
  .conversation-work-file-line { display: grid; grid-template-columns: 42px minmax(0,1fr); min-height: 22px; white-space: pre; }
2723
2736
  .conversation-work-file-line-number { padding: 2px 8px; color: var(--text-dim); text-align: right; user-select: none; border-right: 1px solid var(--glass-border-1); }
2724
2737
  .conversation-work-file-line-code { padding: 2px 10px; overflow-wrap: normal; }
2725
- .conversation-work-file-line.del { color: #ff9a9a; background: rgba(255,68,68,.14); }
2726
- .conversation-work-file-line.add { color: #78e8b8; background: rgba(56,212,160,.13); }
2738
+ .conversation-work-file-line.del { color: var(--nm-state-danger); background: rgba(255,68,68,.14); }
2739
+ .conversation-work-file-line.add { color: var(--nm-state-success); background: rgba(56,212,160,.13); }
2727
2740
  .conversation-work-file-line.empty { color: var(--text-dim); }
2728
2741
  .conversation-work-empty { color: var(--text-dim); font-size: 11px; }
2729
2742
 
@@ -2822,7 +2835,7 @@ button.left-ws-item {
2822
2835
  transition: background var(--duration-fast) var(--ease-out-expo);
2823
2836
  }
2824
2837
 
2825
- .shell-block-header:hover { background: rgba(255,255,255,0.06); }
2838
+ .shell-block-header:hover { background: var(--control-hover-bg); }
2826
2839
  .shell-block-header .arrow { transition: transform var(--duration-fast) var(--ease-out-expo); font-size: 9px; }
2827
2840
  .shell-block.collapsed .shell-block-header .arrow { transform: rotate(-90deg); }
2828
2841
  .shell-block-body {
@@ -2858,7 +2871,7 @@ button.left-ws-item {
2858
2871
  transition: background var(--duration-fast) var(--ease-out-expo);
2859
2872
  }
2860
2873
 
2861
- .diff-block-header:hover { background: rgba(255,255,255,0.06); }
2874
+ .diff-block-header:hover { background: var(--control-hover-bg); }
2862
2875
  .diff-block.collapsed .diff-block-body { display: none; }
2863
2876
  .diff-block-header .arrow { transition: transform var(--duration-fast) var(--ease-out-expo); font-size: 9px; }
2864
2877
  .diff-block.collapsed .diff-block-header .arrow { transform: rotate(-90deg); }
@@ -2882,7 +2895,7 @@ button.todo-item { background: transparent; }
2882
2895
 
2883
2896
  .diff-stat { display: flex; gap: 8px; margin-left: auto; }
2884
2897
  .diff-add { color: var(--accent2); font-size: 11px; }
2885
- .diff-del { color: #ff6666; font-size: 11px; }
2898
+ .diff-del { color: var(--nm-state-danger); font-size: 11px; }
2886
2899
  .diff-block-body {
2887
2900
  padding: 0;
2888
2901
  font-family: var(--font-mono);
@@ -2898,7 +2911,7 @@ button.todo-item { background: transparent; }
2898
2911
  }
2899
2912
 
2900
2913
  .diff-line.add { background: rgba(56,212,160,0.1); color: var(--accent2); }
2901
- .diff-line.del { background: rgba(255,68,68,0.1); color: #ff8888; }
2914
+ .diff-line.del { background: rgba(255,68,68,0.1); color: var(--nm-state-danger); }
2902
2915
  .diff-line.ctx { color: var(--text-dim); }
2903
2916
 
2904
2917
  /* Option feedback */
@@ -3089,7 +3102,7 @@ button.todo-item { background: transparent; }
3089
3102
  }
3090
3103
 
3091
3104
  .stack-icon-btn:hover {
3092
- background: rgba(255,255,255,0.08);
3105
+ background: var(--control-hover-bg);
3093
3106
  color: var(--text-bright);
3094
3107
  border-color: var(--glass-border-1);
3095
3108
  }
@@ -3099,8 +3112,8 @@ button.todo-item { background: transparent; }
3099
3112
  }
3100
3113
 
3101
3114
  .stack-icon-btn:active { transform: scale(0.94); }
3102
- .stack-icon-btn.warn { color: #ffcc44; }
3103
- .stack-icon-btn.danger { color: #ff7777; }
3115
+ .stack-icon-btn.warn { color: var(--nm-state-warning); }
3116
+ .stack-icon-btn.danger { color: var(--nm-state-danger); }
3104
3117
  .stack-icon-btn:focus-visible {
3105
3118
  border-color: var(--accent);
3106
3119
  box-shadow: 0 0 0 3px var(--accent-glow);
@@ -3415,9 +3428,9 @@ button.todo-item { background: transparent; }
3415
3428
 
3416
3429
  .conv-runtime-badge.running { color: var(--accent2); }
3417
3430
  .conv-runtime-badge.stopping,
3418
- .conv-runtime-badge.force_restarting { color: #ffd27a; }
3431
+ .conv-runtime-badge.force_restarting { color: var(--nm-state-warning); }
3419
3432
  .conv-runtime-badge.error,
3420
- .conv-runtime-badge.force_interrupted { color: #ff9ca6; }
3433
+ .conv-runtime-badge.force_interrupted { color: var(--nm-state-danger); }
3421
3434
 
3422
3435
  .queue-edit:focus {
3423
3436
  color: var(--text-bright);
@@ -4109,7 +4122,7 @@ button.todo-item { background: transparent; }
4109
4122
  }
4110
4123
 
4111
4124
  #scroll-bottom-btn.visible { display: flex; }
4112
- #scroll-bottom-btn:hover { background: rgba(255,255,255,0.1); color: var(--text-bright); box-shadow: var(--shadow-lg); }
4125
+ #scroll-bottom-btn:hover { background: var(--control-hover-bg); color: var(--text-bright); box-shadow: var(--shadow-lg); }
4113
4126
 
4114
4127
  /* ============================================================
4115
4128
  MARQUEE BORDER
@@ -4390,8 +4403,8 @@ button.todo-item { background: transparent; }
4390
4403
  transition: background var(--duration-fast) var(--ease-out-expo), color var(--duration-fast) var(--ease-out-expo);
4391
4404
  }
4392
4405
 
4393
- .sub-win-close:hover { background: rgba(255,68,68,0.15); color: #ff6666; }
4394
- .sub-win-close:focus-visible { outline:none; color:#ff7777; box-shadow:inset 0 0 0 2px currentColor; }
4406
+ .sub-win-close:hover { background: rgba(255,68,68,0.15); color: var(--nm-state-danger); }
4407
+ .sub-win-close:focus-visible { outline:none; color:var(--nm-state-danger); box-shadow:inset 0 0 0 2px currentColor; }
4395
4408
 
4396
4409
  .sub-win-body {
4397
4410
  flex: 1;
@@ -4596,7 +4609,7 @@ textarea.mcp-input { min-height:76px; resize:vertical; font-family:var(--font-mo
4596
4609
  .remote-touch-status:hover { background: transparent !important; }
4597
4610
  .remote-touch-status.listening { color: var(--accent2); }
4598
4611
  .remote-touch-status.error,
4599
- .remote-touch-status.checking { color: #ffb454; }
4612
+ .remote-touch-status.checking { color: var(--nm-state-warning); }
4600
4613
  .remote-touch-status.off { color: var(--notice-error-text); }
4601
4614
  .remote-touch-status[aria-busy="true"] { cursor: wait; }
4602
4615
 
@@ -4825,8 +4838,8 @@ textarea.mcp-input { min-height:76px; resize:vertical; font-family:var(--font-mo
4825
4838
  .github-repo-select-icon { position:absolute; right:11px; top:50%; width:14px; height:14px; transform:translateY(-50%); color:var(--text-dim); pointer-events:none; display:inline-flex; align-items:center; justify-content:center; }
4826
4839
  .model-eval-line { display:block; margin-top:4px; font-size:10px; color:var(--text-dim); }
4827
4840
  .model-eval-ok { color: var(--accent2); }
4828
- .model-eval-bad { color: #ff7777; }
4829
- .model-eval-pending { color: #ffd166; }
4841
+ .model-eval-bad { color: var(--nm-state-danger); }
4842
+ .model-eval-pending { color: var(--nm-state-warning); }
4830
4843
 
4831
4844
  /* Memory Lab tag graph */
4832
4845
  .memory-lab-panel {
@@ -5436,7 +5449,7 @@ html.newmark-memory-overview-viewer body {
5436
5449
  transition: color var(--duration-fast) var(--ease-out-expo);
5437
5450
  }
5438
5451
 
5439
- .model-chip .remove:hover { color: #ff6666; }
5452
+ .model-chip .remove:hover { color: var(--nm-state-danger); }
5440
5453
 
5441
5454
  .model-eval-results {
5442
5455
  margin-top: 10px;
@@ -5534,8 +5547,8 @@ html.newmark-memory-overview-viewer body {
5534
5547
  transition: background var(--duration-fast) var(--ease-out-expo);
5535
5548
  }
5536
5549
 
5537
- .archive-action-btn:hover { background: rgba(255,255,255,0.08); color: var(--text-bright); }
5538
- .archive-action-btn.danger:hover { background: rgba(255,68,68,0.15); color: #ff6666; }
5550
+ .archive-action-btn:hover { background: var(--control-hover-bg); color: var(--text-bright); }
5551
+ .archive-action-btn.danger:hover { background: rgba(255,68,68,0.15); color: var(--nm-state-danger); }
5539
5552
 
5540
5553
  /* ============================================================
5541
5554
  AUTOMATION WINDOW
@@ -6243,11 +6256,12 @@ input[type="checkbox"]::before {
6243
6256
  width: 18px;
6244
6257
  height: 18px;
6245
6258
  border-radius: 50%;
6246
- background: var(--text-bright);
6259
+ background: var(--text);
6247
6260
  box-shadow: 0 2px 5px rgba(0,0,0,.28);
6248
6261
  transform: translateX(var(--liquid-switch-x)) scale(1);
6249
6262
  transition: transform 160ms var(--ease-out-expo), box-shadow 100ms var(--ease-out-expo), background 100ms var(--ease-out-expo);
6250
6263
  }
6264
+ input[type="checkbox"]:checked::before { background: #fff; }
6251
6265
  input[type="checkbox"].liquid-switch-dragging::before {
6252
6266
  left: 1px;
6253
6267
  width: 22px;
@@ -7129,6 +7143,10 @@ var state = {
7129
7143
  _conversationLoadingMsgEl: null,
7130
7144
  _syncedMode: null,
7131
7145
  _syncedModel: null,
7146
+ // Monotonic revision for explicit renderer model changes. Activation
7147
+ // snapshots may restore the conversation's remembered model only when no
7148
+ // newer local selection was made while the snapshot was in flight.
7149
+ modelSelectionRevision: 0,
7132
7150
  _syncedInputMode: null,
7133
7151
  _editingQueueIndex: -1,
7134
7152
  _editingGoalText: '',
@@ -9207,7 +9225,7 @@ function renderMarkdownBlocks(text) {
9207
9225
  var code = codeLines.join('\n');
9208
9226
  var normalizedLanguage = lang ? normalizeCodeLanguage(lang) : 'text';
9209
9227
  var highlighted = normalizedLanguage === 'text' ? esc(code) : highlightCodeByLanguage(code, normalizedLanguage);
9210
- html += '<pre><button class="md-code-copy" type="button" title="' + escAttr(t('common.copy')) + '" data-code="' + escAttr(code) + '" onclick="window.copyMarkdownCode(this)">' + esc(t('common.copy')) + '</button><code' + (lang ? ' data-lang="' + escAttr(lang) + '"' : '') + ' class="md-code-block language-' + escAttr(normalizedLanguage) + '">' + highlighted + '</code></pre>';
9228
+ html += '<pre><div class="md-code-toolbar"><span>' + esc(lang || 'text') + '</span><button class="md-code-copy" type="button" aria-label="' + escAttr(currentLang() === 'zh' ? '复制代码' : 'Copy code') + '" title="' + escAttr(t('common.copy')) + '" data-code="' + escAttr(code) + '" onclick="window.copyMarkdownCode(this)">' + esc(t('common.copy')) + '</button></div><code' + (lang ? ' data-lang="' + escAttr(lang) + '"' : '') + ' class="md-code-block language-' + escAttr(normalizedLanguage) + '">' + highlighted + '</code></pre>';
9211
9229
  continue;
9212
9230
  }
9213
9231
  if (trimmed === '$$' || trimmed === '\\[') {
@@ -9339,7 +9357,7 @@ var api = window.api || {
9339
9357
  conversationId: target.conversationId,
9340
9358
  action: action
9341
9359
  };
9342
- ['id', 'text', 'value', 'requestedMode', 'goalObjective', 'createdAt', 'images', 'paused', 'orderedIds'].forEach(function(field) {
9360
+ ['id', 'text', 'value', 'requestedMode', 'goalObjective', 'createdAt', 'images', 'paused', 'orderedIds', 'branchNodeId', 'branchPath'].forEach(function(field) {
9343
9361
  if (input && Object.prototype.hasOwnProperty.call(input, field)) body[field] = input[field];
9344
9362
  });
9345
9363
  var r = await fetch('/api/queue-action', {
@@ -11924,9 +11942,11 @@ function updateConversationWorkRunElement(run, element) {
11924
11942
  }
11925
11943
  var running = ['running', 'stopping', 'force_restarting'].indexOf(String(run.status || '')) >= 0;
11926
11944
  var expanded = !!run.expanded;
11927
- element.className = 'conversation-work-run ' + (running ? 'running ' : '') + (expanded ? 'expanded' : 'collapsed');
11928
- element.setAttribute('data-run-id', run.runId);
11929
- element.setAttribute('data-runtime-key', runtimeKeyFor(run.target && run.target.workspaceId, run.target && run.target.conversationId));
11945
+ var nextClassName = 'conversation-work-run ' + (running ? 'running ' : '') + (expanded ? 'expanded' : 'collapsed');
11946
+ if (element.className !== nextClassName) element.className = nextClassName;
11947
+ if (element.getAttribute('data-run-id') !== String(run.runId)) element.setAttribute('data-run-id', run.runId);
11948
+ var nextRuntimeKey = runtimeKeyFor(run.target && run.target.workspaceId, run.target && run.target.conversationId);
11949
+ if (element.getAttribute('data-runtime-key') !== nextRuntimeKey) element.setAttribute('data-runtime-key', nextRuntimeKey);
11930
11950
  var head = element.querySelector ? element.querySelector('.conversation-work-run-head') : null;
11931
11951
  if (!head) {
11932
11952
  element.innerHTML = '<button class="conversation-work-run-head" type="button" onclick="window.toggleConversationWorkRun(this)">' +
@@ -12004,7 +12024,9 @@ function updateConversationWorkRunElement(run, element) {
12004
12024
  var refreshedParentKey = String(refreshedParent && refreshedParent.getAttribute('data-activity-key') || '');
12005
12025
  var refreshedDetailKey = String(refreshedActivities[refreshedIndex].getAttribute('data-work-detail-key') || 'activity');
12006
12026
  var refreshedKey = refreshedParentKey ? refreshedParentKey + '::' + refreshedDetailKey : '';
12007
- if (activityOpenStates[refreshedKey] !== undefined) refreshedActivities[refreshedIndex].open = activityOpenStates[refreshedKey];
12027
+ if (activityOpenStates[refreshedKey] !== undefined && refreshedActivities[refreshedIndex].open !== activityOpenStates[refreshedKey]) {
12028
+ refreshedActivities[refreshedIndex].open = activityOpenStates[refreshedKey];
12029
+ }
12008
12030
  }
12009
12031
  if (chatEl) {
12010
12032
  if (wasAtBottom) {
@@ -13269,6 +13291,35 @@ function hydrateConversationBranchState(snapshot) {
13269
13291
  rememberRuntimeConversationBranchPath(currentConversationTarget(s.conversationId || activeConversationId()));
13270
13292
  }
13271
13293
 
13294
+ // Apply the conversation's remembered provider-qualified model to the
13295
+ // composer selector. The backend snapshot is authoritative; a newer explicit
13296
+ // user selection made while the snapshot was in flight wins via the revision
13297
+ // guard passed by the activation caller.
13298
+ function applyConversationModelSelection(snapshot) {
13299
+ var nextModel = String(snapshot && snapshot.model || '').trim();
13300
+ if (!nextModel) return;
13301
+ state.model = nextModel;
13302
+ if (typeof snapshot.modelLabel === 'string' && snapshot.modelLabel) state.modelLabel = snapshot.modelLabel;
13303
+ state._syncedModel = nextModel;
13304
+ var sel = els['model-select'] || document.getElementById('model-select');
13305
+ if (!sel) {
13306
+ if (window.syncModelSelectSurface) window.syncModelSelectSurface();
13307
+ return;
13308
+ }
13309
+ var hasOption = Array.prototype.some.call(sel.options, function(option) {
13310
+ return String(option.value || '') === nextModel;
13311
+ });
13312
+ if (hasOption) {
13313
+ sel.value = nextModel;
13314
+ window.syncModelSelectSurface();
13315
+ } else if (window.refreshModelSelect) {
13316
+ // The remembered deployment is not in the current enabled catalog (for
13317
+ // example its provider was explicitly disabled). Reuse the existing
13318
+ // visibility fallback instead of displaying a model that cannot run.
13319
+ window.refreshModelSelect();
13320
+ }
13321
+ }
13322
+
13272
13323
  function applyConversationSnapshot(s, requestedConversationId, options) {
13273
13324
  if (!s) return;
13274
13325
  if (s.computerUse) {
@@ -13291,6 +13342,11 @@ function applyConversationSnapshot(s, requestedConversationId, options) {
13291
13342
  if (s && s.runtimeKey) registerRuntimeKey(snapshotTarget, s.runtimeKey);
13292
13343
  hydrateConversationDraftSnapshot(s, snapshotTarget);
13293
13344
  hydrateConversationBranchState(s);
13345
+ var modelRevisionMatches = !options || options.modelRevision === undefined
13346
+ || Number(state.modelSelectionRevision || 0) === Number(options.modelRevision || 0);
13347
+ if (modelRevisionMatches && isActiveConversationTarget(snapshotTarget)) {
13348
+ applyConversationModelSelection(s);
13349
+ }
13294
13350
  rebindQueueToRuntimeBranch(snapshotTarget);
13295
13351
  if (s && Array.isArray(s.workRuns) && !preserveReadableHistory) {
13296
13352
  var viewedBranchIdForSync = Array.isArray(s.viewedBranchNodePath) && s.viewedBranchNodePath.length
@@ -14009,6 +14065,19 @@ function positionContextInspector() {
14009
14065
  panel.style.maxHeight = Math.max(0, Math.floor(ring.getBoundingClientRect().top - visibleTop - 20)) + 'px';
14010
14066
  panel.style.overflowY = 'auto';
14011
14067
  panel.style.overscrollBehavior = 'contain';
14068
+ // The chat column clips its descendants. Clamp to that column rather than
14069
+ // the desktop viewport so a narrow composer cannot hide half the inspector.
14070
+ var column = document.getElementById('center');
14071
+ var parent = panel.offsetParent;
14072
+ if (column && parent) {
14073
+ var bounds = column.getBoundingClientRect();
14074
+ var origin = parent.getBoundingClientRect();
14075
+ var width = Math.min(320, Math.max(0, bounds.width - 24));
14076
+ var left = Math.max(bounds.left + 12, Math.min(origin.right + 8 - width, bounds.right - 12 - width));
14077
+ panel.style.width = width + 'px';
14078
+ panel.style.left = (left - origin.left) + 'px';
14079
+ panel.style.right = 'auto';
14080
+ }
14012
14081
  }
14013
14082
 
14014
14083
  window.renderContextInspector = function() {
@@ -14109,6 +14178,10 @@ window.closeContextInspector = function() {
14109
14178
 
14110
14179
  (function() {
14111
14180
  window.addEventListener('resize', positionContextInspector);
14181
+ if (typeof ResizeObserver === 'function') {
14182
+ var contextColumn = document.getElementById('center');
14183
+ if (contextColumn) new ResizeObserver(positionContextInspector).observe(contextColumn);
14184
+ }
14112
14185
  document.addEventListener('click', function(event) {
14113
14186
  if (!state.contextInspectorOpen) return;
14114
14187
  var ring = document.getElementById('context-token-ring');
@@ -14408,6 +14481,7 @@ function applyModelFallbackToInputSurface(event) {
14408
14481
  var nextValue = modelDeploymentValueForName(f.to, f.providerId || '');
14409
14482
  if (!nextValue || String(state.model || '') === nextValue) return;
14410
14483
  state.model = nextValue;
14484
+ state.modelSelectionRevision = Number(state.modelSelectionRevision || 0) + 1;
14411
14485
  state.modelLabel = '';
14412
14486
  // 不预置 _syncedModel:下一次发送前的 syncConversationExecutionState 会把
14413
14487
  // 回退模型正式同步到后端 host agent(并持久化为该对话的首选模型)。
@@ -15829,6 +15903,15 @@ function wireDirectLiquidMenuInteractionsV2(menu) {
15829
15903
  ensureBlock();
15830
15904
  }
15831
15905
 
15906
+ function cancelLiquidPopupExit(popup) {
15907
+ if (!popup) return;
15908
+ if (popup._liquidExitTimer) clearTimeout(popup._liquidExitTimer);
15909
+ popup._liquidExitTimer = 0;
15910
+ popup.classList.remove('liquid-popup-exit');
15911
+ popup.style.removeProperty('--liquid-popup-origin-x');
15912
+ popup.style.removeProperty('--liquid-popup-origin-y');
15913
+ }
15914
+
15832
15915
  window.animateLiquidPopupExit = function(popup, anchor, done) {
15833
15916
  if (!popup) { if (done) done(); return; }
15834
15917
  clearLiquidPopupOutset(popup, true);
@@ -17164,6 +17247,11 @@ function bindBackendQueuedRequestToTarget(text, target, occurrence) {
17164
17247
  request.createdAt = queueItem.createdAt;
17165
17248
  request.runId = queueItem.runId;
17166
17249
  request.images = (queueItem.images || []).map(function(image) { return Object.assign({}, image); });
17250
+ if (Array.isArray(queueItem.branchPath) && queueItem.branchPath.length) {
17251
+ request.branchPath = queueItem.branchPath.join('>');
17252
+ } else if (queueItem.branchNodeId) {
17253
+ request.branchPath = String(queueItem.branchNodeId);
17254
+ }
17167
17255
  }
17168
17256
  return request;
17169
17257
  }
@@ -17876,7 +17964,15 @@ window.sendMessage = async function(modeOverride, queuedText, opts) {
17876
17964
  queuedModeRequest.goalDeclaration = true;
17877
17965
  queuedModeRequest.goalObjective = rawText;
17878
17966
  }
17879
- var queueResult = await api.sendMessage({ text: rawText, images: queuedModeRequest.images }, lockedTarget, {
17967
+ var queuedBranchPath = Array.isArray(queuedModeRequest.branchPath)
17968
+ ? queuedModeRequest.branchPath
17969
+ : String(queuedModeRequest.branchPath || '').split('>').filter(Boolean);
17970
+ var queueResult = await api.sendMessage({
17971
+ text: rawText,
17972
+ images: queuedModeRequest.images,
17973
+ branchPath: queuedBranchPath,
17974
+ branchNodeId: String(queuedBranchPath[queuedBranchPath.length - 1] || '')
17975
+ }, lockedTarget, {
17880
17976
  clientMessageId: queuedModeRequest.clientMessageId,
17881
17977
  inputMode: 'next',
17882
17978
  requestedMode: requestedMode,
@@ -18073,12 +18169,6 @@ window.sendMessage = async function(modeOverride, queuedText, opts) {
18073
18169
  updateSubmitButtonState();
18074
18170
  var executionMode = opts.goalDeclaration || requestedMode === 'goal' ? 'build'
18075
18171
  : ((opts.forceBuild || idleBuildNextImmediate) && requestedMode === 'build' ? 'build' : requestedMode);
18076
- // The command freezes its mode and delivery policy; selector persistence
18077
- // must not rewrite the mode of an already running target before acceptance.
18078
- if (api.setModel && state.model !== state._syncedModel) {
18079
- var selectedModelResult = await api.setModel(state.model);
18080
- if (selectedModelResult != null) state._syncedModel = state.model;
18081
- }
18082
18172
  if (consumeProvisionalStop(lockedTarget, localRunId)) {
18083
18173
  // Stop/Escape won before the backend accepted the prompt. Do not send the
18084
18174
  // provider request after the user has already cancelled it.
@@ -18122,10 +18212,20 @@ window.sendMessage = async function(modeOverride, queuedText, opts) {
18122
18212
  try {
18123
18213
  var activationBeforeSend = pendingConversationActivation(lockedTarget);
18124
18214
  if (activationBeforeSend) await activationBeforeSend;
18215
+ // Bind the model actually shown in the composer to the exact target
18216
+ // conversation after its activation snapshot restored the remembered
18217
+ // selection. This makes the visible provider/model authoritative for the
18218
+ // send and prevents a stale renderer selection from reaching another
18219
+ // conversation's remembered deployment.
18220
+ if (api.setModel && state.model && state.model !== state._syncedModel) {
18221
+ var selectedModelResult = await api.setModel(state.model);
18222
+ if (selectedModelResult != null) state._syncedModel = state.model;
18223
+ }
18125
18224
  var sendPromise = api.sendMessage(requestMessage, lockedTarget, {
18126
18225
  requestedMode: requestedMode, inputMode: effectiveInputMode,
18127
18226
  goalObjective: opts.goalObjective || '',
18128
- clientMessageId: String(requestMessage && requestMessage.clientMessageId || localRunId)
18227
+ clientMessageId: String(requestMessage && requestMessage.clientMessageId || localRunId),
18228
+ model: state.model
18129
18229
  });
18130
18230
  if (requestedMode === 'goal') activateSubmittedGoal(opts.goalObjective || rawText);
18131
18231
  var r = await sendPromise;
@@ -19843,9 +19943,13 @@ function trapNewmarkDialogFocus(event, container) {
19843
19943
  }
19844
19944
 
19845
19945
  window.openSubWin = function(title, html) {
19946
+ // A replacement can open during the outgoing glass's 210ms exit. Retire
19947
+ // that exit before it can hide the newly mounted content or restore focus.
19948
+ var replacingExitingWindow = !!els['sub-win']._liquidExitTimer;
19949
+ cancelLiquidPopupExit(els['sub-win']);
19846
19950
  var overlayOpen = els['sub-win-overlay'].classList.contains('open');
19847
19951
  if (!overlayOpen && document.activeElement && typeof document.activeElement.focus === 'function') subWindowOriginFocus = document.activeElement;
19848
- if (overlayOpen && !state.restoringSubWindow && state.activeSubWindowView) {
19952
+ if (overlayOpen && !replacingExitingWindow && !state.restoringSubWindow && state.activeSubWindowView) {
19849
19953
  if (!state.subWindowStack) state.subWindowStack = [];
19850
19954
  state.subWindowStack.push({
19851
19955
  view: Object.assign({}, state.activeSubWindowView),
@@ -20504,6 +20608,7 @@ function applyUiAppearance() {
20504
20608
  }
20505
20609
  applyGlassPresentation(glassPresentationForOpacity(state.glassLevel));
20506
20610
  window.refreshTitlebarThemeIcon();
20611
+ document.querySelectorAll('webview[data-newmark-browser-runtime-key]').forEach(syncBlankBrowserGuestTheme);
20507
20612
  }
20508
20613
 
20509
20614
  window.setTheme = function(value) {
@@ -21207,7 +21312,7 @@ window.validateAllModels = function() {
21207
21312
  return state.modelValidationResults;
21208
21313
  }).catch(function(err) {
21209
21314
  document.body.classList.remove('model-evaluating');
21210
- var failedHtml = '<div style="color:#ff7777;font-size:12px;">' + esc(t('model.validationFailed')) + ': ' + esc(err.message) + '</div>';
21315
+ var failedHtml = '<div style="color:var(--nm-state-danger);font-size:12px;">' + esc(t('model.validationFailed')) + ': ' + esc(err.message) + '</div>';
21211
21316
  var body = document.getElementById('sub-win-body');
21212
21317
  if (body && document.getElementById('model-validation-progress') && els['sub-win-overlay'].classList.contains('open')) {
21213
21318
  body.innerHTML = failedHtml;
@@ -21483,7 +21588,7 @@ window.showAutomationWindow = function() {
21483
21588
  '<div style="display:flex;align-items:center;gap:6px;margin-bottom:4px;">' +
21484
21589
  '<span style="font-size:11px;flex:1;color:var(--text);">' + esc(a.prompt) + '</span>' +
21485
21590
  '<button class="sec-btn" style="font-size:9px;padding:2px 8px;" onclick="window.toggleAutomation(' + ai + ')">' + (a.active ? esc(t('automation.active')) : esc(t('automation.paused'))) + '</button>' +
21486
- '<button class="sec-btn" style="font-size:0;padding:2px 8px;color:#ff6666;" onclick="window.deleteAutomation(' + ai + ')" title="' + escAttr(t('common.delete')) + '">' + iconSvg('trash', t('common.delete'), 'tiny') + '</button>' +
21591
+ '<button class="sec-btn" style="font-size:0;padding:2px 8px;color:var(--nm-state-danger);" onclick="window.deleteAutomation(' + ai + ')" title="' + escAttr(t('common.delete')) + '">' + iconSvg('trash', t('common.delete'), 'tiny') + '</button>' +
21487
21592
  '</div>' +
21488
21593
  '<div style="font-size:10px;color:var(--text-dim);">' + esc(t('message.model')) + ': ' + esc(a.model) + ' | ' + esc(t('automation.condition')) + ': ' + a.condition + '</div>' +
21489
21594
  '</div>';
@@ -21563,7 +21668,7 @@ window.showAutomationWindow = async function() {
21563
21668
  var wakeHtml = '';
21564
21669
  if (wake) {
21565
21670
  wakeHtml = '<div id="automation-wake-status" style="padding:8px 10px;margin-bottom:8px;border-radius:8px;background:var(--glass-bg-1);border:1px solid var(--glass-border-1);font-size:10px;color:var(--text-dim);">' +
21566
- '<div style="color:var(--text);font-size:11px;margin-bottom:3px;">' + esc(t('automation.osWake')) + ': ' + (wake.registered ? '<span style="color:var(--accent2);">' + esc(t('automation.registered')) + '</span>' : (wake.active ? '<span style="color:#ffd166;">' + esc(t('automation.pending')) + '</span>' : '<span>' + esc(t('automation.inactive')) + '</span>')) + '</div>' +
21671
+ '<div style="color:var(--text);font-size:11px;margin-bottom:3px;">' + esc(t('automation.osWake')) + ': ' + (wake.registered ? '<span style="color:var(--accent2);">' + esc(t('automation.registered')) + '</span>' : (wake.active ? '<span style="color:var(--nm-state-warning);">' + esc(t('automation.pending')) + '</span>' : '<span>' + esc(t('automation.inactive')) + '</span>')) + '</div>' +
21567
21672
  '<div>' + esc(t('automation.task')) + ': ' + esc(wake.taskName || '-') + '</div>' +
21568
21673
  '<div>' + esc(t('automation.next')) + ': ' + esc(wake.nextRunAt ? new Date(wake.nextRunAt).toLocaleString(uiLocale()) : '-') + '</div>' +
21569
21674
  (wake.skippedReason ? '<div>' + esc(wake.skippedReason) + '</div>' : '') +
@@ -21583,12 +21688,12 @@ window.showAutomationWindow = async function() {
21583
21688
  '<div style="display:flex;align-items:center;gap:6px;margin-bottom:5px;">' +
21584
21689
  '<span style="font-size:11px;flex:1;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;" title="' + esc(a.prompt || '') + '">' + esc(a.prompt || '') + '</span>' +
21585
21690
  '<button class="sec-btn" style="font-size:9px;padding:2px 8px;' + (a.active ? 'Active' : 'Paused') + '" onclick="window.toggleAutomationById(' + JSON.stringify(a.id).replace(/"/g, '&quot;') + ')">' + (a.active ? esc(t('automation.active')) : esc(t('automation.paused'))) + '</button>' +
21586
- '<button class="sec-btn" style="font-size:9px;padding:2px 8px;color:#ff6666;" onclick="window.deleteAutomationById(' + JSON.stringify(a.id).replace(/"/g, '&quot;') + ')">' + esc(t('common.delete')) + '</button>' +
21691
+ '<button class="sec-btn" style="font-size:9px;padding:2px 8px;color:var(--nm-state-danger);" onclick="window.deleteAutomationById(' + JSON.stringify(a.id).replace(/"/g, '&quot;') + ')">' + esc(t('common.delete')) + '</button>' +
21587
21692
  '</div>' +
21588
21693
  '<div style="font-size:10px;color:var(--text-dim);">' + esc(t('automation.workspace')) + ': ' + esc(a.workspaceName || a.workspaceId || '-') + ' | ' + esc(t('automation.conversation')) + ': ' + esc(a.conversationMode === 'existing' ? (a.conversationId || '-') : t('automation.newConversation')) + '</div>' +
21589
21694
  '<div style="font-size:10px;color:var(--text-dim);">' + esc(t('message.model')) + ': ' + esc(a.model || t('common.current')) + ' | ' + esc(t('automation.type')) + ': ' + esc(a.condition || 'once') + ' | ' + esc(t('automation.status')) + ': ' + status + ' | ' + esc(t('automation.runs')) + ': ' + (a.runCount || 0) + '</div>' +
21590
21695
  '<div style="font-size:10px;color:var(--text-dim);">' + esc(t('automation.next')) + ': ' + esc(next) + ' | ' + esc(t('automation.last')) + ': ' + esc(last) + '</div>' +
21591
- (lastLine ? '<div style="font-size:10px;color:' + (a.lastError ? '#ff7777' : 'var(--text-dim)') + ';margin-top:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">' + esc(lastLine) + '</div>' : '') +
21696
+ (lastLine ? '<div style="font-size:10px;color:' + (a.lastError ? 'var(--nm-state-danger)' : 'var(--text-dim)') + ';margin-top:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">' + esc(lastLine) + '</div>' : '') +
21592
21697
  '</div>';
21593
21698
  }
21594
21699
  }
@@ -21748,7 +21853,7 @@ function renderFlowItem(work, idx, expanded) {
21748
21853
  '<button class="sec-btn" style="flex:1;font-size:10px;" onclick="window.addFlowComp(' + idx + ',\'logic\')">+ ' + esc(t('flow.logic')) + '</button>' +
21749
21854
  '<button class="sec-btn primary" style="flex:0;padding:6px 8px;font-size:10px;" onclick="window.runFlowWork(' + idx + ')" title="' + escAttr(t('flow.run')) + '">' + esc(t('flow.run')) + '</button>' +
21750
21855
  '<button class="sec-btn" style="flex:0;padding:6px 8px;font-size:10px;" onclick="window.saveFlowToDisk(' + idx + ')" title="' + escAttr(t('flow.save')) + '">' + esc(t('flow.save')) + '</button>' +
21751
- '<button class="sec-btn" style="flex:0;padding:6px 8px;font-size:0;color:#ff6666;" onclick="window.deleteFlowWork(' + idx + ')" title="' + escAttr(t('flow.deleteWorkflow')) + '">' + iconSvg('trash', t('flow.deleteWorkflow'), 'tiny') + '</button>' +
21856
+ '<button class="sec-btn" style="flex:0;padding:6px 8px;font-size:0;color:var(--nm-state-danger);" onclick="window.deleteFlowWork(' + idx + ')" title="' + escAttr(t('flow.deleteWorkflow')) + '">' + iconSvg('trash', t('flow.deleteWorkflow'), 'tiny') + '</button>' +
21752
21857
  '</div>' + componentsHtml +
21753
21858
  '</div></div>';
21754
21859
  }
@@ -23495,6 +23600,29 @@ function createBrowserGuestElement(target) {
23495
23600
  return view;
23496
23601
  }
23497
23602
 
23603
+ window.setBrowserViewport = function(contentsId, viewport) {
23604
+ var views = document.querySelectorAll('webview[data-newmark-browser-runtime-key]');
23605
+ var view = Array.from(views).find(function(candidate) { try { return candidate.getWebContentsId() === contentsId; } catch (_) { return false; } });
23606
+ if (!view || !view.parentElement) return false;
23607
+ var frame = view.parentElement;
23608
+ view._newmarkViewport = viewport;
23609
+ frame.style.position = 'relative';
23610
+ frame.style.overflow = 'hidden';
23611
+ view.style.position = 'absolute';
23612
+ view.style.left = '0'; view.style.top = '0'; view.style.flex = 'none';
23613
+ var fit = function() {
23614
+ if (!view.isConnected) { view._newmarkViewportObserver?.disconnect(); return; }
23615
+ var size = view._newmarkViewport;
23616
+ view.style.width = size.width + 'px'; view.style.height = size.height + 'px';
23617
+ view.style.transformOrigin = 'top left';
23618
+ var scale = Math.min(1, (frame.clientWidth || size.width) / size.width, (frame.clientHeight || size.height) / size.height);
23619
+ view.style.transform = 'scale(' + scale + ')';
23620
+ };
23621
+ if (!view._newmarkViewportObserver) { view._newmarkViewportObserver = new ResizeObserver(fit); view._newmarkViewportObserver.observe(frame); }
23622
+ fit();
23623
+ return true;
23624
+ };
23625
+
23498
23626
  function restoreBrowserPlaceholder() {
23499
23627
  var frame = els['browser-frame'] || document.getElementById('browser-frame');
23500
23628
  if (!frame || document.getElementById('browser-guest-placeholder')) return;
@@ -23551,12 +23679,28 @@ function navigateBrowserView(view, url) {
23551
23679
  }
23552
23680
  }
23553
23681
 
23682
+ window.normalizeBrowserAddress = function(raw) {
23683
+ var value = String(raw || '').trim().replace(/^files:\/\//i, 'file://');
23684
+ if (!value || /[\x00-\x1f]/.test(value)) throw new Error('Invalid browser address');
23685
+ if (/^[a-z]:[\\/]/i.test(value) || value.startsWith('/')) {
23686
+ var localPath = value.replace(/\\/g, '/');
23687
+ value = 'file://' + (localPath.startsWith('/') ? '' : '/') + localPath.split('/').map(function(part, index) {
23688
+ return index === 0 && /^[a-z]:$/i.test(part) ? part : encodeURIComponent(part);
23689
+ }).join('/');
23690
+ }
23691
+ if (!/^[a-z][a-z0-9+.-]*:/i.test(value) || /^[^/:]+:\d+(?:\/|$)/.test(value)) value = 'https://' + value;
23692
+ var parsed = new URL(value);
23693
+ if (parsed.protocol === 'file:') {
23694
+ if (parsed.hostname && parsed.hostname !== 'localhost') throw new Error('Use a local file path');
23695
+ } else if (!['http:', 'https:', 'newmark-preview:'].includes(parsed.protocol) && value !== 'about:blank') {
23696
+ throw new Error('Unsupported browser address');
23697
+ }
23698
+ return parsed.href;
23699
+ };
23700
+
23554
23701
  window.navigateBrowser = function(url) {
23555
23702
  var target = currentConversationTarget();
23556
- url = String(url || '').trim();
23557
- if (!/^(?:https?:\/\/|about:blank$|newmark-preview:\/\/)/i.test(url)) {
23558
- url = 'https://' + url;
23559
- }
23703
+ url = window.normalizeBrowserAddress(url);
23560
23704
  if (state.browserPreviewToken && url !== state.browserPreviewUrl) window.revokeBrowserPreviewCapability();
23561
23705
  rememberBrowserUrl(url, true, target);
23562
23706
  var input = els['browser-url'];
@@ -23590,6 +23734,19 @@ window.browserReload = function() {
23590
23734
  if (view && view.reload) view.reload();
23591
23735
  };
23592
23736
 
23737
+ // The local empty browser canvas belongs to the app theme. Visited pages
23738
+ // retain their own styling; recheck the URL inside the guest after navigation.
23739
+ function syncBlankBrowserGuestTheme(view) {
23740
+ try {
23741
+ if (!view._newmarkDomReady || view.getURL() !== 'about:blank') return;
23742
+ var palette = getComputedStyle(document.documentElement);
23743
+ var bg = palette.getPropertyValue('--bg').trim();
23744
+ var fg = palette.getPropertyValue('--text').trim();
23745
+ var script = 'if(location.href === "about:blank"){document.documentElement.style.background=' + JSON.stringify(bg) + ';document.documentElement.style.color=' + JSON.stringify(fg) + ';}';
23746
+ view.executeJavaScript(script).catch(function() {});
23747
+ } catch {}
23748
+ }
23749
+
23593
23750
  function initializeBrowserGuest(view) {
23594
23751
  var target = arguments.length > 1 && arguments[1] ? arguments[1] : currentConversationTarget();
23595
23752
  var targetKey = browserTargetKey(target);
@@ -23608,6 +23765,7 @@ function initializeBrowserGuest(view) {
23608
23765
  currentUrl = view.getURL ? view.getURL() : '';
23609
23766
  if (input && currentUrl && currentUrl !== 'about:blank') input.value = currentUrl;
23610
23767
  } catch {}
23768
+ syncBlankBrowserGuestTheme(view);
23611
23769
  rememberBrowserUrl(currentUrl, false, target);
23612
23770
  if (view._newmarkReadySettled) return;
23613
23771
  var registration = Promise.resolve({ accepted: true });
@@ -23676,7 +23834,7 @@ function initializeBrowserGuest(view) {
23676
23834
  // reload control, so a popup page could not be refreshed in-place.
23677
23835
  view.addEventListener('new-window', function(e) {
23678
23836
  var popupUrl = String(e && e.url || '').trim();
23679
- if (!popupUrl || !/^(?:https?:|about:blank|newmark-preview:)/i.test(popupUrl)) return;
23837
+ if (!popupUrl || !/^(?:https?:|file:|about:blank|newmark-preview:)/i.test(popupUrl)) return;
23680
23838
  if (e && typeof e.preventDefault === 'function') e.preventDefault();
23681
23839
  rememberBrowserUrl(popupUrl, true, target);
23682
23840
  var input = els['browser-url'];
@@ -23863,6 +24021,7 @@ function syncBackendConversation() {
23863
24021
  }
23864
24022
  if (conv && api.ensureConversation) {
23865
24023
  var requestedTarget = currentConversationTarget(conv.id);
24024
+ var modelRevisionAtActivation = Number(state.modelSelectionRevision || 0);
23866
24025
  state.activeBackendConversationId = conv.id;
23867
24026
  var historyPromise = loadActiveConversationMessages(conv.id);
23868
24027
  requestedLoadGeneration = state.conversationLoadGeneration;
@@ -23871,7 +24030,7 @@ function syncBackendConversation() {
23871
24030
  var id = (s && s.conversationId) || conv.id;
23872
24031
  if (!requestIsCurrent() || String(id) !== requestedConversationId) return;
23873
24032
  state.activeBackendConversationId = id;
23874
- applyConversationSnapshot(s, id, { preserveReadableHistory: true });
24033
+ applyConversationSnapshot(s, id, { preserveReadableHistory: true, modelRevision: modelRevisionAtActivation });
23875
24034
  }).catch(function(error) {
23876
24035
  if (!requestIsCurrent()) return;
23877
24036
  showUiNotice(
@@ -24403,12 +24562,13 @@ window.newConversation = function(workspaceReference, branchCommunication) {
24403
24562
  renderConversations();
24404
24563
  els['chat-area'].innerHTML = '';
24405
24564
  var target = currentConversationTarget(id);
24565
+ var modelRevisionAtActivation = Number(state.modelSelectionRevision || 0);
24406
24566
  var activation = api.activateConversation ? api.activateConversation(target) : (api.ensureConversation ? api.ensureConversation(target) : Promise.resolve(null));
24407
24567
  var activationKey = runtimeKeyFor(target.workspaceId, target.conversationId);
24408
24568
  var activationReady = activation.then(function(s) {
24409
24569
  if (createdWorkspaceKey !== currentWorkspaceKey() || id !== String(activeConversationId() || 'default')) return;
24410
24570
  state.activeBackendConversationId = String((s && s.conversationId) || id);
24411
- if (s) applyConversationSnapshot(s, id, { preserveReadableHistory: true });
24571
+ if (s) applyConversationSnapshot(s, id, { preserveReadableHistory: true, modelRevision: modelRevisionAtActivation });
24412
24572
  if (branchCommunication && api.setConversationBranchCommunication) {
24413
24573
  api.setConversationBranchCommunication(target, true).then(function() {
24414
24574
  var convsNow = currentWorkspaceConversations();
@@ -24805,7 +24965,7 @@ window.loadMemoryLabVisualization = function(reason, options) {
24805
24965
  return result;
24806
24966
  }).catch(function(err) {
24807
24967
  var target = document.getElementById('memory-lab-panel');
24808
- if (target) target.innerHTML = '<div style="color:#ff7777;font-size:12px;">' + esc(err.message || String(err)) + '</div>';
24968
+ if (target) target.innerHTML = '<div style="color:var(--nm-state-danger);font-size:12px;">' + esc(err.message || String(err)) + '</div>';
24809
24969
  throw err;
24810
24970
  }).finally(function() {
24811
24971
  if (generation === state.memoryLabVisualizationGeneration) state.memoryLabVisualizationLoading = false;
@@ -26961,7 +27121,7 @@ window.openWsSettings = function() {
26961
27121
  '</select></div>' +
26962
27122
  '<div style="display:flex;gap:6px;margin-top:8px;">' +
26963
27123
  '<button class="sec-btn" style="flex:1;" onclick="window.showNewWorkspaceDialog()">+ ' + esc(t('left.new')) + '</button>' +
26964
- '<button class="sec-btn" style="flex:1;color:#ff6666;" onclick="window.deleteCurrentWorkspace()">' + esc(t('common.delete')) + '</button>' +
27124
+ '<button class="sec-btn" style="flex:1;color:var(--nm-state-danger);" onclick="window.deleteCurrentWorkspace()">' + esc(t('common.delete')) + '</button>' +
26965
27125
  '</div>';
26966
27126
  window.openSubWin(t('workspace.settingsTitle') + ' - ' + esc(wsName), html);
26967
27127
 
@@ -28205,6 +28365,7 @@ function schedulePostStartupUiRendering() {
28205
28365
  var selectedContextGeneration = state.conversationLoadGeneration;
28206
28366
  var selectedContextModel = this.value;
28207
28367
  state.model = selectedContextModel;
28368
+ state.modelSelectionRevision = Number(state.modelSelectionRevision || 0) + 1;
28208
28369
  window.syncModelSelectSurface();
28209
28370
  if (state.model !== state._syncedModel) {
28210
28371
  var modelResult = await api.setModel(selectedContextModel);
@@ -28313,4 +28474,3 @@ function schedulePostStartupUiRendering() {
28313
28474
  </body>
28314
28475
  </html>
28315
28476
 
28316
-