newmark-agent 0.3.12 → 0.4.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.
- package/dist/cli-commands.d.ts +1 -0
- package/dist/cli-commands.js +11 -2
- package/dist/context/domain/types.d.ts +37 -0
- package/dist/context/services/context-orchestrator.js +2 -0
- package/dist/conversation-utility-host.bundle.cjs +1147 -131
- package/dist/conversation-utility-host.js +3 -0
- package/dist/core/agent.d.ts +139 -5
- package/dist/core/agent.js +962 -82
- package/dist/core/agentKernel/agent-loop.js +29 -3
- package/dist/core/agentKernel/types.d.ts +7 -0
- package/dist/core/agentKernelRunner.d.ts +2 -0
- package/dist/core/agentKernelRunner.js +121 -19
- package/dist/core/conversationKernel.d.ts +5 -0
- package/dist/core/conversationKernel.js +29 -0
- package/dist/core/dshCompatibility.d.ts +198 -0
- package/dist/core/dshCompatibility.js +600 -0
- package/dist/core/electronUtilityAgentClient.d.ts +4 -0
- package/dist/core/electronUtilityAgentClient.js +4 -0
- package/dist/core/electronUtilityRuntimePool.d.ts +8 -0
- package/dist/core/electronUtilityRuntimePool.js +14 -0
- package/dist/core/mcpManager.d.ts +1 -0
- package/dist/core/mcpManager.js +100 -10
- package/dist/core/subagent.d.ts +6 -0
- package/dist/core/subagent.js +22 -1
- package/dist/core/toolPolicy.d.ts +6 -0
- package/dist/core/toolPolicy.js +49 -1
- package/dist/core/types.d.ts +1 -1
- package/dist/core/utilityAgentProtocol.d.ts +8 -1
- package/dist/core/workspace.d.ts +9 -0
- package/dist/core/workspace.js +48 -1
- package/dist/core/wslAgentClient.d.ts +4 -0
- package/dist/core/wslAgentClient.js +4 -0
- package/dist/core/wslAgentProtocol.d.ts +8 -1
- package/dist/core/wslAgentRuntimePool.d.ts +8 -0
- package/dist/core/wslAgentRuntimePool.js +15 -0
- package/dist/launcher.js +8 -0
- package/dist/llm/provider.d.ts +1 -1
- package/dist/llm/provider.js +4 -3
- package/dist/main.js +163 -11
- package/dist/preload.js +11 -0
- package/dist/providers/chat-completions.adapter.js +41 -15
- package/dist/providers/provider-adapter.d.ts +3 -0
- package/dist/toolchain/registry/tool-registry.d.ts +13 -1
- package/dist/toolchain/registry/tool-registry.js +8 -0
- package/dist/toolchain/registry-seeder.js +51 -5
- package/dist/tools/index.js +11 -2
- package/dist/tools/nativeTools.js +5 -1
- package/dist/ui/index.html +2530 -205
- package/dist/ui/lucide-sprite.svg +26 -0
- package/dist/wsl-agent-host.bundle.cjs +1147 -131
- package/dist/wsl-agent-host.js +3 -0
- package/package.json +4 -2
package/dist/ui/index.html
CHANGED
|
@@ -136,6 +136,21 @@ try {
|
|
|
136
136
|
--duration-normal: 250ms;
|
|
137
137
|
--duration-slow: 400ms;
|
|
138
138
|
|
|
139
|
+
/* Stable Newmark semantic layers. Components depend on meaning, not on an
|
|
140
|
+
upstream developer-preview framework's private tokens or brand palette. */
|
|
141
|
+
--nm-surface-canvas: var(--app-bg);
|
|
142
|
+
--nm-surface-sunken: var(--glass-bg-1);
|
|
143
|
+
--nm-surface-raised: var(--glass-bg-2);
|
|
144
|
+
--nm-surface-overlay: var(--modal-surface);
|
|
145
|
+
--nm-label-primary: var(--text-bright);
|
|
146
|
+
--nm-label-secondary: var(--text);
|
|
147
|
+
--nm-label-tertiary: var(--text-dim);
|
|
148
|
+
--nm-state-info: var(--accent);
|
|
149
|
+
--nm-state-success: var(--accent2);
|
|
150
|
+
--nm-state-warning: #f4c95d;
|
|
151
|
+
--nm-state-danger: #ff7785;
|
|
152
|
+
--nm-focus-ring: 0 0 0 3px var(--accent-glow);
|
|
153
|
+
|
|
139
154
|
/* Layout sizes */
|
|
140
155
|
--left-width: 200px;
|
|
141
156
|
--left-secondary-width: 220px;
|
|
@@ -338,6 +353,19 @@ html, body {
|
|
|
338
353
|
border: 0;
|
|
339
354
|
}
|
|
340
355
|
button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus { outline: none; }
|
|
356
|
+
:where(button, select, input, textarea, [contenteditable], [tabindex]):focus-visible {
|
|
357
|
+
outline: 2px solid var(--accent);
|
|
358
|
+
outline-offset: 2px;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
@media (prefers-reduced-motion: reduce) {
|
|
362
|
+
*, *::before, *::after {
|
|
363
|
+
scroll-behavior: auto !important;
|
|
364
|
+
animation-duration: 0.01ms !important;
|
|
365
|
+
animation-iteration-count: 1 !important;
|
|
366
|
+
transition-duration: 0.01ms !important;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
341
369
|
::-webkit-scrollbar { width: 4px; height: 4px; }
|
|
342
370
|
::-webkit-scrollbar-track { background: transparent; }
|
|
343
371
|
::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.10); border-radius: var(--radius-full); }
|
|
@@ -527,6 +555,24 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
527
555
|
flex-shrink: 0;
|
|
528
556
|
}
|
|
529
557
|
|
|
558
|
+
button.lt-item,
|
|
559
|
+
button.left-nav-icon {
|
|
560
|
+
border: 0;
|
|
561
|
+
background: transparent;
|
|
562
|
+
font-family: var(--font-ui);
|
|
563
|
+
text-align: left;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
button.left-nav-icon { width: calc(100% - 12px); }
|
|
567
|
+
|
|
568
|
+
.lt-item:focus-visible,
|
|
569
|
+
.left-nav-icon:focus-visible {
|
|
570
|
+
outline: none;
|
|
571
|
+
color: var(--text-bright);
|
|
572
|
+
background: var(--control-hover-bg);
|
|
573
|
+
box-shadow: inset 0 0 0 2px var(--accent);
|
|
574
|
+
}
|
|
575
|
+
|
|
530
576
|
.lt-item:hover {
|
|
531
577
|
background: var(--glass-bg-2);
|
|
532
578
|
color: var(--text);
|
|
@@ -749,6 +795,14 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
749
795
|
overflow: hidden;
|
|
750
796
|
}
|
|
751
797
|
|
|
798
|
+
button.left-ws-item {
|
|
799
|
+
width: 100%;
|
|
800
|
+
border: 0;
|
|
801
|
+
background: transparent;
|
|
802
|
+
font-family: var(--font-ui);
|
|
803
|
+
text-align: left;
|
|
804
|
+
}
|
|
805
|
+
|
|
752
806
|
.left-ws-item:hover { background: var(--glass-bg-2); }
|
|
753
807
|
.left-ws-item.active { background: var(--accent-glow); color: var(--text-bright); }
|
|
754
808
|
|
|
@@ -1055,6 +1109,11 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
1055
1109
|
}
|
|
1056
1110
|
|
|
1057
1111
|
.resize-handle:hover { background: var(--accent); }
|
|
1112
|
+
.resize-handle:focus-visible {
|
|
1113
|
+
outline: none;
|
|
1114
|
+
background: var(--accent);
|
|
1115
|
+
box-shadow: 0 0 0 2px var(--accent-glow);
|
|
1116
|
+
}
|
|
1058
1117
|
|
|
1059
1118
|
.resize-handle[data-side="left"] {
|
|
1060
1119
|
cursor: col-resize;
|
|
@@ -1883,12 +1942,12 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
1883
1942
|
|
|
1884
1943
|
.terminal-output {
|
|
1885
1944
|
flex: 1;
|
|
1886
|
-
overflow
|
|
1945
|
+
overflow: auto;
|
|
1887
1946
|
padding: 8px 12px;
|
|
1888
1947
|
font-family: var(--font-mono);
|
|
1889
1948
|
font-size: 12px;
|
|
1890
1949
|
color: var(--text-dim);
|
|
1891
|
-
white-space: pre
|
|
1950
|
+
white-space: pre;
|
|
1892
1951
|
line-height: 1.5;
|
|
1893
1952
|
}
|
|
1894
1953
|
|
|
@@ -2419,6 +2478,8 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
2419
2478
|
.conversation-work-subagent-chip.completed .conversation-work-subagent-status { color: var(--accent2); }
|
|
2420
2479
|
.conversation-work-command-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2421
2480
|
.conversation-work-activity-detail { margin-top: 2px; color: color-mix(in srgb, var(--text-dim) 88%, transparent); font: 10px/1.45 var(--font-mono); white-space: pre-wrap; word-break: break-word; }
|
|
2481
|
+
.conversation-work-thought-text { margin: 4px 0 5px 24px; color: color-mix(in srgb, var(--text-dim) 92%, transparent); font: 11px/1.55 var(--font-mono); white-space: pre-wrap; word-break: break-word; }
|
|
2482
|
+
.conversation-work-thought-pending { color: var(--text-dim); font-style: italic; }
|
|
2422
2483
|
.conversation-work-files { margin-top: 1px; }
|
|
2423
2484
|
.conversation-work-files > summary { display: grid; grid-template-columns: 17px minmax(0,1fr) 10px; gap: 7px; align-items: center; min-height: 26px; cursor: pointer; list-style: none; color: var(--text); font-size: 11px; font-weight: 600; }
|
|
2424
2485
|
.conversation-work-files > summary::-webkit-details-marker,
|
|
@@ -2524,7 +2585,7 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
2524
2585
|
.shell-block {
|
|
2525
2586
|
margin: 8px 0;
|
|
2526
2587
|
border-radius: var(--radius-md);
|
|
2527
|
-
background:
|
|
2588
|
+
background: var(--nm-surface-sunken);
|
|
2528
2589
|
border: 1px solid var(--glass-border-1);
|
|
2529
2590
|
overflow: hidden;
|
|
2530
2591
|
}
|
|
@@ -2550,7 +2611,7 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
2550
2611
|
font-family: var(--font-mono);
|
|
2551
2612
|
font-size: 12px;
|
|
2552
2613
|
color: var(--text-dim);
|
|
2553
|
-
white-space: pre
|
|
2614
|
+
white-space: pre;
|
|
2554
2615
|
line-height: 1.5;
|
|
2555
2616
|
max-height: 400px;
|
|
2556
2617
|
overflow: auto;
|
|
@@ -2583,6 +2644,23 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
2583
2644
|
.diff-block-header .arrow { transition: transform var(--duration-fast) var(--ease-out-expo); font-size: 9px; }
|
|
2584
2645
|
.diff-block.collapsed .diff-block-header .arrow { transform: rotate(-90deg); }
|
|
2585
2646
|
|
|
2647
|
+
button.shell-block-header,
|
|
2648
|
+
button.diff-block-header,
|
|
2649
|
+
button.flow-item-header,
|
|
2650
|
+
button.work-review-head,
|
|
2651
|
+
button.todo-item {
|
|
2652
|
+
width: 100%;
|
|
2653
|
+
border: 0;
|
|
2654
|
+
font-family: var(--font-ui);
|
|
2655
|
+
text-align: left;
|
|
2656
|
+
}
|
|
2657
|
+
|
|
2658
|
+
button.shell-block-header { background: rgba(255,255,255,0.03); }
|
|
2659
|
+
button.diff-block-header,
|
|
2660
|
+
button.flow-item-header,
|
|
2661
|
+
button.work-review-head,
|
|
2662
|
+
button.todo-item { background: transparent; }
|
|
2663
|
+
|
|
2586
2664
|
.diff-stat { display: flex; gap: 8px; margin-left: auto; }
|
|
2587
2665
|
.diff-add { color: var(--accent2); font-size: 11px; }
|
|
2588
2666
|
.diff-del { color: #ff6666; font-size: 11px; }
|
|
@@ -2958,6 +3036,8 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
2958
3036
|
.work-review-actions { display:flex; align-items:center; gap:5px; }
|
|
2959
3037
|
.work-review-btn { height:28px; padding:0 10px; border:1px solid var(--glass-border-2); border-radius:6px; background:transparent; color:var(--text); cursor:pointer; font:600 11px var(--font); }
|
|
2960
3038
|
.work-review-btn:hover { background:var(--control-hover-bg); border-color:var(--border-hover); }
|
|
3039
|
+
.work-review-toggle { width:28px; height:28px; display:inline-flex; align-items:center; justify-content:center; padding:0; border:1px solid transparent; border-radius:6px; background:transparent; color:var(--text-dim); cursor:pointer; }
|
|
3040
|
+
.work-review-toggle:hover { background:var(--control-hover-bg); border-color:var(--border-hover); }
|
|
2961
3041
|
.work-review-list { border-top:1px solid var(--glass-border-1); }
|
|
2962
3042
|
.work-review.collapsed .work-review-list { display: none; }
|
|
2963
3043
|
.work-review-head { cursor: pointer; }
|
|
@@ -3057,6 +3137,16 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
3057
3137
|
font: 9px var(--font-mono);
|
|
3058
3138
|
}
|
|
3059
3139
|
|
|
3140
|
+
.conv-branch-comm-badge {
|
|
3141
|
+
flex: 0 0 auto;
|
|
3142
|
+
padding: 2px 5px;
|
|
3143
|
+
border-radius: 999px;
|
|
3144
|
+
background: color-mix(in srgb, var(--accent) 16%, transparent);
|
|
3145
|
+
color: var(--accent);
|
|
3146
|
+
font: 9px var(--font-mono);
|
|
3147
|
+
white-space: nowrap;
|
|
3148
|
+
}
|
|
3149
|
+
|
|
3060
3150
|
.conv-runtime-badge.running { color: var(--accent2); }
|
|
3061
3151
|
.conv-runtime-badge.stopping,
|
|
3062
3152
|
.conv-runtime-badge.force_restarting { color: #ffd27a; }
|
|
@@ -3391,9 +3481,47 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
3391
3481
|
flex: 0 0 auto;
|
|
3392
3482
|
}
|
|
3393
3483
|
|
|
3484
|
+
#context-inspector {
|
|
3485
|
+
position: absolute;
|
|
3486
|
+
right: -8px;
|
|
3487
|
+
bottom: calc(100% + 10px);
|
|
3488
|
+
z-index: 80;
|
|
3489
|
+
display: none;
|
|
3490
|
+
width: min(320px, calc(100vw - 24px));
|
|
3491
|
+
padding: 12px;
|
|
3492
|
+
border: 1px solid var(--glass-border-2);
|
|
3493
|
+
border-radius: var(--radius-lg);
|
|
3494
|
+
background: var(--modal-surface);
|
|
3495
|
+
box-shadow: var(--shadow-lg);
|
|
3496
|
+
backdrop-filter: blur(var(--glass-blur-3)) saturate(1.08);
|
|
3497
|
+
color: var(--text);
|
|
3498
|
+
font-size: 10px;
|
|
3499
|
+
line-height: 1.45;
|
|
3500
|
+
}
|
|
3501
|
+
#context-inspector.open { display: block; animation: model-menu-in 150ms var(--ease-out-expo); }
|
|
3502
|
+
.context-inspector-head { display:flex; align-items:flex-start; gap:8px; margin-bottom:10px; }
|
|
3503
|
+
.context-inspector-title { flex:1; min-width:0; color:var(--text-bright); font-size:12px; font-weight:700; }
|
|
3504
|
+
.context-inspector-subtitle { margin-top:2px; color:var(--text-dim); font-size:9px; }
|
|
3505
|
+
.context-inspector-close { width:22px; height:22px; padding:0; border:0; border-radius:var(--radius-sm); background:transparent; color:var(--text-dim); cursor:pointer; }
|
|
3506
|
+
.context-inspector-close:hover, .context-inspector-close:focus-visible { color:var(--text-bright); background:var(--control-hover-bg); outline:none; }
|
|
3507
|
+
.context-inspector-meter { height:6px; margin:8px 0 10px; overflow:hidden; border-radius:var(--radius-full); background:rgba(168,168,168,.18); }
|
|
3508
|
+
.context-inspector-meter-fill { height:100%; border-radius:inherit; background:var(--accent); transition:width var(--duration-normal) var(--ease-out-expo), background var(--duration-fast) var(--ease-out-expo); }
|
|
3509
|
+
.context-inspector-grid { display:grid; grid-template-columns:1fr 1fr; gap:7px; }
|
|
3510
|
+
.context-inspector-cell { padding:7px 8px; border:1px solid var(--glass-border-1); border-radius:var(--radius-sm); background:var(--glass-bg-1); }
|
|
3511
|
+
.context-inspector-label { display:block; color:var(--text-dim); font-size:9px; }
|
|
3512
|
+
.context-inspector-value { display:block; margin-top:2px; color:var(--text-bright); font:600 10px var(--font-mono); }
|
|
3513
|
+
.context-inspector-section { margin-top:10px; padding-top:9px; border-top:1px solid var(--glass-border-1); }
|
|
3514
|
+
.context-inspector-section-title { color:var(--text-bright); font-size:10px; font-weight:650; }
|
|
3515
|
+
.context-inspector-meta { margin-top:3px; color:var(--text-dim); overflow-wrap:anywhere; }
|
|
3516
|
+
.context-inspector-actions { display:flex; align-items:center; gap:7px; margin-top:10px; }
|
|
3517
|
+
.context-inspector-actions .sec-btn { flex:1; min-width:0; }
|
|
3518
|
+
.context-inspector-actions .sec-btn:disabled { opacity:.55; cursor:wait; }
|
|
3519
|
+
|
|
3394
3520
|
#context-token-ring {
|
|
3395
3521
|
width: 16px;
|
|
3396
3522
|
height: 16px;
|
|
3523
|
+
padding: 0;
|
|
3524
|
+
border: 0;
|
|
3397
3525
|
border-radius: 50%;
|
|
3398
3526
|
background: conic-gradient(#a8a8a8 0deg, rgba(168,168,168,0.22) 0deg);
|
|
3399
3527
|
cursor: default;
|
|
@@ -3601,6 +3729,124 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
3601
3729
|
50% { box-shadow: 0 0 24px rgba(91,120,255,0.5), 0 0 60px rgba(91,120,255,0.15); }
|
|
3602
3730
|
}
|
|
3603
3731
|
|
|
3732
|
+
/* ============================================================
|
|
3733
|
+
KEYBOARD COMMAND SURFACE
|
|
3734
|
+
============================================================ */
|
|
3735
|
+
.command-surface-overlay {
|
|
3736
|
+
position: fixed;
|
|
3737
|
+
inset: 0;
|
|
3738
|
+
z-index: 320;
|
|
3739
|
+
display: flex;
|
|
3740
|
+
align-items: flex-start;
|
|
3741
|
+
justify-content: center;
|
|
3742
|
+
padding: min(12vh, 96px) 18px 18px;
|
|
3743
|
+
background: color-mix(in srgb, var(--nm-surface-canvas) 62%, transparent);
|
|
3744
|
+
opacity: 0;
|
|
3745
|
+
visibility: hidden;
|
|
3746
|
+
pointer-events: none;
|
|
3747
|
+
transition: opacity var(--duration-fast) var(--ease-out-expo), visibility 0ms linear var(--duration-fast);
|
|
3748
|
+
}
|
|
3749
|
+
|
|
3750
|
+
.command-surface-overlay.open {
|
|
3751
|
+
opacity: 1;
|
|
3752
|
+
visibility: visible;
|
|
3753
|
+
pointer-events: auto;
|
|
3754
|
+
transition-delay: 0ms, 0ms;
|
|
3755
|
+
}
|
|
3756
|
+
|
|
3757
|
+
.command-surface {
|
|
3758
|
+
width: min(680px, calc(100vw - 36px));
|
|
3759
|
+
max-height: min(680px, calc(100vh - 132px));
|
|
3760
|
+
display: flex;
|
|
3761
|
+
flex-direction: column;
|
|
3762
|
+
overflow: hidden;
|
|
3763
|
+
border: 1px solid var(--glass-border-2);
|
|
3764
|
+
border-radius: var(--radius-xl);
|
|
3765
|
+
background: var(--nm-surface-overlay);
|
|
3766
|
+
box-shadow: var(--shadow-lg);
|
|
3767
|
+
backdrop-filter: blur(var(--glass-blur-3)) saturate(150%);
|
|
3768
|
+
transform: translateY(-8px) scale(0.985);
|
|
3769
|
+
transition: transform var(--duration-fast) var(--ease-out-expo);
|
|
3770
|
+
}
|
|
3771
|
+
|
|
3772
|
+
.command-surface-overlay.open .command-surface { transform: translateY(0) scale(1); }
|
|
3773
|
+
.command-surface-header { display:flex; align-items:flex-start; gap:12px; padding:14px 16px 10px; }
|
|
3774
|
+
.command-surface-heading { flex:1; min-width:0; }
|
|
3775
|
+
.command-surface-title { color:var(--text-bright); font-size:14px; font-weight:700; }
|
|
3776
|
+
.command-surface-subtitle { margin-top:3px; color:var(--text-dim); font-size:10px; line-height:1.45; }
|
|
3777
|
+
.command-surface-close { width:28px; height:28px; border:0; border-radius:var(--radius-sm); background:transparent; color:var(--text-dim); cursor:pointer; }
|
|
3778
|
+
.command-surface-close:hover { color:var(--text-bright); background:var(--control-hover-bg); }
|
|
3779
|
+
.command-search-wrap { padding:0 14px 12px; }
|
|
3780
|
+
.command-search {
|
|
3781
|
+
width:100%;
|
|
3782
|
+
height:40px;
|
|
3783
|
+
box-sizing:border-box;
|
|
3784
|
+
padding:0 12px;
|
|
3785
|
+
border:1px solid var(--glass-border-2);
|
|
3786
|
+
border-radius:var(--radius-md);
|
|
3787
|
+
background:var(--control-bg);
|
|
3788
|
+
color:var(--text);
|
|
3789
|
+
font:12px var(--font-ui);
|
|
3790
|
+
}
|
|
3791
|
+
.command-search:focus { border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-glow); }
|
|
3792
|
+
.command-list { min-height:96px; overflow:auto; padding:0 8px 8px; }
|
|
3793
|
+
.command-category { padding:9px 9px 5px; color:var(--text-dim); font-size:9px; font-weight:700; letter-spacing:.07em; text-transform:uppercase; }
|
|
3794
|
+
.command-option {
|
|
3795
|
+
width:100%;
|
|
3796
|
+
min-height:42px;
|
|
3797
|
+
display:grid;
|
|
3798
|
+
grid-template-columns:minmax(0,1fr) auto;
|
|
3799
|
+
align-items:center;
|
|
3800
|
+
gap:12px;
|
|
3801
|
+
padding:6px 9px;
|
|
3802
|
+
border:1px solid transparent;
|
|
3803
|
+
border-radius:var(--radius-md);
|
|
3804
|
+
background:transparent;
|
|
3805
|
+
color:var(--text);
|
|
3806
|
+
text-align:left;
|
|
3807
|
+
cursor:pointer;
|
|
3808
|
+
font-family:var(--font-ui);
|
|
3809
|
+
}
|
|
3810
|
+
.command-option.active,
|
|
3811
|
+
.command-option:hover { background:var(--control-hover-bg); border-color:var(--glass-border-1); }
|
|
3812
|
+
.command-option[aria-disabled="true"] { opacity:.48; cursor:not-allowed; }
|
|
3813
|
+
.command-option-title { display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:12px; }
|
|
3814
|
+
.command-option-context { display:block; margin-top:2px; color:var(--text-dim); font-size:9px; }
|
|
3815
|
+
.command-shortcuts { display:flex; justify-content:flex-end; gap:4px; }
|
|
3816
|
+
.command-key {
|
|
3817
|
+
min-width:22px;
|
|
3818
|
+
padding:3px 6px;
|
|
3819
|
+
border:1px solid var(--glass-border-2);
|
|
3820
|
+
border-bottom-color:var(--border-hover);
|
|
3821
|
+
border-radius:5px;
|
|
3822
|
+
background:var(--glass-bg-1);
|
|
3823
|
+
color:var(--text-dim);
|
|
3824
|
+
font:10px var(--font-mono);
|
|
3825
|
+
text-align:center;
|
|
3826
|
+
white-space:nowrap;
|
|
3827
|
+
}
|
|
3828
|
+
.command-empty { padding:24px 12px; color:var(--text-dim); font-size:11px; text-align:center; }
|
|
3829
|
+
.command-surface-footer { padding:8px 14px 10px; border-top:1px solid var(--glass-border-1); color:var(--text-dim); font-size:9px; }
|
|
3830
|
+
.shortcut-chord-hint {
|
|
3831
|
+
position:fixed;
|
|
3832
|
+
z-index:330;
|
|
3833
|
+
left:50%;
|
|
3834
|
+
bottom:22px;
|
|
3835
|
+
max-width:min(520px, calc(100vw - 32px));
|
|
3836
|
+
padding:7px 10px;
|
|
3837
|
+
border:1px solid var(--glass-border-2);
|
|
3838
|
+
border-radius:var(--radius-md);
|
|
3839
|
+
background:var(--modal-surface);
|
|
3840
|
+
color:var(--text);
|
|
3841
|
+
box-shadow:var(--shadow-md);
|
|
3842
|
+
font:10px var(--font-mono);
|
|
3843
|
+
opacity:0;
|
|
3844
|
+
visibility:hidden;
|
|
3845
|
+
transform:translate(-50%, 4px);
|
|
3846
|
+
transition:opacity var(--duration-fast) var(--ease-out-expo), transform var(--duration-fast) var(--ease-out-expo), visibility 0ms linear var(--duration-fast);
|
|
3847
|
+
}
|
|
3848
|
+
.shortcut-chord-hint.open { opacity:1; visibility:visible; transform:translate(-50%, 0); transition-delay:0ms; }
|
|
3849
|
+
|
|
3604
3850
|
/* ============================================================
|
|
3605
3851
|
SUB-WINDOW SYSTEM
|
|
3606
3852
|
============================================================ */
|
|
@@ -3702,6 +3948,7 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
3702
3948
|
}
|
|
3703
3949
|
|
|
3704
3950
|
.sub-win-close:hover { background: rgba(255,68,68,0.15); color: #ff6666; }
|
|
3951
|
+
.sub-win-close:focus-visible { outline:none; color:#ff7777; box-shadow:inset 0 0 0 2px currentColor; }
|
|
3705
3952
|
|
|
3706
3953
|
.sub-win-body {
|
|
3707
3954
|
flex: 1;
|
|
@@ -3734,6 +3981,81 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
3734
3981
|
|
|
3735
3982
|
.stab-btn:hover { background: rgba(255,255,255,0.05); color: var(--text); }
|
|
3736
3983
|
.stab-btn.active { background: rgba(91,120,255,0.12); color: var(--accent); border-color: rgba(91,120,255,0.25); }
|
|
3984
|
+
.stab-btn:focus-visible { outline:none; border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-glow); color:var(--text-bright); }
|
|
3985
|
+
|
|
3986
|
+
.plugin-tabs { overflow-x:auto; scrollbar-width:thin; }
|
|
3987
|
+
.plugin-tabs .stab-btn { flex:0 0 auto; }
|
|
3988
|
+
.plugin-panel { min-height:180px; margin-top:10px; }
|
|
3989
|
+
.plugin-panel-state { display:flex; align-items:flex-start; gap:10px; padding:14px; border:1px solid var(--glass-border-1); border-radius:var(--radius-md); background:var(--glass-bg-1); color:var(--text-dim); font-size:11px; line-height:1.5; }
|
|
3990
|
+
.plugin-panel-state::before { content:""; flex:0 0 auto; width:7px; height:7px; margin-top:5px; border-radius:50%; background:var(--nm-state-info); box-shadow:0 0 0 3px color-mix(in srgb, var(--nm-state-info) 14%, transparent); }
|
|
3991
|
+
.plugin-panel-state.error::before { background:var(--nm-state-danger); box-shadow:0 0 0 3px color-mix(in srgb, var(--nm-state-danger) 14%, transparent); }
|
|
3992
|
+
.plugin-panel-state.error { border-color:var(--notice-error-border); color:var(--notice-error-text); }
|
|
3993
|
+
.plugin-panel-state .sec-btn { flex:0 0 auto; margin-left:auto; }
|
|
3994
|
+
.plugin-toolbar { display:flex; align-items:center; gap:8px; margin-bottom:12px; }
|
|
3995
|
+
.plugin-toolbar-copy { flex:1; min-width:0; }
|
|
3996
|
+
.plugin-toolbar-title { color:var(--text-bright); font-size:13px; font-weight:650; }
|
|
3997
|
+
.plugin-toolbar-meta { margin-top:2px; color:var(--text-dim); font-size:10px; }
|
|
3998
|
+
.plugin-toolbar .sec-btn { flex:0 0 auto; }
|
|
3999
|
+
.plugin-search { width:min(220px, 38%); height:34px; padding:0 10px; border:1px solid var(--glass-border-2); border-radius:var(--radius-md); background:var(--control-bg); color:var(--text); font:11px var(--font-ui); }
|
|
4000
|
+
.plugin-search:focus { border-color:var(--accent); box-shadow:0 0 0 2px var(--accent-glow); }
|
|
4001
|
+
.plugin-section { margin-top:14px; }
|
|
4002
|
+
.plugin-section-head { display:flex; align-items:center; gap:8px; margin-bottom:8px; }
|
|
4003
|
+
.plugin-section-title { color:var(--text-bright); font-size:12px; font-weight:650; }
|
|
4004
|
+
.plugin-count-badge,
|
|
4005
|
+
.plugin-status-badge { display:inline-flex; align-items:center; min-height:20px; padding:1px 7px; border:1px solid var(--glass-border-2); border-radius:var(--radius-full); color:var(--text-dim); font-size:9px; font-weight:650; }
|
|
4006
|
+
.plugin-status-badge.enabled { border-color:color-mix(in srgb, var(--accent2) 45%, transparent); color:var(--accent2); }
|
|
4007
|
+
.plugin-status-badge.preview { border-color:color-mix(in srgb, var(--accent) 45%, transparent); color:var(--text-accent); }
|
|
4008
|
+
.plugin-empty { padding:18px 12px; border:1px dashed var(--glass-border-2); border-radius:var(--radius-md); color:var(--text-dim); text-align:center; font-size:11px; line-height:1.5; }
|
|
4009
|
+
.mcp-form-card { padding:12px; margin-bottom:14px; border:1px solid var(--glass-border-2); border-radius:var(--radius-md); background:var(--glass-bg-1); }
|
|
4010
|
+
.mcp-form-head { display:flex; align-items:flex-start; gap:10px; margin-bottom:12px; }
|
|
4011
|
+
.mcp-form-copy { flex:1; min-width:0; }
|
|
4012
|
+
.mcp-form-title { color:var(--text-bright); font-size:13px; font-weight:650; }
|
|
4013
|
+
.mcp-form-subtitle { margin-top:2px; color:var(--text-dim); font-size:10px; line-height:1.45; }
|
|
4014
|
+
.mcp-field-grid { display:grid; grid-template-columns:minmax(0,1fr) 130px; gap:10px; }
|
|
4015
|
+
.mcp-field { display:flex; flex-direction:column; gap:5px; margin-bottom:10px; }
|
|
4016
|
+
.mcp-field label { color:var(--text); font-size:10px; font-weight:600; }
|
|
4017
|
+
.mcp-input { width:100%; min-height:36px; padding:8px 10px; border:1px solid var(--glass-border-2); border-radius:var(--radius-md); background:var(--control-bg); color:var(--text); font:11px var(--font-ui); }
|
|
4018
|
+
textarea.mcp-input { min-height:76px; resize:vertical; font-family:var(--font-mono); line-height:1.5; }
|
|
4019
|
+
.mcp-input:focus { border-color:var(--accent); box-shadow:0 0 0 2px var(--accent-glow); }
|
|
4020
|
+
.mcp-field-help { margin-top:-1px; color:var(--text-dim); font-size:9px; line-height:1.45; word-break:break-word; }
|
|
4021
|
+
.mcp-enabled-check { display:inline-flex; align-items:center; gap:7px; color:var(--text); font-size:10px; cursor:pointer; }
|
|
4022
|
+
.mcp-enabled-check input { accent-color:var(--accent); }
|
|
4023
|
+
.mcp-form-actions { display:flex; align-items:center; justify-content:flex-end; gap:8px; margin-top:4px; }
|
|
4024
|
+
.mcp-form-actions .sec-btn { flex:0 0 auto; }
|
|
4025
|
+
.mcp-server-row { display:flex; align-items:center; gap:10px; padding:10px; margin:7px 0; border:1px solid var(--glass-border-1); border-radius:var(--radius-md); background:var(--glass-bg-1); }
|
|
4026
|
+
.mcp-server-copy { flex:1; min-width:0; }
|
|
4027
|
+
.mcp-server-title { display:flex; align-items:center; gap:6px; flex-wrap:wrap; color:var(--text-bright); font-size:12px; font-weight:650; }
|
|
4028
|
+
.mcp-server-meta { margin-top:4px; color:var(--text-dim); font:10px/1.45 var(--font-mono); overflow-wrap:anywhere; }
|
|
4029
|
+
.mcp-row-actions { display:flex; align-items:center; gap:5px; flex-wrap:wrap; justify-content:flex-end; }
|
|
4030
|
+
.mcp-row-actions .sec-btn { flex:0 0 auto; }
|
|
4031
|
+
.dsh-hero { padding:14px; border:1px solid var(--glass-border-2); border-radius:var(--radius-md); background:var(--glass-bg-1); }
|
|
4032
|
+
.dsh-hero-head { display:flex; align-items:flex-start; gap:10px; }
|
|
4033
|
+
.dsh-hero-copy { flex:1; min-width:0; }
|
|
4034
|
+
.dsh-title { color:var(--text-bright); font-size:14px; font-weight:700; }
|
|
4035
|
+
.dsh-description { margin-top:5px; color:var(--text-dim); font-size:11px; line-height:1.55; }
|
|
4036
|
+
.dsh-actions { display:flex; flex-wrap:wrap; gap:7px; margin-top:11px; }
|
|
4037
|
+
.dsh-actions .sec-btn { flex:0 0 auto; }
|
|
4038
|
+
.dsh-grid { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:10px; margin-top:10px; }
|
|
4039
|
+
.dsh-card { min-width:0; padding:11px; border:1px solid var(--glass-border-1); border-radius:var(--radius-md); background:var(--glass-bg-1); }
|
|
4040
|
+
.dsh-card-title { color:var(--text-bright); font-size:11px; font-weight:650; }
|
|
4041
|
+
.dsh-kv { display:grid; grid-template-columns:minmax(92px,auto) minmax(0,1fr); gap:5px 10px; margin-top:8px; font-size:10px; line-height:1.45; }
|
|
4042
|
+
.dsh-kv dt { color:var(--text-dim); }
|
|
4043
|
+
.dsh-kv dd { color:var(--text); overflow-wrap:anywhere; }
|
|
4044
|
+
.dsh-list { display:flex; flex-direction:column; gap:6px; margin-top:8px; }
|
|
4045
|
+
.dsh-list-item { padding:7px 8px; border:1px solid var(--glass-border-1); border-radius:var(--radius-sm); color:var(--text); font-size:10px; line-height:1.45; overflow-wrap:anywhere; }
|
|
4046
|
+
.dsh-list-item.warning { border-color:var(--notice-error-border); color:var(--notice-error-text); }
|
|
4047
|
+
.dsh-layer-profile { margin-top:10px; padding-top:9px; border-top:1px solid var(--glass-border-1); }
|
|
4048
|
+
.dsh-candidate-actions { display:flex; align-items:center; gap:7px; margin-top:7px; }
|
|
4049
|
+
.dsh-candidate-actions .sec-btn { flex:0 0 auto; }
|
|
4050
|
+
|
|
4051
|
+
@media (max-width: 560px) {
|
|
4052
|
+
.sub-win { width:calc(100vw - 20px); min-width:0; }
|
|
4053
|
+
.plugin-toolbar { align-items:stretch; flex-wrap:wrap; }
|
|
4054
|
+
.plugin-search { width:100%; order:3; }
|
|
4055
|
+
.mcp-field-grid, .dsh-grid { grid-template-columns:1fr; }
|
|
4056
|
+
.mcp-server-row { align-items:flex-start; flex-direction:column; }
|
|
4057
|
+
.mcp-row-actions { width:100%; justify-content:flex-start; }
|
|
4058
|
+
}
|
|
3737
4059
|
|
|
3738
4060
|
.stab-panel {
|
|
3739
4061
|
display: none;
|
|
@@ -4806,6 +5128,89 @@ html.newmark-memory-overview-viewer body {
|
|
|
4806
5128
|
|
|
4807
5129
|
.hidden { display: none !important; }
|
|
4808
5130
|
.no-select { user-select: none; -webkit-user-select: none; }
|
|
5131
|
+
|
|
5132
|
+
/* ============================================================
|
|
5133
|
+
NEWMARK CONVERSATION HIERARCHY (三级字体体系)
|
|
5134
|
+
最终回复 > Build 内联历史 > 工具调用 toolcall
|
|
5135
|
+
保持原有 DOM 结构不变,仅通过字体大小/行高/不透明度体现差异。
|
|
5136
|
+
============================================================ */
|
|
5137
|
+
|
|
5138
|
+
/* --- Level 1: 最终回复(最大、最醒目) --- */
|
|
5139
|
+
.chat-msg.assistant {
|
|
5140
|
+
font-size: 15px;
|
|
5141
|
+
line-height: 1.72;
|
|
5142
|
+
}
|
|
5143
|
+
|
|
5144
|
+
/* Build 块内的最终回复同样以 Level 1 呈现 */
|
|
5145
|
+
.chat-msg.run-final-response {
|
|
5146
|
+
font-size: 15px;
|
|
5147
|
+
line-height: 1.72;
|
|
5148
|
+
}
|
|
5149
|
+
|
|
5150
|
+
/* 用户消息保持可读的稍大字号 */
|
|
5151
|
+
.chat-msg.user {
|
|
5152
|
+
font-size: 14px;
|
|
5153
|
+
line-height: 1.65;
|
|
5154
|
+
}
|
|
5155
|
+
|
|
5156
|
+
/* --- Level 2: Build 内联历史(中等字号) --- */
|
|
5157
|
+
.conversation-work-event.narrative {
|
|
5158
|
+
font-size: 13px;
|
|
5159
|
+
line-height: 1.6;
|
|
5160
|
+
opacity: 0.9;
|
|
5161
|
+
}
|
|
5162
|
+
|
|
5163
|
+
/* Build 块标题保持中等偏小,作为历史导航 */
|
|
5164
|
+
.conversation-work-run-head {
|
|
5165
|
+
font-size: 12px;
|
|
5166
|
+
opacity: 0.78;
|
|
5167
|
+
}
|
|
5168
|
+
|
|
5169
|
+
/* --- Level 3: 工具调用 toolcall(最小、最淡、等宽) --- */
|
|
5170
|
+
.tool-event-summary {
|
|
5171
|
+
font-size: 11px;
|
|
5172
|
+
font-family: var(--font-mono);
|
|
5173
|
+
opacity: 0.78;
|
|
5174
|
+
}
|
|
5175
|
+
|
|
5176
|
+
.tool-event-content {
|
|
5177
|
+
font-size: 11px;
|
|
5178
|
+
font-family: var(--font-mono);
|
|
5179
|
+
line-height: 1.45;
|
|
5180
|
+
opacity: 0.72;
|
|
5181
|
+
color: var(--text-dim);
|
|
5182
|
+
}
|
|
5183
|
+
|
|
5184
|
+
/* 工具调用外的活动/状态项也归入 Level 3 */
|
|
5185
|
+
.conversation-work-event:not(.narrative):not(.guide):not(.error) {
|
|
5186
|
+
font-size: 11px;
|
|
5187
|
+
line-height: 1.45;
|
|
5188
|
+
opacity: 0.72;
|
|
5189
|
+
font-family: var(--font-mono);
|
|
5190
|
+
}
|
|
5191
|
+
|
|
5192
|
+
.conversation-work-event.activity-summary {
|
|
5193
|
+
font-size: 11px;
|
|
5194
|
+
}
|
|
5195
|
+
|
|
5196
|
+
/* 工具调用活动列表项保持最小字号 */
|
|
5197
|
+
.conversation-work-activity-item {
|
|
5198
|
+
font-size: 10.5px;
|
|
5199
|
+
opacity: 0.68;
|
|
5200
|
+
}
|
|
5201
|
+
|
|
5202
|
+
/* --- 层级间距调整,强化视觉层次 --- */
|
|
5203
|
+
.chat-msg.assistant { margin-top: 2px; }
|
|
5204
|
+
.chat-msg.run-final-response { margin-bottom: 6px; }
|
|
5205
|
+
.conversation-work-run { margin: 4px 0 7px; }
|
|
5206
|
+
|
|
5207
|
+
/* 浅色主题下放宽不透明度,保证可读性 */
|
|
5208
|
+
.light .tool-event-content,
|
|
5209
|
+
.light .tool-event-summary,
|
|
5210
|
+
.light .conversation-work-event:not(.narrative):not(.guide):not(.error) {
|
|
5211
|
+
opacity: 0.8;
|
|
5212
|
+
}
|
|
5213
|
+
|
|
4809
5214
|
</style>
|
|
4810
5215
|
</head>
|
|
4811
5216
|
<body>
|
|
@@ -4941,6 +5346,14 @@ html.newmark-memory-overview-viewer body {
|
|
|
4941
5346
|
<circle cx="15" cy="5" r="1" />
|
|
4942
5347
|
<circle cx="15" cy="19" r="1" />
|
|
4943
5348
|
</symbol>
|
|
5349
|
+
<symbol id="group" viewBox="0 0 24 24">
|
|
5350
|
+
<path d="M3 7V5c0-1.1.9-2 2-2h2" />
|
|
5351
|
+
<path d="M17 3h2c1.1 0 2 .9 2 2v2" />
|
|
5352
|
+
<path d="M21 17v2c0 1.1-.9 2-2 2h-2" />
|
|
5353
|
+
<path d="M7 21H5c-1.1 0-2-.9-2-2v-2" />
|
|
5354
|
+
<rect width="7" height="5" x="7" y="7" rx="1" />
|
|
5355
|
+
<rect width="7" height="5" x="10" y="12" rx="1" />
|
|
5356
|
+
</symbol>
|
|
4944
5357
|
<symbol id="image" viewBox="0 0 24 24">
|
|
4945
5358
|
<rect width="18" height="18" x="3" y="3" rx="2" ry="2" />
|
|
4946
5359
|
<circle cx="9" cy="9" r="2" />
|
|
@@ -4968,6 +5381,14 @@ html.newmark-memory-overview-viewer body {
|
|
|
4968
5381
|
<path d="m3 17 2 2 4-4" />
|
|
4969
5382
|
<path d="m3 7 2 2 4-4" />
|
|
4970
5383
|
</symbol>
|
|
5384
|
+
<symbol id="list" viewBox="0 0 24 24">
|
|
5385
|
+
<path d="M3 5h.01" />
|
|
5386
|
+
<path d="M3 12h.01" />
|
|
5387
|
+
<path d="M3 19h.01" />
|
|
5388
|
+
<path d="M8 5h13" />
|
|
5389
|
+
<path d="M8 12h13" />
|
|
5390
|
+
<path d="M8 19h13" />
|
|
5391
|
+
</symbol>
|
|
4971
5392
|
<symbol id="loader-circle" viewBox="0 0 24 24">
|
|
4972
5393
|
<path d="M21 12a9 9 0 1 1-6.219-8.56" />
|
|
4973
5394
|
</symbol>
|
|
@@ -5008,6 +5429,9 @@ html.newmark-memory-overview-viewer body {
|
|
|
5008
5429
|
<path d="m5 9-3 3 3 3" />
|
|
5009
5430
|
<path d="m9 5 3-3 3 3" />
|
|
5010
5431
|
</symbol>
|
|
5432
|
+
<symbol id="navigation" viewBox="0 0 24 24">
|
|
5433
|
+
<polygon points="3 11 22 2 13 21 11 13 3 11" />
|
|
5434
|
+
</symbol>
|
|
5011
5435
|
<symbol id="octagon-x" viewBox="0 0 24 24">
|
|
5012
5436
|
<path d="m15 9-6 6" />
|
|
5013
5437
|
<path d="M2.586 16.726A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2h6.624a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586z" />
|
|
@@ -5020,6 +5444,13 @@ html.newmark-memory-overview-viewer body {
|
|
|
5020
5444
|
<path d="M3 3h6l6 18h6" />
|
|
5021
5445
|
<path d="M14 3h7" />
|
|
5022
5446
|
</symbol>
|
|
5447
|
+
<symbol id="palette" viewBox="0 0 24 24">
|
|
5448
|
+
<path d="M12 22a1 1 0 0 1 0-20 10 9 0 0 1 10 9 5 5 0 0 1-5 5h-2.25a1.75 1.75 0 0 0-1.4 2.8l.3.4a1.75 1.75 0 0 1-1.4 2.8z" />
|
|
5449
|
+
<circle cx="13.5" cy="6.5" r=".5" fill="currentColor" />
|
|
5450
|
+
<circle cx="17.5" cy="10.5" r=".5" fill="currentColor" />
|
|
5451
|
+
<circle cx="6.5" cy="12.5" r=".5" fill="currentColor" />
|
|
5452
|
+
<circle cx="8.5" cy="7.5" r=".5" fill="currentColor" />
|
|
5453
|
+
</symbol>
|
|
5023
5454
|
<symbol id="panel-left-open" viewBox="0 0 24 24">
|
|
5024
5455
|
<rect width="18" height="18" x="3" y="3" rx="2" />
|
|
5025
5456
|
<path d="M9 3v18" />
|
|
@@ -5231,37 +5662,37 @@ html.newmark-memory-overview-viewer body {
|
|
|
5231
5662
|
<!-- Left Sidebar -->
|
|
5232
5663
|
<div id="left">
|
|
5233
5664
|
<div id="left-thumb">
|
|
5234
|
-
<
|
|
5235
|
-
<
|
|
5236
|
-
<
|
|
5237
|
-
<
|
|
5238
|
-
<
|
|
5239
|
-
<
|
|
5240
|
-
<
|
|
5665
|
+
<button type="button" class="lt-item" onclick="window.showNewConversationPage()" title="New conversation"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#message-square"></use></svg><span class="icon-only-label">New conversation</span></button>
|
|
5666
|
+
<button type="button" class="lt-item" onclick="window.showPluginList()" title="Plugins"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#plug"></use></svg><span class="icon-only-label">Plugins</span></button>
|
|
5667
|
+
<button type="button" class="lt-item" onclick="window.showMemoryLab()" title="Memory Lab"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#brain"></use></svg><span class="icon-only-label">Memory Lab</span></button>
|
|
5668
|
+
<button type="button" class="lt-item" onclick="window.showAutomationWindow()" title="Automation"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#calendar"></use></svg><span class="icon-only-label">Automation</span></button>
|
|
5669
|
+
<button type="button" class="lt-item" onclick="window.showFlowEditor()" title="Flow"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#workflow"></use></svg><span class="icon-only-label">Flow</span></button>
|
|
5670
|
+
<button type="button" class="lt-item" onclick="window.openSettings()" title="Settings"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#settings"></use></svg><span class="icon-only-label">Settings</span></button>
|
|
5671
|
+
<button type="button" class="lt-item" id="lt-ws-icon" onclick="window.toggleSecondarySidebar()" title="Workspaces"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#folder-open"></use></svg><span class="icon-only-label">Workspaces</span></button>
|
|
5241
5672
|
</div>
|
|
5242
5673
|
<div id="left-content">
|
|
5243
5674
|
<div style="padding:10px 12px 4px;font-size:10px;color:var(--text-dim);text-transform:uppercase;letter-spacing:0.05em;flex-shrink:0;">Tools</div>
|
|
5244
|
-
<
|
|
5675
|
+
<button type="button" class="left-nav-icon" onclick="window.showNewConversationPage()" title="New conversation">
|
|
5245
5676
|
<span class="icon"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#message-square"></use></svg></span><span>New chat</span>
|
|
5246
|
-
</
|
|
5247
|
-
<
|
|
5677
|
+
</button>
|
|
5678
|
+
<button type="button" class="left-nav-icon" onclick="window.showPluginList()">
|
|
5248
5679
|
<span class="icon"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#plug"></use></svg></span><span>Plugins</span>
|
|
5249
|
-
</
|
|
5250
|
-
<
|
|
5680
|
+
</button>
|
|
5681
|
+
<button type="button" class="left-nav-icon" onclick="window.showMemoryLab()">
|
|
5251
5682
|
<span class="icon"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#brain"></use></svg></span><span>Memory Lab</span>
|
|
5252
|
-
</
|
|
5253
|
-
<
|
|
5683
|
+
</button>
|
|
5684
|
+
<button type="button" class="left-nav-icon" onclick="window.showAutomationWindow()">
|
|
5254
5685
|
<span class="icon"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#calendar"></use></svg></span><span>Automation</span>
|
|
5255
|
-
</
|
|
5256
|
-
<
|
|
5686
|
+
</button>
|
|
5687
|
+
<button type="button" class="left-nav-icon" onclick="window.showFlowEditor()">
|
|
5257
5688
|
<span class="icon"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#workflow"></use></svg></span><span>Flow</span>
|
|
5258
|
-
</
|
|
5259
|
-
<
|
|
5689
|
+
</button>
|
|
5690
|
+
<button type="button" class="left-nav-icon" onclick="window.openSettings()">
|
|
5260
5691
|
<span class="icon"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#settings"></use></svg></span><span>Settings</span>
|
|
5261
|
-
</
|
|
5692
|
+
</button>
|
|
5262
5693
|
<div id="left-ws-section">
|
|
5263
5694
|
<div id="left-ws-header">Workspaces</div>
|
|
5264
|
-
<div id="left-ws-list"></div>
|
|
5695
|
+
<div id="left-ws-list" role="list" aria-label="Workspaces"></div>
|
|
5265
5696
|
<button id="left-ws-add" class="icon-label-btn" onclick="window.showNewWorkspaceDialog()"><svg class="nm-icon tiny" aria-hidden="true" focusable="false"><use href="#plus"></use></svg><span>New</span></button>
|
|
5266
5697
|
</div>
|
|
5267
5698
|
</div>
|
|
@@ -5275,11 +5706,11 @@ html.newmark-memory-overview-viewer body {
|
|
|
5275
5706
|
<button class="sec-btn primary icon-label-btn" onclick="window.newConversation()"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#message-square"></use></svg><span>New chat</span></button>
|
|
5276
5707
|
<button class="sec-btn" onclick="window.toggleLeftSecondary()" title="Collapse" style="flex:0;padding:6px 8px;"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#chevron-left"></use></svg><span class="icon-only-label">Collapse</span></button>
|
|
5277
5708
|
</div>
|
|
5278
|
-
|
|
5709
|
+
<div id="conversation-list" role="list" aria-label="Conversations"></div>
|
|
5279
5710
|
</div>
|
|
5280
5711
|
|
|
5281
5712
|
<!-- Resize Handle: left area (left + secondary) to center-stack -->
|
|
5282
|
-
<div class="resize-handle" data-side="right" data-target="left" title="Resize left sidebar"></div>
|
|
5713
|
+
<div class="resize-handle" data-side="right" data-target="left" role="separator" aria-orientation="vertical" aria-label="Resize left sidebar" tabindex="0" title="Resize left sidebar"></div>
|
|
5283
5714
|
|
|
5284
5715
|
<!-- Center Stack (chat + terminal) -->
|
|
5285
5716
|
<div id="center-stack">
|
|
@@ -5305,7 +5736,7 @@ html.newmark-memory-overview-viewer body {
|
|
|
5305
5736
|
<div id="todo-header" class="stack-row" onclick="window.toggleTodoCollapse()">
|
|
5306
5737
|
<span id="todo-header-label" class="stack-title">Task</span>
|
|
5307
5738
|
<span class="stack-actions">
|
|
5308
|
-
<button class="stack-icon-btn" onclick="event.stopPropagation();window.toggleTodoCollapse()" title="Expand tasks"><svg class="nm-icon tiny" aria-hidden="true" focusable="false"><use href="#chevron-up"></use></svg><span class="icon-only-label">Expand tasks</span></button>
|
|
5739
|
+
<button class="stack-icon-btn" aria-expanded="false" aria-controls="todo-list" onclick="event.stopPropagation();window.toggleTodoCollapse()" title="Expand tasks"><svg class="nm-icon tiny" aria-hidden="true" focusable="false"><use href="#chevron-up"></use></svg><span class="icon-only-label">Expand tasks</span></button>
|
|
5309
5740
|
</span>
|
|
5310
5741
|
</div>
|
|
5311
5742
|
<div id="todo-list"></div>
|
|
@@ -5317,7 +5748,7 @@ html.newmark-memory-overview-viewer body {
|
|
|
5317
5748
|
<span id="queue-header-label" class="stack-title">Next</span>
|
|
5318
5749
|
<span class="stack-actions">
|
|
5319
5750
|
<button class="stack-icon-btn" id="queue-pause-btn" onclick="event.stopPropagation();window.toggleQueuePause()" title="Pause queue" aria-pressed="false"><svg class="nm-icon tiny" aria-hidden="true" focusable="false"><use href="#pause"></use></svg><span class="icon-only-label">Pause queue</span></button>
|
|
5320
|
-
<button class="stack-icon-btn" id="queue-expand-btn" onclick="event.stopPropagation();window.toggleQueuePanel()" title="Expand queue"><svg class="nm-icon tiny" aria-hidden="true" focusable="false"><use href="#chevron-up"></use></svg><span class="icon-only-label">Expand queue</span></button>
|
|
5751
|
+
<button class="stack-icon-btn" id="queue-expand-btn" aria-expanded="false" aria-controls="queue-list" onclick="event.stopPropagation();window.toggleQueuePanel()" title="Expand queue"><svg class="nm-icon tiny" aria-hidden="true" focusable="false"><use href="#chevron-up"></use></svg><span class="icon-only-label">Expand queue</span></button>
|
|
5321
5752
|
</span>
|
|
5322
5753
|
</div>
|
|
5323
5754
|
<div id="queue-list"></div>
|
|
@@ -5361,8 +5792,9 @@ html.newmark-memory-overview-viewer body {
|
|
|
5361
5792
|
<div class="model-select-menu" id="model-select-menu" role="listbox" aria-label="Model" popover="manual"></div>
|
|
5362
5793
|
</div>
|
|
5363
5794
|
<div class="context-token-wrap">
|
|
5364
|
-
<
|
|
5795
|
+
<button type="button" id="context-token-ring" title="Context tokens" aria-haspopup="dialog" aria-expanded="false" onclick="window.toggleContextInspector()" onmouseenter="window.showContextWindowTooltip()" onmouseleave="window.hideContextWindowTooltip()" onfocus="window.showContextWindowTooltip()" onblur="window.hideContextWindowTooltip()"><span class="icon-only-label">Context tokens</span></button>
|
|
5365
5796
|
<div id="context-token-tooltip"></div>
|
|
5797
|
+
<div id="context-inspector" role="dialog" aria-label="Context management" aria-live="polite"></div>
|
|
5366
5798
|
</div>
|
|
5367
5799
|
<select class="tool-select" id="intel-select">
|
|
5368
5800
|
<option value="low">low</option>
|
|
@@ -5376,7 +5808,7 @@ html.newmark-memory-overview-viewer body {
|
|
|
5376
5808
|
<button class="mode-toggle-btn active" data-mode="guide" onclick="window.setInputMode('guide')">Guide</button>
|
|
5377
5809
|
<button class="mode-toggle-btn" data-mode="next" onclick="window.setInputMode('next')">Next</button>
|
|
5378
5810
|
</div>
|
|
5379
|
-
<button id="submit-btn" onclick="window.submitCurrentAction()" title="Send"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#send"></use></svg><span class="icon-only-label">Send</span></button>
|
|
5811
|
+
<button id="submit-btn" onclick="window.submitCurrentAction('click')" title="Send"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#send"></use></svg><span class="icon-only-label">Send</span></button>
|
|
5380
5812
|
</div>
|
|
5381
5813
|
</div>
|
|
5382
5814
|
</div>
|
|
@@ -5384,7 +5816,7 @@ html.newmark-memory-overview-viewer body {
|
|
|
5384
5816
|
<!-- Bottom Terminal -->
|
|
5385
5817
|
<div id="bottom" class="open">
|
|
5386
5818
|
<div id="bottom-header">
|
|
5387
|
-
<div id="terminal-tabs"></div>
|
|
5819
|
+
<div id="terminal-tabs" role="tablist" aria-label="Terminals"></div>
|
|
5388
5820
|
<select id="terminal-shell-select" onchange="window.spawnTerminal(this.value)">
|
|
5389
5821
|
<option value="powershell" data-platform-shell="win32">PowerShell</option>
|
|
5390
5822
|
<option value="cmd" data-platform-shell="win32">CMD</option>
|
|
@@ -5402,7 +5834,7 @@ html.newmark-memory-overview-viewer body {
|
|
|
5402
5834
|
<div class="terminal-output"><span style="color:var(--text-dim);opacity:0.5;">Terminal ready</span></div>
|
|
5403
5835
|
<div class="terminal-input-row">
|
|
5404
5836
|
<span class="terminal-prompt">PS></span>
|
|
5405
|
-
<input class="terminal-input" type="text" placeholder="Enter command..." onfocus="window.ensureTerminalStarted&&window.ensureTerminalStarted()" onkeydown="if(event.key==='Enter')window.terminalSend()">
|
|
5837
|
+
<input class="terminal-input" type="text" placeholder="Enter command..." onfocus="window.ensureTerminalStarted&&window.ensureTerminalStarted()" onkeydown="if(event.key==='Enter'&&!event.isComposing&&event.key!=='Process'&&event.keyCode!==229)window.terminalSend()">
|
|
5406
5838
|
</div>
|
|
5407
5839
|
</div>
|
|
5408
5840
|
</div>
|
|
@@ -5410,25 +5842,25 @@ html.newmark-memory-overview-viewer body {
|
|
|
5410
5842
|
</div>
|
|
5411
5843
|
|
|
5412
5844
|
<!-- Right Resize Handle -->
|
|
5413
|
-
<div class="resize-handle" data-side="left" data-target="right" title="Resize right sidebar"></div>
|
|
5845
|
+
<div class="resize-handle" data-side="left" data-target="right" role="separator" aria-orientation="vertical" aria-label="Resize right sidebar" tabindex="0" title="Resize right sidebar"></div>
|
|
5414
5846
|
|
|
5415
5847
|
<!-- Right Sidebar -->
|
|
5416
5848
|
<div id="right" class="open">
|
|
5417
|
-
<div id="right-tabs">
|
|
5418
|
-
<button class="tab-btn active" data-tab="file-tree" onclick="window.switchRightTab('file-tree')" title="Files"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#folder"></use></svg><span class="icon-only-label">Files</span></button>
|
|
5419
|
-
<button class="tab-btn" data-tab="editor" onclick="window.switchRightTab('editor')" title="Editor"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#square-pen"></use></svg><span class="icon-only-label">Editor</span></button>
|
|
5420
|
-
<button class="tab-btn" data-tab="plan" onclick="window.switchRightTab('plan')" title="Conversation plan"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#list-checks"></use></svg><span class="icon-only-label">Conversation plan</span></button>
|
|
5421
|
-
<button class="tab-btn" data-tab="subagent" onclick="window.switchRightTab('subagent')" title="Subagents"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#bot"></use></svg><span class="icon-only-label">Subagents</span></button>
|
|
5422
|
-
<button class="tab-btn" data-tab="browser" onclick="window.switchRightTab('browser')" title="Browser"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#globe"></use></svg><span class="icon-only-label">Browser</span></button>
|
|
5849
|
+
<div id="right-tabs" role="tablist" aria-label="Right sidebar">
|
|
5850
|
+
<button class="tab-btn active" id="right-tab-file-tree" role="tab" aria-selected="true" aria-controls="panel-file-tree" tabindex="0" data-tab="file-tree" onclick="window.switchRightTab('file-tree')" onkeydown="window.handleRightTabKey(event)" title="Files"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#folder"></use></svg><span class="icon-only-label">Files</span></button>
|
|
5851
|
+
<button class="tab-btn" id="right-tab-editor" role="tab" aria-selected="false" aria-controls="panel-editor" tabindex="-1" data-tab="editor" onclick="window.switchRightTab('editor')" onkeydown="window.handleRightTabKey(event)" title="Editor"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#square-pen"></use></svg><span class="icon-only-label">Editor</span></button>
|
|
5852
|
+
<button class="tab-btn" id="right-tab-plan" role="tab" aria-selected="false" aria-controls="panel-plan" tabindex="-1" data-tab="plan" onclick="window.switchRightTab('plan')" onkeydown="window.handleRightTabKey(event)" title="Conversation plan"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#list-checks"></use></svg><span class="icon-only-label">Conversation plan</span></button>
|
|
5853
|
+
<button class="tab-btn" id="right-tab-subagent" role="tab" aria-selected="false" aria-controls="panel-subagent" tabindex="-1" data-tab="subagent" onclick="window.switchRightTab('subagent')" onkeydown="window.handleRightTabKey(event)" title="Subagents"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#bot"></use></svg><span class="icon-only-label">Subagents</span></button>
|
|
5854
|
+
<button class="tab-btn" id="right-tab-browser" role="tab" aria-selected="false" aria-controls="panel-browser" tabindex="-1" data-tab="browser" onclick="window.switchRightTab('browser')" onkeydown="window.handleRightTabKey(event)" title="Browser"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#globe"></use></svg><span class="icon-only-label">Browser</span></button>
|
|
5423
5855
|
<div class="tab-divider"></div>
|
|
5424
5856
|
<button class="tab-btn" onclick="window.toggleRight()" title="Close right sidebar"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#x"></use></svg><span class="icon-only-label">Close right sidebar</span></button>
|
|
5425
5857
|
</div>
|
|
5426
5858
|
<div id="right-content">
|
|
5427
|
-
<div class="tab-panel active" id="panel-file-tree">
|
|
5859
|
+
<div class="tab-panel active" id="panel-file-tree" role="tabpanel" aria-labelledby="right-tab-file-tree">
|
|
5428
5860
|
<div style="font-size:11px;color:var(--text-dim);margin-bottom:8px;">Workspace file tree</div>
|
|
5429
|
-
<div id="file-tree-container"></div>
|
|
5861
|
+
<div id="file-tree-container" role="tree"></div>
|
|
5430
5862
|
</div>
|
|
5431
|
-
<div class="tab-panel" id="panel-editor">
|
|
5863
|
+
<div class="tab-panel" id="panel-editor" role="tabpanel" aria-labelledby="right-tab-editor" hidden>
|
|
5432
5864
|
<div class="editor-toolbar">
|
|
5433
5865
|
<button class="et-btn" onclick="window.saveEditor()" title="Save" aria-label="Save"><svg class="nm-icon" aria-hidden="true" focusable="false"><use href="#save"></use></svg></button>
|
|
5434
5866
|
<button class="et-btn editor-view-btn" id="editor-md-toggle" onclick="window.toggleEditorMarkdownPreview()" title="Markdown preview" aria-label="Markdown preview"><svg class="nm-icon" aria-hidden="true" focusable="false"><use href="#book-open"></use></svg></button>
|
|
@@ -5444,22 +5876,22 @@ html.newmark-memory-overview-viewer body {
|
|
|
5444
5876
|
<div class="editor-status"><span class="editor-vim-mode" id="editor-vim-mode">INSERT</span><span id="editor-language">text</span><span id="editor-position">1:1</span><span style="margin-left:auto" id="editor-dirty"></span></div>
|
|
5445
5877
|
</div>
|
|
5446
5878
|
</div>
|
|
5447
|
-
<div class="tab-panel" id="panel-plan">
|
|
5879
|
+
<div class="tab-panel" id="panel-plan" role="tabpanel" aria-labelledby="right-tab-plan" hidden>
|
|
5448
5880
|
<div class="right-section-head"><span class="right-section-title">Conversation plan</span><button class="archive-action-btn" onclick="window.refreshConversationPlan()">Refresh</button></div>
|
|
5449
5881
|
<div id="conversation-plan-content"></div>
|
|
5450
5882
|
<div class="right-section-head linked-plan-head"><span class="right-section-title">Linked plan</span><span class="right-row-meta" id="linked-plan-revision"></span></div>
|
|
5451
5883
|
<div id="linked-plan-content" class="linked-plan-reader md-rendered" aria-live="polite"></div>
|
|
5452
5884
|
</div>
|
|
5453
|
-
<div class="tab-panel" id="panel-subagent">
|
|
5885
|
+
<div class="tab-panel" id="panel-subagent" role="tabpanel" aria-labelledby="right-tab-subagent" hidden>
|
|
5454
5886
|
<div style="font-size:11px;color:var(--text-dim);margin-bottom:8px;">Subagents</div>
|
|
5455
5887
|
<div id="subagent-list"></div>
|
|
5456
5888
|
</div>
|
|
5457
|
-
<div class="tab-panel" id="panel-browser">
|
|
5889
|
+
<div class="tab-panel" id="panel-browser" role="tabpanel" aria-labelledby="right-tab-browser" hidden>
|
|
5458
5890
|
<div class="browser-url-bar">
|
|
5459
5891
|
<button class="shell-btn browser-action-btn" onclick="window.browserBack()" title="Back"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#chevron-left"></use></svg><span class="icon-only-label">Back</span></button>
|
|
5460
5892
|
<button class="shell-btn browser-action-btn" onclick="window.browserForward()" title="Forward"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#chevron-right"></use></svg><span class="icon-only-label">Forward</span></button>
|
|
5461
5893
|
<button class="shell-btn browser-action-btn" onclick="window.browserReload()" title="Reload"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#refresh-cw"></use></svg><span class="icon-only-label">Reload</span></button>
|
|
5462
|
-
<input class="browser-url-input" id="browser-url" placeholder="Enter URL..." onkeydown="if(event.key==='Enter')window.navigateBrowser(this.value)">
|
|
5894
|
+
<input class="browser-url-input" id="browser-url" placeholder="Enter URL..." onkeydown="if(event.key==='Enter'&&!event.isComposing&&event.key!=='Process'&&event.keyCode!==229)window.navigateBrowser(this.value)">
|
|
5463
5895
|
<button class="shell-btn" onclick="window.navigateBrowser(document.getElementById('browser-url').value)" title="Go"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#send"></use></svg><span class="icon-only-label">Go</span></button>
|
|
5464
5896
|
<button class="shell-btn" id="computer-use-toggle" onclick="window.toggleComputerUse()" title="ComputerUse: enabled for this conversation" aria-pressed="true">CU</button>
|
|
5465
5897
|
</div>
|
|
@@ -5476,7 +5908,7 @@ html.newmark-memory-overview-viewer body {
|
|
|
5476
5908
|
|
|
5477
5909
|
<!-- ========== SUB-WINDOW OVERLAY ========== -->
|
|
5478
5910
|
<div class="sub-win-overlay" id="sub-win-overlay" onclick="if(event.target===this)window.closeSubWin()">
|
|
5479
|
-
<div class="sub-win" id="sub-win">
|
|
5911
|
+
<div class="sub-win" id="sub-win" role="dialog" aria-modal="true" aria-labelledby="sub-win-title" tabindex="-1">
|
|
5480
5912
|
<div class="sub-win-header" id="sub-win-header">
|
|
5481
5913
|
<span class="sub-win-title" id="sub-win-title">Window</span>
|
|
5482
5914
|
<button class="sub-win-close" onclick="window.closeSubWin()" title="Close"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#x"></use></svg><span class="icon-only-label">Close</span></button>
|
|
@@ -5484,6 +5916,21 @@ html.newmark-memory-overview-viewer body {
|
|
|
5484
5916
|
<div class="sub-win-body" id="sub-win-body"></div>
|
|
5485
5917
|
</div>
|
|
5486
5918
|
</div>
|
|
5919
|
+
<div class="command-surface-overlay" id="command-surface-overlay" onclick="if(event.target===this)window.closeCommandSurface()">
|
|
5920
|
+
<section class="command-surface" id="command-surface" role="dialog" aria-modal="true" aria-labelledby="command-surface-title" tabindex="-1">
|
|
5921
|
+
<header class="command-surface-header">
|
|
5922
|
+
<div class="command-surface-heading">
|
|
5923
|
+
<div class="command-surface-title" id="command-surface-title"></div>
|
|
5924
|
+
<div class="command-surface-subtitle" id="command-surface-subtitle"></div>
|
|
5925
|
+
</div>
|
|
5926
|
+
<button type="button" class="command-surface-close" onclick="window.closeCommandSurface()" aria-label="Close"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#x"></use></svg></button>
|
|
5927
|
+
</header>
|
|
5928
|
+
<div class="command-search-wrap"><input class="command-search" id="command-search" type="search" autocomplete="off" role="combobox" aria-autocomplete="list" aria-expanded="true" aria-controls="command-list"></div>
|
|
5929
|
+
<div class="command-list" id="command-list" role="listbox"></div>
|
|
5930
|
+
<footer class="command-surface-footer" id="command-surface-footer"></footer>
|
|
5931
|
+
</section>
|
|
5932
|
+
</div>
|
|
5933
|
+
<div class="shortcut-chord-hint" id="shortcut-chord-hint" role="status" aria-live="polite"></div>
|
|
5487
5934
|
<script>
|
|
5488
5935
|
/* ============================================================
|
|
5489
5936
|
NEWMARK AGENT - Complete UI Controller v2.0
|
|
@@ -5579,6 +6026,8 @@ var state = {
|
|
|
5579
6026
|
automationItems: [],
|
|
5580
6027
|
contextCompression: null,
|
|
5581
6028
|
contextWindow: null,
|
|
6029
|
+
contextInspectorOpen: false,
|
|
6030
|
+
contextMutationPending: false,
|
|
5582
6031
|
flowWorks: [],
|
|
5583
6032
|
activeAgentRunning: false,
|
|
5584
6033
|
editorPath: '',
|
|
@@ -5596,6 +6045,9 @@ var state = {
|
|
|
5596
6045
|
editorCompletionText: '',
|
|
5597
6046
|
editorCompletionRequest: 0,
|
|
5598
6047
|
editorCompletionAnchor: null,
|
|
6048
|
+
editorCompletionCache: [],
|
|
6049
|
+
editorCompletionInFlight: false,
|
|
6050
|
+
editorCompletionStreamText: '',
|
|
5599
6051
|
editorCaretSignature: '',
|
|
5600
6052
|
editorPredictionEnabled: true,
|
|
5601
6053
|
editorCompletionTimer: null,
|
|
@@ -5651,7 +6103,14 @@ var state = {
|
|
|
5651
6103
|
githubOverviewPendingRepo: '',
|
|
5652
6104
|
mcpServers: [],
|
|
5653
6105
|
mcpDiscovered: [],
|
|
6106
|
+
dshCompatibility: null,
|
|
5654
6107
|
mcpEditingId: '',
|
|
6108
|
+
mcpDraft: null,
|
|
6109
|
+
mcpSearchQuery: '',
|
|
6110
|
+
mcpMutationPending: false,
|
|
6111
|
+
mcpMutationGeneration: 0,
|
|
6112
|
+
mcpFormFocusRequested: false,
|
|
6113
|
+
pluginPanelGeneration: 0,
|
|
5655
6114
|
skillMarketQuery: '',
|
|
5656
6115
|
memoryLab: null,
|
|
5657
6116
|
memoryLabComponentContents: {},
|
|
@@ -5720,6 +6179,48 @@ var NEWMARK_I18N = {
|
|
|
5720
6179
|
en: {
|
|
5721
6180
|
'app.ready': 'Ready',
|
|
5722
6181
|
'app.subtitle': 'Enter an instruction to begin. Enter sends. Shift+Enter inserts a newline.',
|
|
6182
|
+
'shortcuts.paletteTitle': 'Command palette',
|
|
6183
|
+
'shortcuts.helpTitle': 'Keyboard shortcuts',
|
|
6184
|
+
'shortcuts.paletteSubtitle': 'Search every registered Newmark GUI command. Shortcuts never replace standard editing keys.',
|
|
6185
|
+
'shortcuts.helpSubtitle': 'Common desktop keys plus conflict-safe Newmark command chords.',
|
|
6186
|
+
'shortcuts.searchCommands': 'Search commands...',
|
|
6187
|
+
'shortcuts.searchShortcuts': 'Search commands or shortcuts...',
|
|
6188
|
+
'shortcuts.noResults': 'No matching commands.',
|
|
6189
|
+
'shortcuts.footer': 'Up/Down navigate · Enter runs · Esc closes · Tab stays inside this dialog',
|
|
6190
|
+
'shortcuts.category.general': 'General',
|
|
6191
|
+
'shortcuts.category.navigation': 'Navigation',
|
|
6192
|
+
'shortcuts.category.workspace': 'Workspace and chat',
|
|
6193
|
+
'shortcuts.category.layout': 'Layout and focus',
|
|
6194
|
+
'shortcuts.category.input': 'Input and modes',
|
|
6195
|
+
'shortcuts.category.editor': 'Editor',
|
|
6196
|
+
'shortcuts.category.browser': 'Browser',
|
|
6197
|
+
'shortcuts.category.terminal': 'Terminal',
|
|
6198
|
+
'shortcuts.category.context': 'Context controls',
|
|
6199
|
+
'shortcuts.context.global': 'Application',
|
|
6200
|
+
'shortcuts.context.prompt': 'Prompt',
|
|
6201
|
+
'shortcuts.context.editor': 'Editor only',
|
|
6202
|
+
'shortcuts.context.browser': 'Browser only',
|
|
6203
|
+
'shortcuts.context.terminal': 'Terminal only',
|
|
6204
|
+
'shortcuts.context.dialog': 'Dialog',
|
|
6205
|
+
'shortcuts.openPalette': 'Open command palette',
|
|
6206
|
+
'shortcuts.openHelp': 'Show keyboard shortcuts',
|
|
6207
|
+
'shortcuts.focusPrimary': 'Focus primary input',
|
|
6208
|
+
'shortcuts.focusNext': 'Focus next application region',
|
|
6209
|
+
'shortcuts.focusPrevious': 'Focus previous application region',
|
|
6210
|
+
'shortcuts.toggleLeft': 'Toggle left sidebar',
|
|
6211
|
+
'shortcuts.toggleWorkspacePanel': 'Toggle workspace and conversation panel',
|
|
6212
|
+
'shortcuts.toggleRight': 'Toggle right sidebar',
|
|
6213
|
+
'shortcuts.toggleTerminal': 'Toggle terminal',
|
|
6214
|
+
'shortcuts.nextConversation': 'Next conversation',
|
|
6215
|
+
'shortcuts.previousConversation': 'Previous conversation',
|
|
6216
|
+
'shortcuts.nextBranch': 'Next branch',
|
|
6217
|
+
'shortcuts.previousBranch': 'Previous branch',
|
|
6218
|
+
'shortcuts.scrollBottom': 'Scroll chat to bottom',
|
|
6219
|
+
'shortcuts.newTerminal': 'New terminal',
|
|
6220
|
+
'shortcuts.focusTerminal': 'Focus terminal input',
|
|
6221
|
+
'shortcuts.focusBrowserAddress': 'Focus browser address',
|
|
6222
|
+
'shortcuts.toggleTheme': 'Toggle light and dark theme',
|
|
6223
|
+
'shortcuts.chordHint': '{prefix} waiting for: {keys}',
|
|
5723
6224
|
'top.minimize': 'Minimize',
|
|
5724
6225
|
'top.maximize': 'Maximize',
|
|
5725
6226
|
'top.close': 'Close',
|
|
@@ -5731,12 +6232,14 @@ var NEWMARK_I18N = {
|
|
|
5731
6232
|
'left.flow': 'Flow',
|
|
5732
6233
|
'left.settings': 'Settings',
|
|
5733
6234
|
'left.workspaces': 'Workspaces',
|
|
6235
|
+
'left.conversations': 'Conversations',
|
|
5734
6236
|
'left.new': 'New',
|
|
5735
6237
|
'left.collapse': 'Collapse left sidebar',
|
|
5736
6238
|
'left.collapseSecondary': 'Collapse workspace panel',
|
|
5737
6239
|
'input.placeholder': 'Input instruction...',
|
|
5738
6240
|
'input.send': 'Send',
|
|
5739
6241
|
'input.stop': 'Stop',
|
|
6242
|
+
'input.continue': 'Continue',
|
|
5740
6243
|
'input.guide': 'Guide',
|
|
5741
6244
|
'input.next': 'Next',
|
|
5742
6245
|
'mode.build': 'Build',
|
|
@@ -6066,7 +6569,13 @@ var NEWMARK_I18N = {
|
|
|
6066
6569
|
'flow.noAvailable': 'No workflows are available to run.',
|
|
6067
6570
|
'flow.started': 'Flow started',
|
|
6068
6571
|
'plugins.title': 'Plugins',
|
|
6572
|
+
'plugins.tabMcp': 'MCP',
|
|
6573
|
+
'plugins.tabDsh': 'DSH Plugin',
|
|
6574
|
+
'plugins.tabSkills': 'Skills',
|
|
6575
|
+
'plugins.tabMarket': 'Market',
|
|
6576
|
+
'plugins.tabGithub': 'GitHub',
|
|
6069
6577
|
'plugins.mcp': 'MCP Management',
|
|
6578
|
+
'plugins.dsh': 'DSH Plugin',
|
|
6070
6579
|
'plugins.management': 'Skills Management',
|
|
6071
6580
|
'plugins.market': 'Skills Market',
|
|
6072
6581
|
'plugins.github': 'GitHub CLI',
|
|
@@ -6124,6 +6633,74 @@ var NEWMARK_I18N = {
|
|
|
6124
6633
|
'plugins.mcpNoServers': 'No user MCP servers.',
|
|
6125
6634
|
'plugins.mcpDiscovered': 'Discovered from plugins',
|
|
6126
6635
|
'plugins.mcpStored': 'User MCP servers',
|
|
6636
|
+
'plugins.mcpConfiguredCount': '{count} configured',
|
|
6637
|
+
'plugins.mcpSearch': 'Search MCP servers...',
|
|
6638
|
+
'plugins.mcpNoMatch': 'No MCP servers match this search.',
|
|
6639
|
+
'plugins.mcpRefresh': 'Refresh',
|
|
6640
|
+
'plugins.mcpRefreshing': 'Refreshing MCP servers...',
|
|
6641
|
+
'plugins.mcpLoadError': 'MCP servers could not be loaded.',
|
|
6642
|
+
'plugins.mcpUnavailable': 'MCP management is unavailable in this interface.',
|
|
6643
|
+
'plugins.mcpAddTitle': 'Add MCP server',
|
|
6644
|
+
'plugins.mcpEditTitle': 'Edit MCP server',
|
|
6645
|
+
'plugins.mcpReviewTitle': 'Review MCP candidate',
|
|
6646
|
+
'plugins.mcpFormHelp': 'Review every field before saving. Imported candidates always start disabled.',
|
|
6647
|
+
'plugins.mcpEnabled': 'Enable this server after saving',
|
|
6648
|
+
'plugins.mcpEndpointStdio': 'Command',
|
|
6649
|
+
'plugins.mcpEndpointHttp': 'Server URL',
|
|
6650
|
+
'plugins.mcpCwd': 'Working directory (optional)',
|
|
6651
|
+
'plugins.mcpSecretsHelp': 'When editing, leave blank to preserve saved values; enter {} to clear them. Secret values are never displayed.',
|
|
6652
|
+
'plugins.mcpSavedEnvKeys': 'Saved environment keys: {keys}',
|
|
6653
|
+
'plugins.mcpSavedHeaderKeys': 'Saved header keys: {keys}',
|
|
6654
|
+
'plugins.mcpNoSavedKeys': 'No saved keys.',
|
|
6655
|
+
'plugins.mcpInvalidArgs': 'Arguments must be a JSON array.',
|
|
6656
|
+
'plugins.mcpInvalidObject': '{field} must be a JSON object.',
|
|
6657
|
+
'plugins.mcpRequiredName': 'Enter a server name.',
|
|
6658
|
+
'plugins.mcpRequiredCommand': 'Enter a command for this stdio server.',
|
|
6659
|
+
'plugins.mcpRequiredUrl': 'Enter an http(s) URL for this server.',
|
|
6660
|
+
'plugins.mcpSaving': 'Saving...',
|
|
6661
|
+
'plugins.mcpSaved': 'MCP server saved.',
|
|
6662
|
+
'plugins.mcpEnabledStatus': 'Enabled',
|
|
6663
|
+
'plugins.mcpDisabledStatus': 'Disabled',
|
|
6664
|
+
'plugins.mcpMutationFailed': 'MCP operation failed.',
|
|
6665
|
+
'plugins.mcpRemoveConfirm': 'Remove MCP server "{name}"?',
|
|
6666
|
+
'plugins.mcpReadonly': 'Read-only metadata',
|
|
6667
|
+
'plugins.mcpDiscoveredEmpty': 'No MCP metadata was discovered from installed plugins.',
|
|
6668
|
+
'plugins.mcpStoredEmpty': 'No user MCP servers yet. Add one or review a compatible DSH candidate.',
|
|
6669
|
+
'plugins.mcpReviewImport': 'Review and import',
|
|
6670
|
+
'plugins.mcpCandidateHelp': 'This only pre-fills the MCP form. Nothing is installed, executed, or enabled automatically.',
|
|
6671
|
+
'plugins.retry': 'Retry',
|
|
6672
|
+
'plugins.dshTitle': 'DSH Plugin compatibility',
|
|
6673
|
+
'plugins.dshHelp': 'Developer preview: inspect the locally available official DSH CLI and package configuration. Discovery is read-only and never installs, executes, updates, or rewrites DSH.',
|
|
6674
|
+
'plugins.dshPreview': 'Developer preview',
|
|
6675
|
+
'plugins.dshRescan': 'Rescan',
|
|
6676
|
+
'plugins.dshScanning': 'Scanning DSH compatibility...',
|
|
6677
|
+
'plugins.dshLoadError': 'DSH compatibility information could not be loaded.',
|
|
6678
|
+
'plugins.dshUnavailable': 'DSH discovery is unavailable in this interface.',
|
|
6679
|
+
'plugins.dshCli': 'CLI and package',
|
|
6680
|
+
'plugins.dshCliPath': 'CLI path',
|
|
6681
|
+
'plugins.dshCliVersion': 'CLI version',
|
|
6682
|
+
'plugins.dshPackageVersion': 'Package version',
|
|
6683
|
+
'plugins.dshHome': 'DSH_HOME',
|
|
6684
|
+
'plugins.dshHomeSource': 'Home source',
|
|
6685
|
+
'plugins.dshConfigFiles': 'Configuration files',
|
|
6686
|
+
'plugins.dshLayers': 'Configuration layer order',
|
|
6687
|
+
'plugins.dshLayerOrder': 'Later layers override earlier rows; unknown keys remain visible and untouched.',
|
|
6688
|
+
'plugins.dshHomePatches': 'Home-level patches',
|
|
6689
|
+
'plugins.dshUpdateability': 'Updateability: use official DSH tooling or edit the shown patch files; Newmark never rewrites them.',
|
|
6690
|
+
'plugins.dshUpdateChannel': 'Update channel',
|
|
6691
|
+
'plugins.dshLatestChannel': 'latest (not locked)',
|
|
6692
|
+
'plugins.dshProfiles': 'Profiles',
|
|
6693
|
+
'plugins.dshBundles': 'Bundles',
|
|
6694
|
+
'plugins.dshWarnings': 'Warnings',
|
|
6695
|
+
'plugins.dshUnknownKeys': 'Unknown keys',
|
|
6696
|
+
'plugins.dshMcpCandidates': 'MCP candidates',
|
|
6697
|
+
'plugins.dshNone': 'None discovered',
|
|
6698
|
+
'plugins.dshNotAvailable': 'Not available',
|
|
6699
|
+
'plugins.dshOfficialRepo': 'Official repository',
|
|
6700
|
+
'plugins.dshOfficialDocs': 'Documentation',
|
|
6701
|
+
'plugins.dshOfficialNpm': 'npm package',
|
|
6702
|
+
'plugins.dshReadonly': 'Read-only compatibility policy',
|
|
6703
|
+
'plugins.dshReadonlyDetail': 'Newmark only reads local compatibility metadata. Use official DSH tooling to install, execute, update, or change DSH configuration.',
|
|
6127
6704
|
'workspace.new': 'New workspace',
|
|
6128
6705
|
'workspace.type': 'Type',
|
|
6129
6706
|
'workspace.internal': 'Internal workspace',
|
|
@@ -6223,6 +6800,21 @@ var NEWMARK_I18N = {
|
|
|
6223
6800
|
'status.contextModeModel': 'model',
|
|
6224
6801
|
'status.messages': 'messages',
|
|
6225
6802
|
'status.noCompression': 'No compression event in this conversation',
|
|
6803
|
+
'status.contextInspector': 'Context management',
|
|
6804
|
+
'status.contextInspectorHint': 'DSH-inspired live budget; visible chat history stays unchanged.',
|
|
6805
|
+
'status.activeBuild': 'Active Build',
|
|
6806
|
+
'status.longHistory': 'Long history',
|
|
6807
|
+
'status.trigger': 'Trigger',
|
|
6808
|
+
'status.retention': 'Retention',
|
|
6809
|
+
'status.hotCache': 'Hot cache',
|
|
6810
|
+
'status.coldArchive': 'Cold archive',
|
|
6811
|
+
'status.lastCompression': 'Last compression',
|
|
6812
|
+
'status.noCompressionShort': 'No compression yet',
|
|
6813
|
+
'status.compressNow': 'Compress now',
|
|
6814
|
+
'status.compressing': 'Compressing...',
|
|
6815
|
+
'status.compressedNow': 'Context compressed.',
|
|
6816
|
+
'status.compressionFailed': 'Context compression failed.',
|
|
6817
|
+
'status.compressionBusy': 'Compression is unavailable while this conversation is running.',
|
|
6226
6818
|
'status.recentFiles': 'Recent file changes',
|
|
6227
6819
|
'status.noFileChanges': 'No file changes recorded for the latest run.',
|
|
6228
6820
|
'status.pendingOptions': 'Pending options',
|
|
@@ -6243,6 +6835,8 @@ var NEWMARK_I18N = {
|
|
|
6243
6835
|
'conversation.reorderFailed': 'Could not save the conversation order.',
|
|
6244
6836
|
'conversation.pin': 'Pin conversation',
|
|
6245
6837
|
'conversation.unpin': 'Unpin conversation',
|
|
6838
|
+
'conversation.branchCommunication': 'Allow branch communication',
|
|
6839
|
+
'conversation.branchCommunicationBadge': 'Branch communication',
|
|
6246
6840
|
'conversation.loadingIsolated': 'Loading isolated conversation...',
|
|
6247
6841
|
'conversation.locked': 'Current conversation is locked while the agent is working.',
|
|
6248
6842
|
'queue.next': 'Next',
|
|
@@ -6286,6 +6880,48 @@ var NEWMARK_I18N = {
|
|
|
6286
6880
|
zh: {
|
|
6287
6881
|
'app.ready': '就绪',
|
|
6288
6882
|
'app.subtitle': '输入指令开始。Enter 发送,Shift+Enter 换行。',
|
|
6883
|
+
'shortcuts.paletteTitle': '命令面板',
|
|
6884
|
+
'shortcuts.helpTitle': '键盘快捷键',
|
|
6885
|
+
'shortcuts.paletteSubtitle': '搜索并执行所有已注册的 Newmark GUI 命令;不会覆盖标准文本编辑按键。',
|
|
6886
|
+
'shortcuts.helpSubtitle': '通用桌面快捷键与避免冲突的 Newmark 命令序列。',
|
|
6887
|
+
'shortcuts.searchCommands': '搜索命令...',
|
|
6888
|
+
'shortcuts.searchShortcuts': '搜索命令或快捷键...',
|
|
6889
|
+
'shortcuts.noResults': '没有匹配的命令。',
|
|
6890
|
+
'shortcuts.footer': '上/下选择 · Enter 执行 · Esc 关闭 · Tab 保持在对话框内',
|
|
6891
|
+
'shortcuts.category.general': '通用',
|
|
6892
|
+
'shortcuts.category.navigation': '导航',
|
|
6893
|
+
'shortcuts.category.workspace': '工作区与对话',
|
|
6894
|
+
'shortcuts.category.layout': '布局与焦点',
|
|
6895
|
+
'shortcuts.category.input': '输入与模式',
|
|
6896
|
+
'shortcuts.category.editor': '编辑器',
|
|
6897
|
+
'shortcuts.category.browser': '浏览器',
|
|
6898
|
+
'shortcuts.category.terminal': '终端',
|
|
6899
|
+
'shortcuts.category.context': '上下文操作',
|
|
6900
|
+
'shortcuts.context.global': '应用',
|
|
6901
|
+
'shortcuts.context.prompt': '输入框',
|
|
6902
|
+
'shortcuts.context.editor': '仅编辑器',
|
|
6903
|
+
'shortcuts.context.browser': '仅浏览器',
|
|
6904
|
+
'shortcuts.context.terminal': '仅终端',
|
|
6905
|
+
'shortcuts.context.dialog': '对话框',
|
|
6906
|
+
'shortcuts.openPalette': '打开命令面板',
|
|
6907
|
+
'shortcuts.openHelp': '显示键盘快捷键',
|
|
6908
|
+
'shortcuts.focusPrimary': '聚焦主要输入框',
|
|
6909
|
+
'shortcuts.focusNext': '聚焦下一个应用区域',
|
|
6910
|
+
'shortcuts.focusPrevious': '聚焦上一个应用区域',
|
|
6911
|
+
'shortcuts.toggleLeft': '切换左侧边栏',
|
|
6912
|
+
'shortcuts.toggleWorkspacePanel': '切换工作区与对话面板',
|
|
6913
|
+
'shortcuts.toggleRight': '切换右侧边栏',
|
|
6914
|
+
'shortcuts.toggleTerminal': '切换终端',
|
|
6915
|
+
'shortcuts.nextConversation': '下一个对话',
|
|
6916
|
+
'shortcuts.previousConversation': '上一个对话',
|
|
6917
|
+
'shortcuts.nextBranch': '下一个分支',
|
|
6918
|
+
'shortcuts.previousBranch': '上一个分支',
|
|
6919
|
+
'shortcuts.scrollBottom': '滚动到对话底部',
|
|
6920
|
+
'shortcuts.newTerminal': '新建终端',
|
|
6921
|
+
'shortcuts.focusTerminal': '聚焦终端输入框',
|
|
6922
|
+
'shortcuts.focusBrowserAddress': '聚焦浏览器地址栏',
|
|
6923
|
+
'shortcuts.toggleTheme': '切换明暗主题',
|
|
6924
|
+
'shortcuts.chordHint': '{prefix} 等待:{keys}',
|
|
6289
6925
|
'top.minimize': '最小化',
|
|
6290
6926
|
'top.maximize': '最大化',
|
|
6291
6927
|
'top.close': '关闭',
|
|
@@ -6297,12 +6933,14 @@ var NEWMARK_I18N = {
|
|
|
6297
6933
|
'left.flow': '工作流',
|
|
6298
6934
|
'left.settings': '设置',
|
|
6299
6935
|
'left.workspaces': '工作区',
|
|
6936
|
+
'left.conversations': '对话',
|
|
6300
6937
|
'left.new': '新建',
|
|
6301
6938
|
'left.collapse': '折叠左侧栏',
|
|
6302
6939
|
'left.collapseSecondary': '折叠工作区面板',
|
|
6303
6940
|
'input.placeholder': '输入指令...',
|
|
6304
6941
|
'input.send': '发送',
|
|
6305
6942
|
'input.stop': '停止',
|
|
6943
|
+
'input.continue': '继续',
|
|
6306
6944
|
'input.guide': 'Guide',
|
|
6307
6945
|
'input.next': 'Next',
|
|
6308
6946
|
'mode.build': 'Build',
|
|
@@ -6632,7 +7270,13 @@ var NEWMARK_I18N = {
|
|
|
6632
7270
|
'flow.noAvailable': '当前没有可运行的工作流。',
|
|
6633
7271
|
'flow.started': 'Flow 已启动',
|
|
6634
7272
|
'plugins.title': '插件',
|
|
7273
|
+
'plugins.tabMcp': 'MCP',
|
|
7274
|
+
'plugins.tabDsh': 'DSH Plugin',
|
|
7275
|
+
'plugins.tabSkills': 'Skills',
|
|
7276
|
+
'plugins.tabMarket': 'Market',
|
|
7277
|
+
'plugins.tabGithub': 'GitHub',
|
|
6635
7278
|
'plugins.mcp': 'MCP 管理',
|
|
7279
|
+
'plugins.dsh': 'DSH Plugin',
|
|
6636
7280
|
'plugins.management': 'Skills 管理',
|
|
6637
7281
|
'plugins.market': 'Skills Market',
|
|
6638
7282
|
'plugins.github': 'GitHub CLI',
|
|
@@ -6690,6 +7334,74 @@ var NEWMARK_I18N = {
|
|
|
6690
7334
|
'plugins.mcpNoServers': '暂无用户 MCP 服务器。',
|
|
6691
7335
|
'plugins.mcpDiscovered': '从插件发现',
|
|
6692
7336
|
'plugins.mcpStored': '用户 MCP 服务器',
|
|
7337
|
+
'plugins.mcpConfiguredCount': '已配置 {count} 项',
|
|
7338
|
+
'plugins.mcpSearch': '搜索 MCP 服务器...',
|
|
7339
|
+
'plugins.mcpNoMatch': '没有符合搜索条件的 MCP 服务器。',
|
|
7340
|
+
'plugins.mcpRefresh': '刷新',
|
|
7341
|
+
'plugins.mcpRefreshing': '正在刷新 MCP 服务器...',
|
|
7342
|
+
'plugins.mcpLoadError': '无法加载 MCP 服务器。',
|
|
7343
|
+
'plugins.mcpUnavailable': '当前界面不支持 MCP 管理。',
|
|
7344
|
+
'plugins.mcpAddTitle': '添加 MCP 服务器',
|
|
7345
|
+
'plugins.mcpEditTitle': '编辑 MCP 服务器',
|
|
7346
|
+
'plugins.mcpReviewTitle': '审核 MCP 候选项',
|
|
7347
|
+
'plugins.mcpFormHelp': '保存前请审核所有字段。从候选项导入时始终默认禁用。',
|
|
7348
|
+
'plugins.mcpEnabled': '保存后启用此服务器',
|
|
7349
|
+
'plugins.mcpEndpointStdio': '命令',
|
|
7350
|
+
'plugins.mcpEndpointHttp': '服务器 URL',
|
|
7351
|
+
'plugins.mcpCwd': '工作目录(可选)',
|
|
7352
|
+
'plugins.mcpSecretsHelp': '编辑时留空可保留已保存的值;输入 {} 可清空。界面绝不显示密钥值。',
|
|
7353
|
+
'plugins.mcpSavedEnvKeys': '已保存环境变量键:{keys}',
|
|
7354
|
+
'plugins.mcpSavedHeaderKeys': '已保存请求头键:{keys}',
|
|
7355
|
+
'plugins.mcpNoSavedKeys': '没有已保存的键。',
|
|
7356
|
+
'plugins.mcpInvalidArgs': '参数必须是 JSON 数组。',
|
|
7357
|
+
'plugins.mcpInvalidObject': '{field} 必须是 JSON 对象。',
|
|
7358
|
+
'plugins.mcpRequiredName': '请输入服务器名称。',
|
|
7359
|
+
'plugins.mcpRequiredCommand': '请输入 stdio 服务器命令。',
|
|
7360
|
+
'plugins.mcpRequiredUrl': '请输入 http(s) 服务器 URL。',
|
|
7361
|
+
'plugins.mcpSaving': '正在保存...',
|
|
7362
|
+
'plugins.mcpSaved': 'MCP 服务器已保存。',
|
|
7363
|
+
'plugins.mcpEnabledStatus': '已启用',
|
|
7364
|
+
'plugins.mcpDisabledStatus': '已禁用',
|
|
7365
|
+
'plugins.mcpMutationFailed': 'MCP 操作失败。',
|
|
7366
|
+
'plugins.mcpRemoveConfirm': '移除 MCP 服务器“{name}”?',
|
|
7367
|
+
'plugins.mcpReadonly': '只读元数据',
|
|
7368
|
+
'plugins.mcpDiscoveredEmpty': '未从已安装插件中发现 MCP 元数据。',
|
|
7369
|
+
'plugins.mcpStoredEmpty': '暂无用户 MCP 服务器。可以添加服务器,或审核兼容的 DSH 候选项。',
|
|
7370
|
+
'plugins.mcpReviewImport': '审核并导入',
|
|
7371
|
+
'plugins.mcpCandidateHelp': '此操作只会预填 MCP 表单,不会安装、执行或自动启用任何内容。',
|
|
7372
|
+
'plugins.retry': '重试',
|
|
7373
|
+
'plugins.dshTitle': 'DSH Plugin 兼容',
|
|
7374
|
+
'plugins.dshHelp': '开发者预览:检查本地官方 DSH CLI 与包配置。发现过程严格只读,绝不会安装、执行、更新或改写 DSH。',
|
|
7375
|
+
'plugins.dshPreview': '开发者预览',
|
|
7376
|
+
'plugins.dshRescan': '重新扫描',
|
|
7377
|
+
'plugins.dshScanning': '正在扫描 DSH 兼容信息...',
|
|
7378
|
+
'plugins.dshLoadError': '无法加载 DSH 兼容信息。',
|
|
7379
|
+
'plugins.dshUnavailable': '当前界面不支持 DSH 发现。',
|
|
7380
|
+
'plugins.dshCli': 'CLI 与软件包',
|
|
7381
|
+
'plugins.dshCliPath': 'CLI 路径',
|
|
7382
|
+
'plugins.dshCliVersion': 'CLI 版本',
|
|
7383
|
+
'plugins.dshPackageVersion': '软件包版本',
|
|
7384
|
+
'plugins.dshHome': 'DSH_HOME',
|
|
7385
|
+
'plugins.dshHomeSource': '目录来源',
|
|
7386
|
+
'plugins.dshConfigFiles': '配置文件',
|
|
7387
|
+
'plugins.dshLayers': '配置层顺序',
|
|
7388
|
+
'plugins.dshLayerOrder': '后面的层覆盖前面的条目;未知键会被展示但不会改写。',
|
|
7389
|
+
'plugins.dshHomePatches': 'Home 级 patch',
|
|
7390
|
+
'plugins.dshUpdateability': '可更新性:请使用官方 DSH 工具或编辑下方 patch 文件;Newmark 不会重写这些文件。',
|
|
7391
|
+
'plugins.dshUpdateChannel': '更新通道',
|
|
7392
|
+
'plugins.dshLatestChannel': 'latest(未锁定)',
|
|
7393
|
+
'plugins.dshProfiles': 'Profiles',
|
|
7394
|
+
'plugins.dshBundles': 'Bundles',
|
|
7395
|
+
'plugins.dshWarnings': '警告',
|
|
7396
|
+
'plugins.dshUnknownKeys': '未知配置键',
|
|
7397
|
+
'plugins.dshMcpCandidates': 'MCP 候选项',
|
|
7398
|
+
'plugins.dshNone': '未发现',
|
|
7399
|
+
'plugins.dshNotAvailable': '不可用',
|
|
7400
|
+
'plugins.dshOfficialRepo': '官方仓库',
|
|
7401
|
+
'plugins.dshOfficialDocs': '官方文档',
|
|
7402
|
+
'plugins.dshOfficialNpm': 'npm 软件包',
|
|
7403
|
+
'plugins.dshReadonly': '只读兼容策略',
|
|
7404
|
+
'plugins.dshReadonlyDetail': 'Newmark 只读取本地兼容元数据。安装、执行、更新或更改 DSH 配置请使用官方 DSH 工具。',
|
|
6693
7405
|
'workspace.new': '新建工作区',
|
|
6694
7406
|
'workspace.type': '类型',
|
|
6695
7407
|
'workspace.internal': '内部工作区',
|
|
@@ -6789,6 +7501,21 @@ var NEWMARK_I18N = {
|
|
|
6789
7501
|
'status.contextModeModel': '模型',
|
|
6790
7502
|
'status.messages': '条消息',
|
|
6791
7503
|
'status.noCompression': '当前对话暂无压缩事件',
|
|
7504
|
+
'status.contextInspector': '上下文管理',
|
|
7505
|
+
'status.contextInspectorHint': '借鉴 DSH 的动态预算;可见对话历史不会被改写。',
|
|
7506
|
+
'status.activeBuild': '当前 Build',
|
|
7507
|
+
'status.longHistory': '长期历史',
|
|
7508
|
+
'status.trigger': '触发线',
|
|
7509
|
+
'status.retention': '保留量',
|
|
7510
|
+
'status.hotCache': '热缓存',
|
|
7511
|
+
'status.coldArchive': '冷归档',
|
|
7512
|
+
'status.lastCompression': '最近一次压缩',
|
|
7513
|
+
'status.noCompressionShort': '尚未压缩',
|
|
7514
|
+
'status.compressNow': '立即压缩',
|
|
7515
|
+
'status.compressing': '正在压缩...',
|
|
7516
|
+
'status.compressedNow': '上下文已压缩。',
|
|
7517
|
+
'status.compressionFailed': '上下文压缩失败。',
|
|
7518
|
+
'status.compressionBusy': '对话运行中,暂时无法压缩上下文。',
|
|
6792
7519
|
'status.recentFiles': '最近文件变更',
|
|
6793
7520
|
'status.noFileChanges': '最近一轮没有记录文件变更。',
|
|
6794
7521
|
'status.pendingOptions': '待处理选项',
|
|
@@ -6809,6 +7536,8 @@ var NEWMARK_I18N = {
|
|
|
6809
7536
|
'conversation.reorderFailed': '无法保存对话顺序。',
|
|
6810
7537
|
'conversation.pin': '置顶对话',
|
|
6811
7538
|
'conversation.unpin': '取消置顶对话',
|
|
7539
|
+
'conversation.branchCommunication': '允许分支交流',
|
|
7540
|
+
'conversation.branchCommunicationBadge': '分支交流',
|
|
6812
7541
|
'conversation.loadingIsolated': '正在加载隔离对话...',
|
|
6813
7542
|
'conversation.locked': 'Agent 工作中,当前对话已锁定。',
|
|
6814
7543
|
'queue.next': '下一轮',
|
|
@@ -6933,6 +7662,10 @@ function applyLanguageToUi() {
|
|
|
6933
7662
|
}
|
|
6934
7663
|
var wsHead = document.getElementById('left-ws-header');
|
|
6935
7664
|
if (wsHead) wsHead.textContent = t('left.workspaces');
|
|
7665
|
+
var wsList = document.getElementById('left-ws-list');
|
|
7666
|
+
if (wsList) wsList.setAttribute('aria-label', t('left.workspaces'));
|
|
7667
|
+
var conversationList = document.getElementById('conversation-list');
|
|
7668
|
+
if (conversationList) conversationList.setAttribute('aria-label', t('left.conversations'));
|
|
6936
7669
|
var wsAdd = document.querySelector('#left-ws-add span:last-child');
|
|
6937
7670
|
if (wsAdd) wsAdd.textContent = t('left.new');
|
|
6938
7671
|
setTitleAndLabel('.secondary-top button[onclick="window.openWsSettings()"]', t('workspace.settingsTitle'));
|
|
@@ -6958,6 +7691,10 @@ function applyLanguageToUi() {
|
|
|
6958
7691
|
if (browserUrl) browserUrl.setAttribute('placeholder', t('browser.url'));
|
|
6959
7692
|
var terminalInputs = document.querySelectorAll('.terminal-input');
|
|
6960
7693
|
for (var ti = 0; ti < terminalInputs.length; ti++) terminalInputs[ti].setAttribute('placeholder', t('terminal.enterCommand'));
|
|
7694
|
+
var terminalTabs = document.getElementById('terminal-tabs');
|
|
7695
|
+
if (terminalTabs) terminalTabs.setAttribute('aria-label', t('shortcuts.category.terminal'));
|
|
7696
|
+
var fileTree = document.getElementById('file-tree-container');
|
|
7697
|
+
if (fileTree) fileTree.setAttribute('aria-label', t('right.fileTree'));
|
|
6961
7698
|
var terminalReady = document.querySelector('#terminal-pane-0 .terminal-output span');
|
|
6962
7699
|
if (terminalReady && terminalReady.textContent === 'Terminal ready') terminalReady.textContent = t('terminal.ready');
|
|
6963
7700
|
var terminalStatusSpans = document.querySelectorAll('.terminal-output span');
|
|
@@ -8220,6 +8957,8 @@ window.toggleWorkReview = function(head) {
|
|
|
8220
8957
|
var review = head && head.closest ? head.closest('.work-review') : null;
|
|
8221
8958
|
if (!review) return;
|
|
8222
8959
|
review.classList.toggle('collapsed');
|
|
8960
|
+
var toggle = review.querySelector('.work-review-toggle');
|
|
8961
|
+
if (toggle) toggle.setAttribute('aria-expanded', review.classList.contains('collapsed') ? 'false' : 'true');
|
|
8223
8962
|
};
|
|
8224
8963
|
|
|
8225
8964
|
window.toggleWorkReviewFiles = function(button) {
|
|
@@ -8324,7 +9063,7 @@ function addWorkReview(diffs) {
|
|
|
8324
9063
|
review.innerHTML = '<div class="work-review-head" onclick="window.toggleWorkReview(this)"><div class="work-review-mark">' + iconSvg('file-diff', t('review.fileChanges'), 'small') + '</div>' +
|
|
8325
9064
|
'<div><div class="work-review-title">' + esc(editedLabel) + '</div><div class="work-review-stats"><span class="work-review-add">+' + added + '</span><span class="work-review-del">-' + deleted + '</span></div></div>' +
|
|
8326
9065
|
'<div class="work-review-actions"><button class="work-review-btn" onclick="window.openWorkReview(this);event.stopPropagation()">' + esc(t('review.open')) + '</button>' +
|
|
8327
|
-
'<span class="work-review-chevron" aria-hidden="true"></span></div></div>' +
|
|
9066
|
+
'<button type="button" class="work-review-toggle" aria-expanded="false" onclick="event.stopPropagation();window.toggleWorkReview(this)" title="' + escAttr(t('queue.expand')) + '"><span class="work-review-chevron" aria-hidden="true"></span><span class="icon-only-label">' + esc(t('queue.expand')) + '</span></button></div></div>' +
|
|
8328
9067
|
'<div class="work-review-list">' + rows + (files.length > 3 ? '<button class="work-review-more" onclick="window.toggleWorkReviewFiles(this)">' + esc(t('review.showMore').replace('{count}', files.length - 3)) + '</button>' : '') + '</div>';
|
|
8329
9068
|
els['chat-area'].appendChild(review);
|
|
8330
9069
|
autoScrollIfAtBottom();
|
|
@@ -8859,7 +9598,7 @@ function publicWorkEvent(event) {
|
|
|
8859
9598
|
var content = String(event && event.content || '');
|
|
8860
9599
|
var toolArgs = String(event && event.toolArgs || '');
|
|
8861
9600
|
if (/<think(?:\s|>)/i.test(content) || /<\/think>/i.test(content) || /<\/?think\b|(?:reasoning_content|thinking_delta)\s*[::]/i.test(toolArgs)) return false;
|
|
8862
|
-
return ['start', 'text', 'response', 'final_response', 'status', 'tool_call', 'tool_result', 'guide', 'guide_accepted', 'guide_applied', 'guide_deferred', 'guide_rejected', 'done', 'error', 'interrupted', 'force_interrupted'].indexOf(type) >= 0;
|
|
9601
|
+
return ['start', 'text', 'response', 'final_response', 'status', 'tool_call', 'tool_result', 'thought', 'thought_result', 'guide', 'guide_accepted', 'guide_applied', 'guide_deferred', 'guide_rejected', 'done', 'error', 'interrupted', 'force_interrupted'].indexOf(type) >= 0;
|
|
8863
9602
|
}
|
|
8864
9603
|
|
|
8865
9604
|
function publicToolNameForUi(value) {
|
|
@@ -9118,7 +9857,12 @@ function syncWorkRunsSnapshot(runs, target, branchId) {
|
|
|
9118
9857
|
return item;
|
|
9119
9858
|
});
|
|
9120
9859
|
state.workRunsByBranch[workRunBranchKey(target, selectedBranchId)] = normalized;
|
|
9121
|
-
|
|
9860
|
+
// 串分支修复:全局显示列表(workRunsByTarget)只在 sync 的分支就是「浏览分支」时
|
|
9861
|
+
// 才更新。当运行分支(runtime)的 streaming 结果到达、而用户正在浏览另一个分支时,
|
|
9862
|
+
// 只按分支存储(workRunsByBranch),不污染当前浏览分支的显示。
|
|
9863
|
+
if (selectedBranchId === branchIds.viewed) {
|
|
9864
|
+
state.workRunsByTarget[key] = normalized;
|
|
9865
|
+
}
|
|
9122
9866
|
return normalized;
|
|
9123
9867
|
}
|
|
9124
9868
|
|
|
@@ -9410,6 +10154,23 @@ function renderWorkToolGroup(event, eventIndex) {
|
|
|
9410
10154
|
activityRows + '</div></details>';
|
|
9411
10155
|
}
|
|
9412
10156
|
|
|
10157
|
+
function renderWorkThought(event, eventIndex) {
|
|
10158
|
+
var zh = currentLang() === 'zh';
|
|
10159
|
+
var content = String(event.content || '').trim();
|
|
10160
|
+
var completed = !!event.completed;
|
|
10161
|
+
var activityDomKey = String(event.id || ('thought-' + eventIndex));
|
|
10162
|
+
var label = completed ? (zh ? '进行了思考' : 'Thought') : (zh ? '思考中' : 'Thinking');
|
|
10163
|
+
var detailRows = '';
|
|
10164
|
+
if (content) {
|
|
10165
|
+
detailRows = '<div class="conversation-work-thought-text">' + esc(content) + '</div>';
|
|
10166
|
+
} else if (!completed) {
|
|
10167
|
+
detailRows = '<div class="conversation-work-thought-text conversation-work-thought-pending">' + esc(zh ? '正在思考…' : 'Thinking…') + '</div>';
|
|
10168
|
+
}
|
|
10169
|
+
return '<details class="conversation-work-activity conversation-work-thought" data-activity-key="' + escAttr(activityDomKey) + '"><summary>' +
|
|
10170
|
+
iconSvg('brain', 'thought', 'tiny') + '<span>' + esc(label) + '</span>' +
|
|
10171
|
+
'<span class="conversation-work-activity-chevron" aria-hidden="true"></span></summary>' + detailRows + '</details>';
|
|
10172
|
+
}
|
|
10173
|
+
|
|
9413
10174
|
function workEventLabel(event) {
|
|
9414
10175
|
var type = String(event && event.type || 'status').toLowerCase();
|
|
9415
10176
|
var content = String(event && event.content || '').trim();
|
|
@@ -9514,6 +10275,16 @@ function renderWorkRunEvents(run, includeGuides) {
|
|
|
9514
10275
|
}
|
|
9515
10276
|
if (!rawEvent) continue;
|
|
9516
10277
|
}
|
|
10278
|
+
if (rawType === 'thought_result') {
|
|
10279
|
+
for (var thoughtPriorIndex = events.length - 1; thoughtPriorIndex >= 0; thoughtPriorIndex--) {
|
|
10280
|
+
var thoughtPrior = events[thoughtPriorIndex];
|
|
10281
|
+
if (String(thoughtPrior && thoughtPrior.type || '').toLowerCase() !== 'thought' || thoughtPrior.completed) continue;
|
|
10282
|
+
events[thoughtPriorIndex] = Object.assign({}, thoughtPrior, { completed: true, content: rawEvent.content || thoughtPrior.content });
|
|
10283
|
+
rawEvent = null;
|
|
10284
|
+
break;
|
|
10285
|
+
}
|
|
10286
|
+
if (!rawEvent) continue;
|
|
10287
|
+
}
|
|
9517
10288
|
events.push(rawEvent);
|
|
9518
10289
|
}
|
|
9519
10290
|
flushPublicText();
|
|
@@ -9554,6 +10325,7 @@ function renderWorkRunEvents(run, includeGuides) {
|
|
|
9554
10325
|
}
|
|
9555
10326
|
if (type.indexOf('guide') === 0 || event.guide) return renderWorkRunGuideMessage(event);
|
|
9556
10327
|
if (type === 'tool_group') return renderWorkToolGroup(event, eventIndex);
|
|
10328
|
+
if (type === 'thought') return renderWorkThought(event, eventIndex);
|
|
9557
10329
|
var activitySummary = type.indexOf('tool_') === 0 && type !== 'tool_call' && type !== 'tool_result';
|
|
9558
10330
|
var cls = type.indexOf('guide') === 0 ? ' guide' : (type === 'error' ? ' error' : (activitySummary ? ' activity-summary' : ''));
|
|
9559
10331
|
var label = activitySummary ? workToolActivityLabel(event.activity, Number(event.count || 1), !!event.completed) : workEventLabel(event) + (event.completed ? (currentLang() === 'zh' ? ' · 已完成' : ' · completed') : '');
|
|
@@ -10576,7 +11348,12 @@ function applyConversationSnapshot(s, requestedConversationId) {
|
|
|
10576
11348
|
if (s && s.runtimeKey) registerRuntimeKey(snapshotTarget, s.runtimeKey);
|
|
10577
11349
|
hydrateConversationBranchState(s);
|
|
10578
11350
|
rebindQueueToRuntimeBranch(snapshotTarget);
|
|
10579
|
-
if (s && Array.isArray(s.workRuns))
|
|
11351
|
+
if (s && Array.isArray(s.workRuns)) {
|
|
11352
|
+
var viewedBranchIdForSync = Array.isArray(s.viewedBranchNodePath) && s.viewedBranchNodePath.length
|
|
11353
|
+
? String(s.viewedBranchNodePath[s.viewedBranchNodePath.length - 1])
|
|
11354
|
+
: '';
|
|
11355
|
+
syncWorkRunsSnapshot(s.workRuns, snapshotTarget, viewedBranchIdForSync || undefined);
|
|
11356
|
+
}
|
|
10580
11357
|
applyAutoRouteRatingState(s);
|
|
10581
11358
|
if (s && s.chatMessages) {
|
|
10582
11359
|
renderChatMessages(s.chatMessages);
|
|
@@ -10639,9 +11416,9 @@ function addShellBlock(title, content) {
|
|
|
10639
11416
|
var div = document.createElement('div');
|
|
10640
11417
|
div.className = 'chat-msg assistant';
|
|
10641
11418
|
div.innerHTML = '<div class="shell-block collapsed">' +
|
|
10642
|
-
'<
|
|
11419
|
+
'<button type="button" class="shell-block-header" aria-expanded="false" onclick="this.parentElement.classList.toggle(\'collapsed\');this.setAttribute(\'aria-expanded\',this.parentElement.classList.contains(\'collapsed\')?\'false\':\'true\')">' +
|
|
10643
11420
|
'<span class="arrow">></span> ' + esc(title) +
|
|
10644
|
-
'</
|
|
11421
|
+
'</button><div class="shell-block-body">' + esc(content) + '</div></div>';
|
|
10645
11422
|
els['chat-area'].appendChild(div);
|
|
10646
11423
|
autoScrollIfAtBottom();
|
|
10647
11424
|
}
|
|
@@ -10650,10 +11427,10 @@ function addDiffBlock(title, adds, dels, linesHTML) {
|
|
|
10650
11427
|
var div = document.createElement('div');
|
|
10651
11428
|
div.className = 'chat-msg assistant';
|
|
10652
11429
|
div.innerHTML = '<div class="diff-block collapsed">' +
|
|
10653
|
-
'<
|
|
11430
|
+
'<button type="button" class="diff-block-header" aria-expanded="false" onclick="this.parentElement.classList.toggle(\'collapsed\');this.setAttribute(\'aria-expanded\',this.parentElement.classList.contains(\'collapsed\')?\'false\':\'true\')">' +
|
|
10654
11431
|
'<span class="arrow">></span> ' + esc(title) +
|
|
10655
11432
|
'<span class="diff-stat"><span class="diff-add">+' + adds + '</span><span class="diff-del">-' + dels + '</span></span>' +
|
|
10656
|
-
'</
|
|
11433
|
+
'</button><div class="diff-block-body">' + linesHTML + '</div></div>';
|
|
10657
11434
|
els['chat-area'].appendChild(div);
|
|
10658
11435
|
autoScrollIfAtBottom();
|
|
10659
11436
|
}
|
|
@@ -11135,7 +11912,7 @@ window.stopCurrentConversation = async function() {
|
|
|
11135
11912
|
return true;
|
|
11136
11913
|
};
|
|
11137
11914
|
|
|
11138
|
-
window.submitCurrentAction = function() {
|
|
11915
|
+
window.submitCurrentAction = function(source) {
|
|
11139
11916
|
if (currentFlowRunning() && flowTakeoverMatchesCurrent()) {
|
|
11140
11917
|
if (!promptHasText()) {
|
|
11141
11918
|
window.stopFlowRun();
|
|
@@ -11170,6 +11947,8 @@ window.submitCurrentAction = function() {
|
|
|
11170
11947
|
return;
|
|
11171
11948
|
}
|
|
11172
11949
|
if (isCurrentConversationRunning() && !promptHasText()) {
|
|
11950
|
+
// 回车:运行中空输入不操作(打断仅通过 Esc 或点击打断按钮)。
|
|
11951
|
+
if (source === 'enter') return;
|
|
11173
11952
|
window.stopCurrentConversation();
|
|
11174
11953
|
return;
|
|
11175
11954
|
}
|
|
@@ -11211,6 +11990,98 @@ window.renderContextWindow = function() {
|
|
|
11211
11990
|
ring.style.mask = 'radial-gradient(farthest-side, transparent 58%, #000 60%)';
|
|
11212
11991
|
var status = c.warning === 'over_limit' ? t('status.contextOverLimit') : (c.warning === 'near_limit' ? t('status.contextNearLimit') : t('status.contextTokens'));
|
|
11213
11992
|
ring.title = status + ': ' + used + ' / ' + max;
|
|
11993
|
+
if (window.renderContextInspector) window.renderContextInspector();
|
|
11994
|
+
};
|
|
11995
|
+
|
|
11996
|
+
function contextInspectorValue(value) {
|
|
11997
|
+
var number = Number(value);
|
|
11998
|
+
return Number.isFinite(number) ? Math.max(0, Math.round(number)) : 0;
|
|
11999
|
+
}
|
|
12000
|
+
|
|
12001
|
+
function contextInspectorCell(label, value) {
|
|
12002
|
+
return '<div class="context-inspector-cell"><span class="context-inspector-label">' + esc(label) + '</span><span class="context-inspector-value">' + esc(value) + '</span></div>';
|
|
12003
|
+
}
|
|
12004
|
+
|
|
12005
|
+
window.renderContextInspector = function() {
|
|
12006
|
+
var panel = document.getElementById('context-inspector');
|
|
12007
|
+
var ring = els['context-token-ring'] || document.getElementById('context-token-ring');
|
|
12008
|
+
if (!panel || !ring) return;
|
|
12009
|
+
ring.setAttribute('aria-expanded', state.contextInspectorOpen ? 'true' : 'false');
|
|
12010
|
+
panel.classList.toggle('open', state.contextInspectorOpen);
|
|
12011
|
+
if (!state.contextInspectorOpen) {
|
|
12012
|
+
panel.innerHTML = '';
|
|
12013
|
+
return;
|
|
12014
|
+
}
|
|
12015
|
+
var c = state.contextWindow || {};
|
|
12016
|
+
var max = Math.max(1, contextInspectorValue(c.maxTokens) || 1);
|
|
12017
|
+
var used = contextInspectorValue(c.estimatedTokens);
|
|
12018
|
+
var active = contextInspectorValue(c.buildBlockTokens);
|
|
12019
|
+
var history = contextInspectorValue(c.longHistoryTokens);
|
|
12020
|
+
var activeTrigger = contextInspectorValue(c.buildBlockTriggerTokens);
|
|
12021
|
+
var historyTrigger = contextInspectorValue(c.longHistoryTriggerTokens);
|
|
12022
|
+
var activeRetention = contextInspectorValue(c.buildBlockRetentionTokens);
|
|
12023
|
+
var historyRetention = contextInspectorValue(c.longHistoryRetentionTokens);
|
|
12024
|
+
var percent = Math.min(100, Math.round((used / max) * 100));
|
|
12025
|
+
var fillColor = c.warning === 'over_limit' ? 'var(--nm-state-danger)' : (c.warning === 'near_limit' ? 'var(--nm-state-warning)' : 'var(--accent)');
|
|
12026
|
+
var compression = state.contextCompression || null;
|
|
12027
|
+
var last = compression
|
|
12028
|
+
? ((compression.fallback ? t('status.contextModeFallback') : t('status.contextModeModel')) + ' · ' + String(compression.originalMessages || 0) + ' → ' + String(compression.compressedMessages || 0) + ' ' + t('status.messages'))
|
|
12029
|
+
: t('status.noCompressionShort');
|
|
12030
|
+
var busy = !!state.contextMutationPending;
|
|
12031
|
+
var running = typeof isCurrentConversationRunning === 'function' && isCurrentConversationRunning();
|
|
12032
|
+
panel.innerHTML = '<div class="context-inspector-head"><div><div class="context-inspector-title">' + esc(t('status.contextInspector')) + '</div><div class="context-inspector-subtitle">' + esc(t('status.contextInspectorHint')) + '</div></div>' +
|
|
12033
|
+
'<button type="button" class="context-inspector-close" onclick="window.closeContextInspector()" aria-label="' + esc(t('common.close') || 'Close') + '">×</button></div>' +
|
|
12034
|
+
'<div class="context-inspector-meter"><div class="context-inspector-meter-fill" style="width:' + percent + '%;background:' + fillColor + '"></div></div>' +
|
|
12035
|
+
'<div class="context-inspector-grid">' +
|
|
12036
|
+
contextInspectorCell(t('status.contextTokens'), used + ' / ' + max) +
|
|
12037
|
+
contextInspectorCell(t('status.activeBuild'), active + ' / ' + activeTrigger) +
|
|
12038
|
+
contextInspectorCell(t('status.longHistory'), history + ' / ' + historyTrigger) +
|
|
12039
|
+
contextInspectorCell(t('status.retention'), activeRetention + ' + ' + historyRetention) +
|
|
12040
|
+
contextInspectorCell(t('status.hotCache'), contextInspectorValue(c.cacheEntries) + ' entries') +
|
|
12041
|
+
contextInspectorCell(t('status.coldArchive'), contextInspectorValue(c.archiveEntries) + ' entries') +
|
|
12042
|
+
'</div>' +
|
|
12043
|
+
'<div class="context-inspector-section"><div class="context-inspector-section-title">' + esc(t('status.lastCompression')) + '</div><div class="context-inspector-meta">' + esc(last) + '</div>' +
|
|
12044
|
+
(compression && compression.model ? '<div class="context-inspector-meta">' + esc(compression.model) + '</div>' : '') + '</div>' +
|
|
12045
|
+
'<div class="context-inspector-actions"><button type="button" class="sec-btn primary" onclick="window.compressContextNow()"' + (busy || running ? ' disabled' : '') + '>' + esc(busy ? t('status.compressing') : t('status.compressNow')) + '</button></div>';
|
|
12046
|
+
};
|
|
12047
|
+
|
|
12048
|
+
window.closeContextInspector = function() {
|
|
12049
|
+
state.contextInspectorOpen = false;
|
|
12050
|
+
window.renderContextInspector();
|
|
12051
|
+
};
|
|
12052
|
+
|
|
12053
|
+
window.toggleContextInspector = function() {
|
|
12054
|
+
state.contextInspectorOpen = !state.contextInspectorOpen;
|
|
12055
|
+
window.hideContextWindowTooltip();
|
|
12056
|
+
window.renderContextInspector();
|
|
12057
|
+
};
|
|
12058
|
+
|
|
12059
|
+
window.compressContextNow = function() {
|
|
12060
|
+
if (state.contextMutationPending) return;
|
|
12061
|
+
if (typeof isCurrentConversationRunning === 'function' && isCurrentConversationRunning()) {
|
|
12062
|
+
showUiNotice(t('status.compressionBusy'), 'error', 'context-compress-busy');
|
|
12063
|
+
return;
|
|
12064
|
+
}
|
|
12065
|
+
if (!api.compressContext) {
|
|
12066
|
+
showUiNotice(t('status.compressionFailed'), 'error', 'context-compress-unavailable');
|
|
12067
|
+
return;
|
|
12068
|
+
}
|
|
12069
|
+
state.contextMutationPending = true;
|
|
12070
|
+
window.renderContextInspector();
|
|
12071
|
+
Promise.resolve(api.compressContext({ target: currentConversationTarget(), force: true })).then(function(result) {
|
|
12072
|
+
if (!result || result.ok === false) throw new Error((result && result.error) || t('status.compressionFailed'));
|
|
12073
|
+
if (result.contextWindow) state.contextWindow = result.contextWindow;
|
|
12074
|
+
if (result.contextCompression !== undefined) state.contextCompression = result.contextCompression;
|
|
12075
|
+
window.renderContextWindow();
|
|
12076
|
+
window.renderRightStatusPanel();
|
|
12077
|
+
showUiNotice(t('status.compressedNow'), 'success', 'context-compress-success');
|
|
12078
|
+
return result;
|
|
12079
|
+
}).catch(function(error) {
|
|
12080
|
+
showUiNotice(error && error.message ? error.message : t('status.compressionFailed'), 'error', 'context-compress-error');
|
|
12081
|
+
}).finally(function() {
|
|
12082
|
+
state.contextMutationPending = false;
|
|
12083
|
+
window.renderContextInspector();
|
|
12084
|
+
});
|
|
11214
12085
|
};
|
|
11215
12086
|
|
|
11216
12087
|
window.contextWindowTooltipHtml = function() {
|
|
@@ -11831,6 +12702,7 @@ window.renderQueuePanel = function() {
|
|
|
11831
12702
|
}
|
|
11832
12703
|
var toggle = panel.querySelector('#queue-expand-btn');
|
|
11833
12704
|
if (toggle) {
|
|
12705
|
+
toggle.setAttribute('aria-expanded', state.queueCollapsed ? 'false' : 'true');
|
|
11834
12706
|
toggle.title = state.queueCollapsed ? t('queue.expand') : t('queue.collapse');
|
|
11835
12707
|
toggle.innerHTML = iconSvg(state.queueCollapsed ? 'chevron-up' : 'chevron-down', toggle.title, 'tiny');
|
|
11836
12708
|
}
|
|
@@ -12120,7 +12992,14 @@ window.sendMessage = async function(modeOverride, queuedText, opts) {
|
|
|
12120
12992
|
var displayText = optimisticAttachments.length
|
|
12121
12993
|
? rawText + (rawText ? '\n\n' : '') + '[' + optimisticAttachments.length + ' image attachment' + (optimisticAttachments.length === 1 ? '' : 's') + ']'
|
|
12122
12994
|
: text;
|
|
12123
|
-
if (!text && !optimisticAttachments.length)
|
|
12995
|
+
if (!text && !optimisticAttachments.length) {
|
|
12996
|
+
// 空输入时发送默认句段「继续 / Continue」,按界面语言切换。
|
|
12997
|
+
var continuePhrase = t('input.continue');
|
|
12998
|
+
rawText = continuePhrase;
|
|
12999
|
+
text = continuePhrase;
|
|
13000
|
+
requestMessage = continuePhrase;
|
|
13001
|
+
displayText = continuePhrase;
|
|
13002
|
+
}
|
|
12124
13003
|
|
|
12125
13004
|
var lockedConversationId = activeConversationId();
|
|
12126
13005
|
var lockedTarget = currentConversationTarget(lockedConversationId);
|
|
@@ -12868,19 +13747,25 @@ window.toggleBottom = function() {
|
|
|
12868
13747
|
};
|
|
12869
13748
|
|
|
12870
13749
|
// === Right Sidebar Tabs ===
|
|
13750
|
+
function rightTabButtonHtml(tab, icon, label, active) {
|
|
13751
|
+
return '<button class="tab-btn' + (active ? ' active' : '') + '" id="right-tab-' + tab + '" role="tab" aria-selected="' + (active ? 'true' : 'false') + '" aria-controls="panel-' + tab + '" tabindex="' + (active ? '0' : '-1') + '" data-tab="' + tab + '" onclick="window.switchRightTab("' + tab + '")" onkeydown="window.handleRightTabKey(event)" title="' + escAttr(label) + '">' + iconOnly(icon, label) + '</button>';
|
|
13752
|
+
}
|
|
13753
|
+
|
|
12871
13754
|
window.upgradeRightSidebar = function() {
|
|
12872
13755
|
var rightTabs = els['right-tabs'] || document.getElementById('right-tabs');
|
|
12873
13756
|
var rightContent = els['right-content'] || document.getElementById('right-content');
|
|
12874
13757
|
if (!rightTabs || !rightContent || rightTabs.getAttribute('data-upgraded') === 'true') return;
|
|
12875
13758
|
rightTabs.setAttribute('data-upgraded', 'true');
|
|
13759
|
+
rightTabs.setAttribute('role', 'tablist');
|
|
13760
|
+
rightTabs.setAttribute('aria-label', t('right.files'));
|
|
12876
13761
|
rightTabs.innerHTML =
|
|
12877
|
-
'
|
|
12878
|
-
|
|
12879
|
-
|
|
12880
|
-
'
|
|
12881
|
-
|
|
12882
|
-
|
|
12883
|
-
|
|
13762
|
+
rightTabButtonHtml('file-tree', 'folder', t('right.files'), state.rightTab === 'file-tree') +
|
|
13763
|
+
rightTabButtonHtml('editor', 'square-pen', t('right.editor'), state.rightTab === 'editor') +
|
|
13764
|
+
rightTabButtonHtml('plan', 'list-checks', t('right.plan'), state.rightTab === 'plan') +
|
|
13765
|
+
rightTabButtonHtml('subagent', 'bot', t('right.subagents'), state.rightTab === 'subagent') +
|
|
13766
|
+
rightTabButtonHtml('browser', 'globe', t('right.browser'), state.rightTab === 'browser') +
|
|
13767
|
+
rightTabButtonHtml('status', 'activity', t('right.status'), state.rightTab === 'status') +
|
|
13768
|
+
rightTabButtonHtml('archives', 'archive', t('right.archives'), state.rightTab === 'archives') +
|
|
12884
13769
|
'<div class="tab-divider"></div>' +
|
|
12885
13770
|
'<button class="tab-btn" onclick="window.toggleRight()" title="' + escAttr(t('right.close')) + '">' + iconOnly('x', t('right.close')) + '</button>';
|
|
12886
13771
|
|
|
@@ -12888,7 +13773,7 @@ window.upgradeRightSidebar = function() {
|
|
|
12888
13773
|
if (filePanel && !filePanel.getAttribute('data-upgraded')) {
|
|
12889
13774
|
filePanel.setAttribute('data-upgraded', 'true');
|
|
12890
13775
|
var tree = document.getElementById('file-tree-container');
|
|
12891
|
-
filePanel.innerHTML = '<div class="right-section-head"><span class="right-section-title">' + esc(t('right.fileTree')) + '</span><button class="archive-action-btn" onclick="window.loadFileTree()">' + esc(t('right.refresh')) + '</button></div><div id="file-tree-container"></div>';
|
|
13776
|
+
filePanel.innerHTML = '<div class="right-section-head"><span class="right-section-title">' + esc(t('right.fileTree')) + '</span><button class="archive-action-btn" onclick="window.loadFileTree()">' + esc(t('right.refresh')) + '</button></div><div id="file-tree-container" role="tree"></div>';
|
|
12892
13777
|
if (tree) document.getElementById('file-tree-container').innerHTML = tree.innerHTML;
|
|
12893
13778
|
}
|
|
12894
13779
|
var subPanel = document.getElementById('panel-subagent');
|
|
@@ -12919,6 +13804,14 @@ window.upgradeRightSidebar = function() {
|
|
|
12919
13804
|
archivesPanel.innerHTML = '<div class="right-section-head"><span class="right-section-title">' + esc(t('right.archives')) + '</span><button class="archive-action-btn" onclick="window.refreshRightArchives()">' + esc(t('right.refresh')) + '</button></div><div style="display:flex;gap:6px;margin-bottom:8px;"><button class="sec-btn primary" style="flex:1;" onclick="window.archiveCurrent()">' + esc(t('archive.current')) + '</button></div><div id="right-archive-list"></div>';
|
|
12920
13805
|
rightContent.appendChild(archivesPanel);
|
|
12921
13806
|
}
|
|
13807
|
+
var upgradedPanels = rightContent.querySelectorAll('.tab-panel');
|
|
13808
|
+
for (var upgradedIndex = 0; upgradedIndex < upgradedPanels.length; upgradedIndex++) {
|
|
13809
|
+
var upgradedPanel = upgradedPanels[upgradedIndex];
|
|
13810
|
+
var upgradedTab = upgradedPanel.id.replace(/^panel-/, '');
|
|
13811
|
+
upgradedPanel.setAttribute('role', 'tabpanel');
|
|
13812
|
+
upgradedPanel.setAttribute('aria-labelledby', 'right-tab-' + upgradedTab);
|
|
13813
|
+
upgradedPanel.hidden = upgradedTab !== state.rightTab;
|
|
13814
|
+
}
|
|
12922
13815
|
};
|
|
12923
13816
|
|
|
12924
13817
|
window.switchRightTab = function(tab) {
|
|
@@ -12932,11 +13825,16 @@ window.switchRightTab = function(tab) {
|
|
|
12932
13825
|
if (!rightTabs || !rightContent) return;
|
|
12933
13826
|
var btns = rightTabs.querySelectorAll('.tab-btn[data-tab]');
|
|
12934
13827
|
for (var i = 0; i < btns.length; i++) {
|
|
12935
|
-
|
|
13828
|
+
var selected = btns[i].getAttribute('data-tab') === tab;
|
|
13829
|
+
btns[i].classList.toggle('active', selected);
|
|
13830
|
+
btns[i].setAttribute('aria-selected', selected ? 'true' : 'false');
|
|
13831
|
+
btns[i].tabIndex = selected ? 0 : -1;
|
|
12936
13832
|
}
|
|
12937
13833
|
var panels = rightContent.querySelectorAll('.tab-panel');
|
|
12938
13834
|
for (var j = 0; j < panels.length; j++) {
|
|
12939
|
-
|
|
13835
|
+
var panelActive = panels[j].id === 'panel-' + tab;
|
|
13836
|
+
panels[j].classList.toggle('active', panelActive);
|
|
13837
|
+
panels[j].hidden = !panelActive;
|
|
12940
13838
|
}
|
|
12941
13839
|
// Load content on first access
|
|
12942
13840
|
if (tab === 'file-tree') window.loadFileTree();
|
|
@@ -13028,7 +13926,7 @@ window.renderConversationPlan = function() {
|
|
|
13028
13926
|
var plan = normalizeConversationPlan(state.conversationPlan);
|
|
13029
13927
|
var items = plan.items || [];
|
|
13030
13928
|
var html = '<div class="plan-compose">' +
|
|
13031
|
-
'<input id="conversation-plan-input" class="plan-input" placeholder="' + escAttr(t('plan.placeholder')) + '" onkeydown="if(event.key==="Enter")window.addConversationPlanItem()">' +
|
|
13929
|
+
'<input id="conversation-plan-input" class="plan-input" placeholder="' + escAttr(t('plan.placeholder')) + '" onkeydown="if(event.key==="Enter"&&!event.isComposing&&event.key!=="Process"&&event.keyCode!==229)window.addConversationPlanItem()">' +
|
|
13032
13930
|
'<button class="sec-btn primary" onclick="window.addConversationPlanItem()">' + esc(t('plan.add')) + '</button>' +
|
|
13033
13931
|
'</div>';
|
|
13034
13932
|
if (!items.length) {
|
|
@@ -13096,7 +13994,7 @@ window.editConversationPlanItem = function(idx) {
|
|
|
13096
13994
|
var rows = target.querySelectorAll('.plan-row');
|
|
13097
13995
|
var row = rows[idx];
|
|
13098
13996
|
if (!row) return;
|
|
13099
|
-
row.querySelector('.right-row-body').innerHTML = '<input class="plan-edit-input" id="conversation-plan-edit-' + idx + '" value="' + escAttr(item.text) + '" onkeydown="if(event.key==="Enter")window.saveConversationPlanEdit(' + idx + ')">';
|
|
13997
|
+
row.querySelector('.right-row-body').innerHTML = '<input class="plan-edit-input" id="conversation-plan-edit-' + idx + '" value="' + escAttr(item.text) + '" onkeydown="if(event.key==="Enter"&&!event.isComposing&&event.key!=="Process"&&event.keyCode!==229)window.saveConversationPlanEdit(' + idx + ')">';
|
|
13100
13998
|
var actions = row.querySelector('.plan-actions');
|
|
13101
13999
|
if (actions) {
|
|
13102
14000
|
actions.innerHTML = '<button class="archive-action-btn" onclick="window.saveConversationPlanEdit(' + idx + ')">' + esc(t('common.save')) + '</button>' +
|
|
@@ -13247,6 +14145,8 @@ window.renderRightStatusPanel = function() {
|
|
|
13247
14145
|
if (contextWindow) {
|
|
13248
14146
|
html += '<div class="right-row"><div class="right-row-body"><span class="right-row-title">' + esc(t('status.contextTokens')) + '</span><span class="right-row-meta">' +
|
|
13249
14147
|
esc(String(contextWindow.estimatedTokens || 0) + ' / ' + String(contextWindow.maxTokens || 0) + ' | ' + String(contextWindow.warning || 'ok')) +
|
|
14148
|
+
(contextWindow.buildBlockTokens !== undefined ? '<br>' + esc(t('status.activeBuild')) + ': ' + esc(String(contextWindow.buildBlockTokens || 0) + ' / ' + String(contextWindow.buildBlockTriggerTokens || 0)) +
|
|
14149
|
+
' · ' + esc(t('status.longHistory')) + ': ' + esc(String(contextWindow.longHistoryTokens || 0) + ' / ' + String(contextWindow.longHistoryTriggerTokens || 0)) : '') +
|
|
13250
14150
|
'</span></div></div>';
|
|
13251
14151
|
}
|
|
13252
14152
|
if (compression) {
|
|
@@ -13470,6 +14370,35 @@ window.spawnTerminal = function(shellId, options) {
|
|
|
13470
14370
|
return window.addTerminalTab(shellId, options);
|
|
13471
14371
|
};
|
|
13472
14372
|
|
|
14373
|
+
window.handleTerminalTabKey = function(event) {
|
|
14374
|
+
if (!event || event.defaultPrevented || event.isComposing || event.key === 'Process' || event.keyCode === 229 || event.target !== event.currentTarget) return false;
|
|
14375
|
+
var tabs = Array.prototype.slice.call(document.querySelectorAll('#terminal-tabs .terminal-tab'));
|
|
14376
|
+
var index = tabs.indexOf(event.currentTarget);
|
|
14377
|
+
if (index < 0 || !tabs.length) return false;
|
|
14378
|
+
var next = index;
|
|
14379
|
+
if (event.key === 'ArrowRight') next = (index + 1) % tabs.length;
|
|
14380
|
+
else if (event.key === 'ArrowLeft') next = (index - 1 + tabs.length) % tabs.length;
|
|
14381
|
+
else if (event.key === 'Home') next = 0;
|
|
14382
|
+
else if (event.key === 'End') next = tabs.length - 1;
|
|
14383
|
+
else if (event.key === 'Enter' || event.key === ' ') next = index;
|
|
14384
|
+
else if (event.key === 'Delete') {
|
|
14385
|
+
event.preventDefault();
|
|
14386
|
+
var closingId = parseInt(tabs[index].getAttribute('data-tab-id'), 10);
|
|
14387
|
+
window.closeTerminalTab(closingId);
|
|
14388
|
+
requestAnimationFrame(function() {
|
|
14389
|
+
var activeTab = document.querySelector('#terminal-tabs .terminal-tab.active') || document.querySelector('#terminal-tabs .terminal-tab');
|
|
14390
|
+
if (activeTab) activeTab.focus({ preventScroll:true });
|
|
14391
|
+
});
|
|
14392
|
+
return true;
|
|
14393
|
+
}
|
|
14394
|
+
else return false;
|
|
14395
|
+
event.preventDefault();
|
|
14396
|
+
var tabId = parseInt(tabs[next].getAttribute('data-tab-id'), 10);
|
|
14397
|
+
window.switchTerminalTab(tabId);
|
|
14398
|
+
tabs[next].focus({ preventScroll:true });
|
|
14399
|
+
return true;
|
|
14400
|
+
};
|
|
14401
|
+
|
|
13473
14402
|
window.addTerminalTab = function(shellId, options) {
|
|
13474
14403
|
options = options || {};
|
|
13475
14404
|
shellId = normalizeTerminalShell(shellId || state._terminalShell);
|
|
@@ -13487,13 +14416,23 @@ window.addTerminalTab = function(shellId, options) {
|
|
|
13487
14416
|
// Create tab button
|
|
13488
14417
|
var tab = document.createElement('div');
|
|
13489
14418
|
tab.className = 'terminal-tab active';
|
|
14419
|
+
tab.id = 'terminal-tab-' + tabId;
|
|
14420
|
+
tab.setAttribute('role', 'tab');
|
|
14421
|
+
tab.setAttribute('aria-selected', 'true');
|
|
14422
|
+
tab.setAttribute('aria-controls', 'terminal-pane-' + tabId);
|
|
14423
|
+
tab.tabIndex = 0;
|
|
13490
14424
|
tab.setAttribute('data-tab-id', tabId);
|
|
13491
|
-
tab.innerHTML = name + '<button class="close-tab" onclick="event.stopPropagation();window.closeTerminalTab(' + tabId + ')" title="' + escAttr(t('common.closeTab')) + '">' + iconSvg('x', t('common.closeTab'), 'tiny') + '</button>';
|
|
14425
|
+
tab.innerHTML = name + '<button type="button" class="close-tab" onclick="event.stopPropagation();window.closeTerminalTab(' + tabId + ')" title="' + escAttr(t('common.closeTab')) + '">' + iconSvg('x', t('common.closeTab'), 'tiny') + '</button>';
|
|
13492
14426
|
tab.onclick = function() { window.switchTerminalTab(tabId); };
|
|
14427
|
+
tab.addEventListener('keydown', window.handleTerminalTabKey);
|
|
13493
14428
|
|
|
13494
14429
|
// Deactivate all other tabs
|
|
13495
14430
|
var allTabs = tabsContainer.querySelectorAll('.terminal-tab');
|
|
13496
|
-
for (var i = 0; i < allTabs.length; i++)
|
|
14431
|
+
for (var i = 0; i < allTabs.length; i++) {
|
|
14432
|
+
allTabs[i].classList.remove('active');
|
|
14433
|
+
allTabs[i].setAttribute('aria-selected', 'false');
|
|
14434
|
+
allTabs[i].tabIndex = -1;
|
|
14435
|
+
}
|
|
13497
14436
|
|
|
13498
14437
|
tabsContainer.appendChild(tab);
|
|
13499
14438
|
|
|
@@ -13501,18 +14440,20 @@ window.addTerminalTab = function(shellId, options) {
|
|
|
13501
14440
|
var pane = document.createElement('div');
|
|
13502
14441
|
pane.className = 'terminal-pane active';
|
|
13503
14442
|
pane.id = 'terminal-pane-' + tabId;
|
|
14443
|
+
pane.setAttribute('role', 'tabpanel');
|
|
14444
|
+
pane.setAttribute('aria-labelledby', tab.id);
|
|
13504
14445
|
pane.setAttribute('data-tab-id', tabId);
|
|
13505
14446
|
pane.setAttribute('data-session', '');
|
|
13506
14447
|
pane.innerHTML =
|
|
13507
14448
|
'<div class="terminal-output"><span style="color:var(--accent2);">Connecting ' + shellId + '...</span>\r\n</div>' +
|
|
13508
14449
|
'<div class="terminal-input-row">' +
|
|
13509
14450
|
'<span class="terminal-prompt">' + shellLabel + '></span>' +
|
|
13510
|
-
'<input class="terminal-input" type="text" placeholder="Enter command..." onkeydown="if(event.key===\'Enter\')window.terminalSend()">' +
|
|
14451
|
+
'<input class="terminal-input" type="text" placeholder="Enter command..." onkeydown="if(event.key===\'Enter\'&&!event.isComposing&&event.key!==\'Process\'&&event.keyCode!==229)window.terminalSend()">' +
|
|
13511
14452
|
'</div>';
|
|
13512
14453
|
|
|
13513
14454
|
// Deactivate all other panes
|
|
13514
14455
|
var allPanes = body.querySelectorAll('.terminal-pane');
|
|
13515
|
-
for (var j = 0; j < allPanes.length; j++) allPanes[j].classList.remove('active');
|
|
14456
|
+
for (var j = 0; j < allPanes.length; j++) { allPanes[j].classList.remove('active'); allPanes[j].hidden = true; }
|
|
13516
14457
|
|
|
13517
14458
|
body.appendChild(pane);
|
|
13518
14459
|
|
|
@@ -13563,21 +14504,33 @@ window.ensureTerminalTakeoverPane = function(session) {
|
|
|
13563
14504
|
|
|
13564
14505
|
var tab = document.createElement('div');
|
|
13565
14506
|
tab.className = 'terminal-tab agent-takeover marquee-border';
|
|
14507
|
+
tab.id = 'terminal-tab-' + tabId;
|
|
14508
|
+
tab.setAttribute('role', 'tab');
|
|
14509
|
+
tab.setAttribute('aria-selected', 'true');
|
|
14510
|
+
tab.setAttribute('aria-controls', 'terminal-pane-' + tabId);
|
|
14511
|
+
tab.tabIndex = 0;
|
|
13566
14512
|
tab.setAttribute('data-tab-id', tabId);
|
|
13567
14513
|
tab.setAttribute('data-takeover-session', key);
|
|
13568
14514
|
tab.setAttribute('data-takeover-workspace-id', session.workspaceId || '');
|
|
13569
14515
|
tab.setAttribute('data-takeover-conversation', session.conversationId || 'default');
|
|
13570
|
-
tab.innerHTML = 'Agent:' + esc(session.name || key) + '<button class="close-tab" onclick="event.stopPropagation();window.closeTerminalTab(' + tabId + ')" title="' + escAttr(t('common.closeTab')) + '">' + iconSvg('x', t('common.closeTab'), 'tiny') + '</button>';
|
|
14516
|
+
tab.innerHTML = 'Agent:' + esc(session.name || key) + '<button type="button" class="close-tab" onclick="event.stopPropagation();window.closeTerminalTab(' + tabId + ')" title="' + escAttr(t('common.closeTab')) + '">' + iconSvg('x', t('common.closeTab'), 'tiny') + '</button>';
|
|
13571
14517
|
tab.onclick = function() { window.switchTerminalTab(tabId); };
|
|
14518
|
+
tab.addEventListener('keydown', window.handleTerminalTabKey);
|
|
13572
14519
|
|
|
13573
14520
|
var allTabs = tabsContainer.querySelectorAll('.terminal-tab');
|
|
13574
|
-
for (var i = 0; i < allTabs.length; i++)
|
|
14521
|
+
for (var i = 0; i < allTabs.length; i++) {
|
|
14522
|
+
allTabs[i].classList.remove('active');
|
|
14523
|
+
allTabs[i].setAttribute('aria-selected', 'false');
|
|
14524
|
+
allTabs[i].tabIndex = -1;
|
|
14525
|
+
}
|
|
13575
14526
|
tab.classList.add('active');
|
|
13576
14527
|
tabsContainer.appendChild(tab);
|
|
13577
14528
|
|
|
13578
14529
|
var pane = document.createElement('div');
|
|
13579
14530
|
pane.className = 'terminal-pane active agent-takeover marquee-border';
|
|
13580
14531
|
pane.id = 'terminal-pane-' + tabId;
|
|
14532
|
+
pane.setAttribute('role', 'tabpanel');
|
|
14533
|
+
pane.setAttribute('aria-labelledby', tab.id);
|
|
13581
14534
|
pane.setAttribute('data-tab-id', tabId);
|
|
13582
14535
|
pane.setAttribute('data-session', '');
|
|
13583
14536
|
pane.setAttribute('data-takeover-session', key);
|
|
@@ -13589,11 +14542,11 @@ window.ensureTerminalTakeoverPane = function(session) {
|
|
|
13589
14542
|
'<div class="terminal-output"></div>' +
|
|
13590
14543
|
'<div class="terminal-input-row">' +
|
|
13591
14544
|
'<span class="terminal-prompt">Agent></span>' +
|
|
13592
|
-
'<input class="terminal-input" type="text" placeholder="Enter command..." onkeydown="if(event.key===\'Enter\')window.terminalSend()">' +
|
|
14545
|
+
'<input class="terminal-input" type="text" placeholder="Enter command..." onkeydown="if(event.key===\'Enter\'&&!event.isComposing&&event.key!==\'Process\'&&event.keyCode!==229)window.terminalSend()">' +
|
|
13593
14546
|
'</div>';
|
|
13594
14547
|
|
|
13595
14548
|
var allPanes = body.querySelectorAll('.terminal-pane');
|
|
13596
|
-
for (var j = 0; j < allPanes.length; j++) allPanes[j].classList.remove('active');
|
|
14549
|
+
for (var j = 0; j < allPanes.length; j++) { allPanes[j].classList.remove('active'); allPanes[j].hidden = true; }
|
|
13597
14550
|
body.appendChild(pane);
|
|
13598
14551
|
tabsContainer.scrollLeft = tabsContainer.scrollWidth;
|
|
13599
14552
|
window.switchTerminalTab(tabId);
|
|
@@ -13688,12 +14641,17 @@ window.switchTerminalTab = function(tabId) {
|
|
|
13688
14641
|
// Update tabs
|
|
13689
14642
|
var allTabs = document.querySelectorAll('.terminal-tab');
|
|
13690
14643
|
for (var i = 0; i < allTabs.length; i++) {
|
|
13691
|
-
|
|
14644
|
+
var selected = parseInt(allTabs[i].getAttribute('data-tab-id')) === tabId;
|
|
14645
|
+
allTabs[i].classList.toggle('active', selected);
|
|
14646
|
+
allTabs[i].setAttribute('aria-selected', selected ? 'true' : 'false');
|
|
14647
|
+
allTabs[i].tabIndex = selected ? 0 : -1;
|
|
13692
14648
|
}
|
|
13693
14649
|
// Update panes
|
|
13694
14650
|
var allPanes = document.querySelectorAll('.terminal-pane');
|
|
13695
14651
|
for (var j = 0; j < allPanes.length; j++) {
|
|
13696
|
-
|
|
14652
|
+
var active = parseInt(allPanes[j].getAttribute('data-tab-id')) === tabId;
|
|
14653
|
+
allPanes[j].classList.toggle('active', active);
|
|
14654
|
+
allPanes[j].hidden = !active;
|
|
13697
14655
|
}
|
|
13698
14656
|
// Update active session
|
|
13699
14657
|
var activePane = document.querySelector('.terminal-pane.active');
|
|
@@ -13879,6 +14837,7 @@ function renderTodo() {
|
|
|
13879
14837
|
label.textContent = t('goal.list') + (items.length ? ' ' + items.length : '');
|
|
13880
14838
|
var toggle = wrap.querySelector('#todo-header .stack-icon-btn');
|
|
13881
14839
|
if (toggle) {
|
|
14840
|
+
toggle.setAttribute('aria-expanded', state.todoCollapsed ? 'false' : 'true');
|
|
13882
14841
|
var title = state.todoCollapsed ? t('queue.expand') : t('queue.collapse');
|
|
13883
14842
|
toggle.title = title;
|
|
13884
14843
|
toggle.innerHTML = iconSvg(state.todoCollapsed ? 'chevron-up' : 'chevron-down', title, 'tiny');
|
|
@@ -13891,10 +14850,10 @@ function renderTodo() {
|
|
|
13891
14850
|
for (var i = 0; i < items.length; i++) {
|
|
13892
14851
|
var item = items[i];
|
|
13893
14852
|
var done = item.status === 'done';
|
|
13894
|
-
html += '<
|
|
14853
|
+
html += '<button type="button" class="todo-item ' + (done ? 'done' : '') + '" onclick="window.checkTodo(' + i + ')" title="' + escAttr(item.text) + '" aria-pressed="' + (done ? 'true' : 'false') + '">' +
|
|
13895
14854
|
'<span class="todo-check">' + (done ? iconSvg('check', 'done', 'tiny') : '') + '</span>' +
|
|
13896
14855
|
'<span class="todo-text">' + esc(item.text) + '</span>' +
|
|
13897
|
-
'</
|
|
14856
|
+
'</button>';
|
|
13898
14857
|
}
|
|
13899
14858
|
list.innerHTML = html;
|
|
13900
14859
|
}
|
|
@@ -13995,8 +14954,61 @@ window.setInputMode = function(mode, persist) {
|
|
|
13995
14954
|
};
|
|
13996
14955
|
|
|
13997
14956
|
// === Sub-Window System ===
|
|
14957
|
+
var subWindowOriginFocus = null;
|
|
14958
|
+
function newmarkFocusableElements(container) {
|
|
14959
|
+
if (!container || !container.querySelectorAll) return [];
|
|
14960
|
+
return Array.prototype.slice.call(container.querySelectorAll('button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [contenteditable="true"], [tabindex]:not([tabindex="-1"])')).filter(function(element) {
|
|
14961
|
+
return !element.hidden && element.getAttribute('aria-hidden') !== 'true' && element.getClientRects().length > 0;
|
|
14962
|
+
});
|
|
14963
|
+
}
|
|
14964
|
+
|
|
14965
|
+
function focusSubWindowInitial() {
|
|
14966
|
+
var dialog = els['sub-win'];
|
|
14967
|
+
if (!dialog || !els['sub-win-overlay'].classList.contains('open')) return;
|
|
14968
|
+
var body = els['sub-win-body'];
|
|
14969
|
+
var target = body && (body.querySelector('[autofocus]') || newmarkFocusableElements(body)[0]);
|
|
14970
|
+
if (!target) target = dialog.querySelector('.sub-win-close') || dialog;
|
|
14971
|
+
if (target && typeof target.focus === 'function') target.focus({ preventScroll: true });
|
|
14972
|
+
}
|
|
14973
|
+
|
|
14974
|
+
function updateApplicationInertState() {
|
|
14975
|
+
var commandOpen = !!(document.getElementById('command-surface-overlay') && document.getElementById('command-surface-overlay').classList.contains('open'));
|
|
14976
|
+
var subWindowOpen = !!(els['sub-win-overlay'] && els['sub-win-overlay'].classList.contains('open'));
|
|
14977
|
+
var topbar = document.getElementById('topbar');
|
|
14978
|
+
var main = document.getElementById('main');
|
|
14979
|
+
if (topbar) topbar.inert = commandOpen || subWindowOpen;
|
|
14980
|
+
if (main) main.inert = commandOpen || subWindowOpen;
|
|
14981
|
+
if (els['sub-win-overlay']) els['sub-win-overlay'].inert = commandOpen;
|
|
14982
|
+
}
|
|
14983
|
+
window.updateApplicationInertState = updateApplicationInertState;
|
|
14984
|
+
|
|
14985
|
+
function trapNewmarkDialogFocus(event, container) {
|
|
14986
|
+
if (!event || event.key !== 'Tab' || !container) return false;
|
|
14987
|
+
var items = newmarkFocusableElements(container);
|
|
14988
|
+
if (!items.length) {
|
|
14989
|
+
event.preventDefault();
|
|
14990
|
+
if (typeof container.focus === 'function') container.focus();
|
|
14991
|
+
return true;
|
|
14992
|
+
}
|
|
14993
|
+
var first = items[0];
|
|
14994
|
+
var last = items[items.length - 1];
|
|
14995
|
+
var active = document.activeElement;
|
|
14996
|
+
if (event.shiftKey && (active === first || !container.contains(active))) {
|
|
14997
|
+
event.preventDefault();
|
|
14998
|
+
last.focus();
|
|
14999
|
+
return true;
|
|
15000
|
+
}
|
|
15001
|
+
if (!event.shiftKey && (active === last || !container.contains(active))) {
|
|
15002
|
+
event.preventDefault();
|
|
15003
|
+
first.focus();
|
|
15004
|
+
return true;
|
|
15005
|
+
}
|
|
15006
|
+
return false;
|
|
15007
|
+
}
|
|
15008
|
+
|
|
13998
15009
|
window.openSubWin = function(title, html) {
|
|
13999
15010
|
var overlayOpen = els['sub-win-overlay'].classList.contains('open');
|
|
15011
|
+
if (!overlayOpen && document.activeElement && typeof document.activeElement.focus === 'function') subWindowOriginFocus = document.activeElement;
|
|
14000
15012
|
if (overlayOpen && !state.restoringSubWindow && state.activeSubWindowView) {
|
|
14001
15013
|
if (!state.subWindowStack) state.subWindowStack = [];
|
|
14002
15014
|
state.subWindowStack.push({
|
|
@@ -14010,6 +15022,25 @@ window.openSubWin = function(title, html) {
|
|
|
14010
15022
|
els['sub-win-body'].innerHTML = html;
|
|
14011
15023
|
els['sub-win'].classList.toggle('memory-lab-window', !!(state.activeSubWindowView && state.activeSubWindowView.name === 'memoryLab'));
|
|
14012
15024
|
els['sub-win-overlay'].classList.add('open');
|
|
15025
|
+
updateApplicationInertState();
|
|
15026
|
+
requestAnimationFrame(focusSubWindowInitial);
|
|
15027
|
+
};
|
|
15028
|
+
|
|
15029
|
+
window.handleRightTabKey = function(event) {
|
|
15030
|
+
if (!event) return;
|
|
15031
|
+
var tabs = Array.prototype.slice.call((els['right-tabs'] || document).querySelectorAll('.tab-btn[data-tab]'));
|
|
15032
|
+
var index = tabs.indexOf(event.currentTarget);
|
|
15033
|
+
if (index < 0) return;
|
|
15034
|
+
var next = index;
|
|
15035
|
+
if (event.key === 'ArrowRight') next = (index + 1) % tabs.length;
|
|
15036
|
+
else if (event.key === 'ArrowLeft') next = (index - 1 + tabs.length) % tabs.length;
|
|
15037
|
+
else if (event.key === 'Home') next = 0;
|
|
15038
|
+
else if (event.key === 'End') next = tabs.length - 1;
|
|
15039
|
+
else return;
|
|
15040
|
+
event.preventDefault();
|
|
15041
|
+
var tab = tabs[next].getAttribute('data-tab');
|
|
15042
|
+
window.switchRightTab(tab);
|
|
15043
|
+
tabs[next].focus();
|
|
14013
15044
|
};
|
|
14014
15045
|
|
|
14015
15046
|
window.closeSubWin = function() {
|
|
@@ -14023,6 +15054,7 @@ window.closeSubWin = function() {
|
|
|
14023
15054
|
requestAnimationFrame(function() {
|
|
14024
15055
|
els['sub-win-body'].scrollTop = previous.scrollTop || 0;
|
|
14025
15056
|
state.restoringSubWindow = false;
|
|
15057
|
+
focusSubWindowInitial();
|
|
14026
15058
|
});
|
|
14027
15059
|
return;
|
|
14028
15060
|
}
|
|
@@ -14030,6 +15062,12 @@ window.closeSubWin = function() {
|
|
|
14030
15062
|
state.activeSubWindowView = null;
|
|
14031
15063
|
var win = els['sub-win'];
|
|
14032
15064
|
if (win) { win.classList.remove('memory-lab-window'); win.style.left = ''; win.style.top = ''; win.style.margin = ''; }
|
|
15065
|
+
var restoreFocus = subWindowOriginFocus;
|
|
15066
|
+
subWindowOriginFocus = null;
|
|
15067
|
+
updateApplicationInertState();
|
|
15068
|
+
requestAnimationFrame(function() {
|
|
15069
|
+
if (restoreFocus && restoreFocus.isConnected && typeof restoreFocus.focus === 'function') restoreFocus.focus({ preventScroll: true });
|
|
15070
|
+
});
|
|
14033
15071
|
};
|
|
14034
15072
|
|
|
14035
15073
|
function rerenderActiveSubWindowForLanguage() {
|
|
@@ -14078,19 +15116,19 @@ window.openSettings = function(tab) {
|
|
|
14078
15116
|
var activeTab = tab || state.settingsActiveTab || 'general';
|
|
14079
15117
|
var refreshingSettings = els['sub-win-overlay'].classList.contains('open') && state.activeSubWindowView && state.activeSubWindowView.name === 'settings';
|
|
14080
15118
|
window._settingsTabCache = window._settingsTabCache || {};
|
|
14081
|
-
var html = '<div class="settings-tabs">' +
|
|
14082
|
-
'<button class="stab-btn" data-stab="general" onclick="window.settingsTab(\'general\')">' + esc(t('settings.general')) + '</button>' +
|
|
14083
|
-
'<button class="stab-btn" data-stab="models" onclick="window.settingsTab(\'models\')">' + esc(t('settings.models')) + '</button>' +
|
|
14084
|
-
'<button class="stab-btn" data-stab="tools" onclick="window.settingsTab(\'tools\')">' + esc(t('settings.tools')) + '</button>' +
|
|
14085
|
-
'<button class="stab-btn" data-stab="archive" onclick="window.settingsTab(\'archive\')">' + esc(t('settings.archive')) + '</button>' +
|
|
14086
|
-
'<button class="stab-btn" data-stab="updates" onclick="window.settingsTab(\'updates\')">' + esc(t('settings.updates')) + '</button>' +
|
|
15119
|
+
var html = '<div class="settings-tabs" role="tablist" aria-label="' + escAttr(t('settings.title')) + '">' +
|
|
15120
|
+
'<button class="stab-btn" id="settings-tab-general" role="tab" aria-controls="stab-general" data-stab="general" onclick="window.settingsTab(\'general\')" onkeydown="window.handleSettingsTabKey(event)">' + esc(t('settings.general')) + '</button>' +
|
|
15121
|
+
'<button class="stab-btn" id="settings-tab-models" role="tab" aria-controls="stab-models" data-stab="models" onclick="window.settingsTab(\'models\')" onkeydown="window.handleSettingsTabKey(event)">' + esc(t('settings.models')) + '</button>' +
|
|
15122
|
+
'<button class="stab-btn" id="settings-tab-tools" role="tab" aria-controls="stab-tools" data-stab="tools" onclick="window.settingsTab(\'tools\')" onkeydown="window.handleSettingsTabKey(event)">' + esc(t('settings.tools')) + '</button>' +
|
|
15123
|
+
'<button class="stab-btn" id="settings-tab-archive" role="tab" aria-controls="stab-archive" data-stab="archive" onclick="window.settingsTab(\'archive\')" onkeydown="window.handleSettingsTabKey(event)">' + esc(t('settings.archive')) + '</button>' +
|
|
15124
|
+
'<button class="stab-btn" id="settings-tab-updates" role="tab" aria-controls="stab-updates" data-stab="updates" onclick="window.settingsTab(\'updates\')" onkeydown="window.handleSettingsTabKey(event)">' + esc(t('settings.updates')) + '</button>' +
|
|
14087
15125
|
'</div>' +
|
|
14088
|
-
'<div class="stab-panel" id="stab-general" data-lazy="1"></div>' +
|
|
15126
|
+
'<div class="stab-panel" id="stab-general" role="tabpanel" aria-labelledby="settings-tab-general" data-lazy="1"></div>' +
|
|
14089
15127
|
// Lazy: only render active tab on open; others render on first click
|
|
14090
|
-
(activeTab === 'models' ? '<div class="stab-panel" id="stab-models">' + renderModelSettings() + '</div>' : '<div class="stab-panel" id="stab-models" data-lazy="1"></div>') +
|
|
14091
|
-
(activeTab === 'tools' ? '<div class="stab-panel" id="stab-tools">' + renderToolSettings() + '</div>' : '<div class="stab-panel" id="stab-tools" data-lazy="1"></div>') +
|
|
14092
|
-
(activeTab === 'archive' ? '<div class="stab-panel" id="stab-archive">' + renderArchiveSettings() + '</div>' : '<div class="stab-panel" id="stab-archive" data-lazy="1"></div>') +
|
|
14093
|
-
(activeTab === 'updates' ? '<div class="stab-panel" id="stab-updates">' + renderUpdateSettings() + '</div>' : '<div class="stab-panel" id="stab-updates" data-lazy="1"></div>');
|
|
15128
|
+
(activeTab === 'models' ? '<div class="stab-panel" id="stab-models" role="tabpanel" aria-labelledby="settings-tab-models">' + renderModelSettings() + '</div>' : '<div class="stab-panel" id="stab-models" role="tabpanel" aria-labelledby="settings-tab-models" data-lazy="1"></div>') +
|
|
15129
|
+
(activeTab === 'tools' ? '<div class="stab-panel" id="stab-tools" role="tabpanel" aria-labelledby="settings-tab-tools">' + renderToolSettings() + '</div>' : '<div class="stab-panel" id="stab-tools" role="tabpanel" aria-labelledby="settings-tab-tools" data-lazy="1"></div>') +
|
|
15130
|
+
(activeTab === 'archive' ? '<div class="stab-panel" id="stab-archive" role="tabpanel" aria-labelledby="settings-tab-archive">' + renderArchiveSettings() + '</div>' : '<div class="stab-panel" id="stab-archive" role="tabpanel" aria-labelledby="settings-tab-archive" data-lazy="1"></div>') +
|
|
15131
|
+
(activeTab === 'updates' ? '<div class="stab-panel" id="stab-updates" role="tabpanel" aria-labelledby="settings-tab-updates">' + renderUpdateSettings() + '</div>' : '<div class="stab-panel" id="stab-updates" role="tabpanel" aria-labelledby="settings-tab-updates" data-lazy="1"></div>');
|
|
14094
15132
|
state.activeSubWindowView = { name: 'settings', tab: activeTab };
|
|
14095
15133
|
if (refreshingSettings) state.restoringSubWindow = true;
|
|
14096
15134
|
window.openSubWin(t('settings.title'), html);
|
|
@@ -14457,7 +15495,12 @@ window.settingsTab = function(name) {
|
|
|
14457
15495
|
state.settingsActiveTab = name || 'general';
|
|
14458
15496
|
var btns = document.querySelectorAll('.stab-btn');
|
|
14459
15497
|
for (var i = 0; i < btns.length; i++) {
|
|
14460
|
-
|
|
15498
|
+
var selected = btns[i].getAttribute('data-stab') === name;
|
|
15499
|
+
btns[i].classList.toggle('active', selected);
|
|
15500
|
+
if (btns[i].closest('.settings-tabs:not(.plugin-tabs)')) {
|
|
15501
|
+
btns[i].setAttribute('aria-selected', selected ? 'true' : 'false');
|
|
15502
|
+
btns[i].tabIndex = selected ? 0 : -1;
|
|
15503
|
+
}
|
|
14461
15504
|
}
|
|
14462
15505
|
// Render lazy panels on first access for faster initial open
|
|
14463
15506
|
var panelId = 'stab-' + name;
|
|
@@ -14483,6 +15526,7 @@ window.settingsTab = function(name) {
|
|
|
14483
15526
|
var panels = document.querySelectorAll('.stab-panel');
|
|
14484
15527
|
for (var j = 0; j < panels.length; j++) {
|
|
14485
15528
|
panels[j].classList.toggle('active', panels[j].id === panelId);
|
|
15529
|
+
panels[j].hidden = panels[j].id !== panelId;
|
|
14486
15530
|
}
|
|
14487
15531
|
if (name === 'models' && panel && panel.getAttribute('data-lazy') !== '1') window.loadGlobalAgentPrompt();
|
|
14488
15532
|
};
|
|
@@ -15290,9 +16334,26 @@ window.archiveCurrent = function() {
|
|
|
15290
16334
|
return window.archiveConv(currentId);
|
|
15291
16335
|
};
|
|
15292
16336
|
|
|
15293
|
-
window.
|
|
15294
|
-
|
|
15295
|
-
|
|
16337
|
+
window.handleSettingsTabKey = function(event) {
|
|
16338
|
+
if (!event) return;
|
|
16339
|
+
var tabs = Array.prototype.slice.call(document.querySelectorAll('.settings-tabs:not(.plugin-tabs) [role="tab"]'));
|
|
16340
|
+
var index = tabs.indexOf(event.currentTarget);
|
|
16341
|
+
if (index < 0) return;
|
|
16342
|
+
var next = index;
|
|
16343
|
+
if (event.key === 'ArrowRight') next = (index + 1) % tabs.length;
|
|
16344
|
+
else if (event.key === 'ArrowLeft') next = (index - 1 + tabs.length) % tabs.length;
|
|
16345
|
+
else if (event.key === 'Home') next = 0;
|
|
16346
|
+
else if (event.key === 'End') next = tabs.length - 1;
|
|
16347
|
+
else return;
|
|
16348
|
+
event.preventDefault();
|
|
16349
|
+
var name = tabs[next].getAttribute('data-stab');
|
|
16350
|
+
window.settingsTab(name);
|
|
16351
|
+
tabs[next].focus();
|
|
16352
|
+
};
|
|
16353
|
+
|
|
16354
|
+
window.loadArchive = function(idx, scope) {
|
|
16355
|
+
var item = (scope === 'all' ? state.allArchives : state.workspaceArchives)[idx];
|
|
16356
|
+
if (!item || !api.readArchive) return;
|
|
15296
16357
|
api.readArchive(item.id || item.name).then(function(content) {
|
|
15297
16358
|
window.openSubWin(t('archive.titlePrefix') + ': ' + item.name, '<pre style="white-space:pre-wrap;word-break:break-word;background:var(--glass-bg-1);border:1px solid var(--glass-border-1);border-radius:8px;padding:12px;font-size:11px;max-height:65vh;overflow:auto;">' + esc(content || '') + '</pre>');
|
|
15298
16359
|
}).catch(function(err) {
|
|
@@ -15624,10 +16685,10 @@ function renderFlowItem(work, idx, expanded) {
|
|
|
15624
16685
|
componentsHtml += '</div>';
|
|
15625
16686
|
}
|
|
15626
16687
|
return '<div class="flow-item">' +
|
|
15627
|
-
'<
|
|
16688
|
+
'<button type="button" class="flow-item-header' + (expanded ? '' : ' collapsed') + '" aria-expanded="' + (expanded ? 'true' : 'false') + '" onclick="this.classList.toggle(\'collapsed\');this.setAttribute(\'aria-expanded\',this.classList.contains(\'collapsed\')?\'false\':\'true\')">' +
|
|
15628
16689
|
'<span class="arrow">></span><span class="flow-item-name">' + esc(work.name || t('flow.untitled')) + '</span>' +
|
|
15629
16690
|
'<span class="flow-item-type">' + (work.components ? work.components.length : 0) + ' ' + esc(t('flow.components')) + '</span>' +
|
|
15630
|
-
'</
|
|
16691
|
+
'</button>' +
|
|
15631
16692
|
'<div class="flow-item-children" style="margin-bottom:4px;">' +
|
|
15632
16693
|
'<div style="display:flex;gap:4px;padding:4px 0;">' +
|
|
15633
16694
|
'<button class="sec-btn" style="flex:1;font-size:10px;" onclick="window.addFlowComp(' + idx + ',\'dialog\')">+ ' + esc(t('flow.dialog')) + '</button>' +
|
|
@@ -15642,7 +16703,7 @@ function renderFlowItem(work, idx, expanded) {
|
|
|
15642
16703
|
window.newFlowWork = function() {
|
|
15643
16704
|
var html = '<div style="padding:10px;">' +
|
|
15644
16705
|
'<label style="display:block;font-size:12px;color:var(--text-dim);margin-bottom:6px;">' + esc(t('flow.workflowName')) + '</label>' +
|
|
15645
|
-
'<input id="new-flow-input" style="width:100%;padding:8px 10px;border:1px solid var(--glass-border-2);border-radius:var(--radius-sm);background:var(--glass-bg-1);color:var(--text);font-size:13px;outline:none;box-sizing:border-box;" placeholder="' + escAttr(t('flow.enterName')) + '" onkeydown="if(event.key===\'Enter\')window.doNewFlowWork()">' +
|
|
16706
|
+
'<input id="new-flow-input" style="width:100%;padding:8px 10px;border:1px solid var(--glass-border-2);border-radius:var(--radius-sm);background:var(--glass-bg-1);color:var(--text);font-size:13px;outline:none;box-sizing:border-box;" placeholder="' + escAttr(t('flow.enterName')) + '" onkeydown="if(event.key===\'Enter\'&&!event.isComposing&&event.key!==\'Process\'&&event.keyCode!==229)window.doNewFlowWork()">' +
|
|
15646
16707
|
'<div style="margin-top:12px;display:flex;gap:8px;">' +
|
|
15647
16708
|
'<button class="sec-btn primary" style="flex:1;" onclick="window.doNewFlowWork()">' + esc(t('common.create')) + '</button>' +
|
|
15648
16709
|
'<button class="sec-btn" onclick="window.showFlowEditor()">' + esc(t('common.cancel')) + '</button>' +
|
|
@@ -16351,14 +17412,25 @@ function renderTreeNodes(nodes, parent, depth) {
|
|
|
16351
17412
|
var n = nodes[i];
|
|
16352
17413
|
var div = document.createElement('div');
|
|
16353
17414
|
div.className = 'ft-item';
|
|
17415
|
+
div.setAttribute('role', 'treeitem');
|
|
17416
|
+
var treeRoot = parent.closest ? (parent.closest('[role="tree"]') || parent) : parent;
|
|
17417
|
+
div.tabIndex = treeRoot.querySelector && treeRoot.querySelector('[role="treeitem"][tabindex="0"]') ? -1 : 0;
|
|
17418
|
+
div.addEventListener('keydown', window.handleFileTreeKey);
|
|
17419
|
+
div.addEventListener('focus', function() {
|
|
17420
|
+
var root = this.closest('[role="tree"]');
|
|
17421
|
+
if (!root) return;
|
|
17422
|
+
Array.prototype.forEach.call(root.querySelectorAll('[role="treeitem"]'), function(item) { item.tabIndex = item === document.activeElement ? 0 : -1; });
|
|
17423
|
+
});
|
|
16354
17424
|
div.style.paddingLeft = (8 + depth * 14) + 'px';
|
|
16355
17425
|
var icon = n.type === 'directory' ? iconSvg('folder', 'Folder', 'small') : iconSvg('file', 'File', 'small');
|
|
16356
17426
|
if (n.type === 'directory') {
|
|
17427
|
+
div.setAttribute('aria-expanded', 'false');
|
|
16357
17428
|
div.innerHTML = '<span class="ft-toggle collapsed">' + iconSvg('chevron-right', t('fileTree.toggleFolder'), 'tiny') + '</span>' +
|
|
16358
17429
|
'<span class="ft-icon">' + icon + '</span><span class="ft-name">' + esc(n.name) + '</span>';
|
|
16359
17430
|
parent.appendChild(div);
|
|
16360
17431
|
var childContainer = document.createElement('div');
|
|
16361
17432
|
childContainer.className = 'ft-children';
|
|
17433
|
+
childContainer.setAttribute('role', 'group');
|
|
16362
17434
|
childContainer.style.display = 'none';
|
|
16363
17435
|
parent.appendChild(childContainer);
|
|
16364
17436
|
div.onclick = function(node, toggle, children, childDepth) {
|
|
@@ -16367,6 +17439,7 @@ function renderTreeNodes(nodes, parent, depth) {
|
|
|
16367
17439
|
var opening = children.style.display === 'none';
|
|
16368
17440
|
children.style.display = opening ? 'block' : 'none';
|
|
16369
17441
|
toggle.classList.toggle('collapsed', !opening);
|
|
17442
|
+
this.setAttribute('aria-expanded', opening ? 'true' : 'false');
|
|
16370
17443
|
if (!opening || children.getAttribute('data-loaded') === 'true') return;
|
|
16371
17444
|
children.setAttribute('data-loading', 'true');
|
|
16372
17445
|
try {
|
|
@@ -16474,8 +17547,7 @@ window.renderNativeEditor = function() {
|
|
|
16474
17547
|
}
|
|
16475
17548
|
window.renderEditorGutter(code);
|
|
16476
17549
|
if (els['editor-language']) els['editor-language'].textContent = language;
|
|
16477
|
-
|
|
16478
|
-
if (els['editor-position']) els['editor-position'].textContent = before.length + ':' + (before[before.length - 1].length + 1);
|
|
17550
|
+
window.renderEditorCaretStatus();
|
|
16479
17551
|
if (els['editor-dirty']) els['editor-dirty'].textContent = code !== state.editorOriginal ? 'modified' : '';
|
|
16480
17552
|
if (els['editor-vim-mode']) els['editor-vim-mode'].textContent = state.editorVimEnabled ? state.editorVimMode.toUpperCase() : 'INSERT';
|
|
16481
17553
|
if (state.editorPreview && els['editor-md-preview']) els['editor-md-preview'].innerHTML = renderMessageContent(code);
|
|
@@ -16517,6 +17589,7 @@ window.editorSetValue = function(value, preserveUndo) {
|
|
|
16517
17589
|
if (!ta) return;
|
|
16518
17590
|
if (!preserveUndo && ta.value !== value) { state.editorUndo.push(ta.value); if (state.editorUndo.length > 100) state.editorUndo.shift(); state.editorRedo = []; }
|
|
16519
17591
|
ta.value = value;
|
|
17592
|
+
state.editorCompletionCache = [];
|
|
16520
17593
|
window.renderNativeEditor();
|
|
16521
17594
|
};
|
|
16522
17595
|
|
|
@@ -16545,23 +17618,100 @@ window.editorReplaceSelection = function(text) {
|
|
|
16545
17618
|
window.renderNativeEditor();
|
|
16546
17619
|
};
|
|
16547
17620
|
|
|
16548
|
-
window.
|
|
17621
|
+
window.applyEditorCompletionDelta = function(payload) {
|
|
17622
|
+
payload = payload || {};
|
|
17623
|
+
if (String(payload.requestId || '') !== String(state.editorCompletionRequest || '')) return;
|
|
17624
|
+
var delta = String(payload.text || '');
|
|
17625
|
+
if (!delta || !state.editorCompletionAnchor) return;
|
|
17626
|
+
state.editorCompletionStreamText = (state.editorCompletionStreamText || '') + delta;
|
|
17627
|
+
state.editorCompletionText = state.editorCompletionStreamText.slice(0, 1200);
|
|
17628
|
+
window.renderEditorGhostText();
|
|
17629
|
+
if (els['editor-completion']) { els['editor-completion'].textContent = ''; els['editor-completion'].classList.remove('open'); }
|
|
17630
|
+
};
|
|
17631
|
+
|
|
17632
|
+
function editorCompletionValueKey(value) {
|
|
17633
|
+
var text = String(value || '');
|
|
17634
|
+
var hash = 2166136261;
|
|
17635
|
+
for (var i = 0; i < text.length; i++) hash = Math.imul(hash ^ text.charCodeAt(i), 16777619);
|
|
17636
|
+
return text.length + ':' + (hash >>> 0);
|
|
17637
|
+
}
|
|
17638
|
+
|
|
17639
|
+
function editorCompletionAnchorKey(anchor) {
|
|
17640
|
+
return [anchor.path, anchor.start, anchor.end, editorCompletionValueKey(anchor.value)].join('\u0000');
|
|
17641
|
+
}
|
|
17642
|
+
|
|
17643
|
+
function editorCompletionCacheFind(anchor) {
|
|
17644
|
+
var cache = Array.isArray(state.editorCompletionCache) ? state.editorCompletionCache : [];
|
|
17645
|
+
state.editorCompletionCache = cache;
|
|
17646
|
+
var now = Date.now();
|
|
17647
|
+
var key = editorCompletionAnchorKey(anchor);
|
|
17648
|
+
for (var i = cache.length - 1; i >= 0; i--) {
|
|
17649
|
+
var item = cache[i];
|
|
17650
|
+
if (!item || item.expiresAt <= now) { cache.splice(i, 1); continue; }
|
|
17651
|
+
if (item.key === key) {
|
|
17652
|
+
cache.splice(i, 1);
|
|
17653
|
+
cache.unshift(item);
|
|
17654
|
+
return item;
|
|
17655
|
+
}
|
|
17656
|
+
}
|
|
17657
|
+
return null;
|
|
17658
|
+
}
|
|
17659
|
+
|
|
17660
|
+
function editorCompletionCachePut(anchor, text, ttl) {
|
|
17661
|
+
var cache = Array.isArray(state.editorCompletionCache) ? state.editorCompletionCache : [];
|
|
17662
|
+
var key = editorCompletionAnchorKey(anchor);
|
|
17663
|
+
state.editorCompletionCache = cache.filter(function(item) { return !item || item.key !== key; });
|
|
17664
|
+
state.editorCompletionCache.unshift({ key: key, text: text, expiresAt: Date.now() + ttl });
|
|
17665
|
+
if (state.editorCompletionCache.length > 16) state.editorCompletionCache.length = 16;
|
|
17666
|
+
}
|
|
17667
|
+
|
|
17668
|
+
window.requestEditorCompletion = async function(options) {
|
|
17669
|
+
options = options || {};
|
|
17670
|
+
var force = options.force === true;
|
|
16549
17671
|
var ta = els['editor-textarea']; if (!ta || !state.editorPath || !api.editorComplete) return;
|
|
16550
17672
|
var requestId = ++state.editorCompletionRequest;
|
|
16551
17673
|
var pos = ta.selectionStart;
|
|
16552
17674
|
var anchor = { path: state.editorPath, value: ta.value, start: pos, end: ta.selectionEnd };
|
|
16553
17675
|
state.editorCompletionAnchor = anchor;
|
|
17676
|
+
var cached = force ? null : editorCompletionCacheFind(anchor);
|
|
17677
|
+
if (cached) {
|
|
17678
|
+
state.editorCompletionInFlight = false;
|
|
17679
|
+
state.editorCompletionStreamText = '';
|
|
17680
|
+
state.editorCompletionText = cached.text || '';
|
|
17681
|
+
state.editorCompletionAnchor = state.editorCompletionText ? anchor : null;
|
|
17682
|
+
window.renderEditorGhostText();
|
|
17683
|
+
if (els['editor-completion']) { els['editor-completion'].textContent = ''; els['editor-completion'].classList.remove('open'); }
|
|
17684
|
+
return;
|
|
17685
|
+
}
|
|
16554
17686
|
if (els['editor-completion']) { els['editor-completion'].textContent = 'Predicting...'; els['editor-completion'].classList.add('open'); }
|
|
16555
|
-
|
|
16556
|
-
|
|
16557
|
-
var
|
|
17687
|
+
state.editorCompletionInFlight = true;
|
|
17688
|
+
state.editorCompletionStreamText = '';
|
|
17689
|
+
var beforeStart = Math.max(0, pos - 3200);
|
|
17690
|
+
var afterEnd = Math.min(ta.value.length, pos + 800);
|
|
17691
|
+
var result;
|
|
17692
|
+
try {
|
|
17693
|
+
result = await api.editorComplete({ requestId: String(requestId), path: state.editorPath, before: ta.value.slice(beforeStart, pos), after: ta.value.slice(pos, afterEnd) });
|
|
17694
|
+
} catch (error) {
|
|
17695
|
+
result = { ok: false, text: '', error: error && error.message ? error.message : String(error) };
|
|
17696
|
+
} finally {
|
|
17697
|
+
if (requestId === state.editorCompletionRequest) state.editorCompletionInFlight = false;
|
|
17698
|
+
}
|
|
16558
17699
|
if (requestId !== state.editorCompletionRequest) return;
|
|
16559
|
-
|
|
16560
|
-
|
|
17700
|
+
// Input/caret handlers already schedule the replacement request. Do not
|
|
17701
|
+
// recursively schedule here: that doubled provider traffic on fast edits.
|
|
17702
|
+
if (!window.editorAnchorMatches(anchor)) return;
|
|
17703
|
+
var suggestion = result && result.ok ? String(result.text || '').slice(0, 1200) : '';
|
|
17704
|
+
if (!suggestion.trim()) suggestion = '';
|
|
17705
|
+
state.editorCompletionText = suggestion;
|
|
17706
|
+
state.editorCompletionStreamText = '';
|
|
17707
|
+
state.editorCompletionAnchor = suggestion ? anchor : null;
|
|
17708
|
+
editorCompletionCachePut(anchor, suggestion, suggestion ? 15000 : 2000);
|
|
16561
17709
|
window.renderEditorGhostText();
|
|
16562
17710
|
if (els['editor-completion']) {
|
|
16563
|
-
|
|
16564
|
-
|
|
17711
|
+
// Empty/aborted/timeout responses are normal for an inline predictor. The
|
|
17712
|
+
// editor should stay quiet instead of flashing an error on every keystroke.
|
|
17713
|
+
els['editor-completion'].textContent = '';
|
|
17714
|
+
els['editor-completion'].classList.remove('open');
|
|
16565
17715
|
}
|
|
16566
17716
|
};
|
|
16567
17717
|
|
|
@@ -16590,7 +17740,7 @@ window.scheduleEditorCompletion = function() {
|
|
|
16590
17740
|
state.editorCompletionTimer = setTimeout(function() {
|
|
16591
17741
|
state.editorCompletionTimer = null;
|
|
16592
17742
|
window.requestEditorCompletion();
|
|
16593
|
-
},
|
|
17743
|
+
}, 300);
|
|
16594
17744
|
};
|
|
16595
17745
|
|
|
16596
17746
|
window.editorCaretSignature = function() {
|
|
@@ -16609,7 +17759,8 @@ window.handleEditorCaretChange = function() {
|
|
|
16609
17759
|
var signature = window.editorCaretSignature();
|
|
16610
17760
|
if (signature === state.editorCaretSignature) return;
|
|
16611
17761
|
state.editorCaretSignature = signature;
|
|
16612
|
-
window.
|
|
17762
|
+
window.renderEditorCaretStatus();
|
|
17763
|
+
window.renderEditorGhostText();
|
|
16613
17764
|
window.scheduleEditorCompletion();
|
|
16614
17765
|
};
|
|
16615
17766
|
|
|
@@ -16617,7 +17768,24 @@ window.acceptEditorCompletion = function() {
|
|
|
16617
17768
|
if (state.editorCompletionText && window.editorCompletionAnchorIsCurrent()) window.editorReplaceSelection(state.editorCompletionText);
|
|
16618
17769
|
window.dismissEditorCompletion();
|
|
16619
17770
|
};
|
|
16620
|
-
window.dismissEditorCompletion = function() {
|
|
17771
|
+
window.dismissEditorCompletion = function() {
|
|
17772
|
+
state.editorCompletionText = '';
|
|
17773
|
+
state.editorCompletionStreamText = '';
|
|
17774
|
+
state.editorCompletionAnchor = null;
|
|
17775
|
+
state.editorCompletionRequest++;
|
|
17776
|
+
if (state.editorCompletionInFlight && api.editorCompleteCancel) {
|
|
17777
|
+
try { Promise.resolve(api.editorCompleteCancel()).catch(function() {}); } catch (_) {}
|
|
17778
|
+
}
|
|
17779
|
+
if (els['editor-completion']) { els['editor-completion'].textContent = ''; els['editor-completion'].classList.remove('open'); }
|
|
17780
|
+
window.renderEditorGhostText();
|
|
17781
|
+
};
|
|
17782
|
+
|
|
17783
|
+
window.renderEditorCaretStatus = function() {
|
|
17784
|
+
var ta = els['editor-textarea'];
|
|
17785
|
+
if (!ta) return;
|
|
17786
|
+
var before = String(ta.value || '').slice(0, ta.selectionStart || 0).split('\n');
|
|
17787
|
+
if (els['editor-position']) els['editor-position'].textContent = before.length + ':' + (before[before.length - 1].length + 1);
|
|
17788
|
+
};
|
|
16621
17789
|
|
|
16622
17790
|
window.requestEditorAssist = async function() {
|
|
16623
17791
|
var ta = els['editor-textarea']; if (!ta || !state.editorPath || !api.editorAssist) return;
|
|
@@ -17223,6 +18391,42 @@ function rememberBrowserUrl(url, force, target) {
|
|
|
17223
18391
|
}
|
|
17224
18392
|
}
|
|
17225
18393
|
|
|
18394
|
+
window.handleFileTreeKey = function(event) {
|
|
18395
|
+
if (!event || event.defaultPrevented || event.isComposing || event.key === 'Process' || event.keyCode === 229 || event.target !== event.currentTarget) return false;
|
|
18396
|
+
var item = event.currentTarget;
|
|
18397
|
+
var root = item.closest('[role="tree"]');
|
|
18398
|
+
if (!root) return false;
|
|
18399
|
+
if (event.key === 'Enter' || event.key === ' ') return window.activateButtonLike(event);
|
|
18400
|
+
if (event.key === 'ArrowRight') {
|
|
18401
|
+
if (item.hasAttribute('aria-expanded') && item.getAttribute('aria-expanded') !== 'true') {
|
|
18402
|
+
event.preventDefault(); item.click(); return true;
|
|
18403
|
+
}
|
|
18404
|
+
var group = item.nextElementSibling;
|
|
18405
|
+
var child = group && group.matches('[role="group"]') ? group.querySelector('[role="treeitem"]') : null;
|
|
18406
|
+
if (child) { event.preventDefault(); child.focus({ preventScroll:true }); return true; }
|
|
18407
|
+
return false;
|
|
18408
|
+
}
|
|
18409
|
+
if (event.key === 'ArrowLeft') {
|
|
18410
|
+
if (item.getAttribute('aria-expanded') === 'true') { event.preventDefault(); item.click(); return true; }
|
|
18411
|
+
var ownerGroup = item.parentElement && item.parentElement.matches('[role="group"]') ? item.parentElement : null;
|
|
18412
|
+
var parentItem = ownerGroup && ownerGroup.previousElementSibling && ownerGroup.previousElementSibling.matches('[role="treeitem"]') ? ownerGroup.previousElementSibling : null;
|
|
18413
|
+
if (parentItem) { event.preventDefault(); parentItem.focus({ preventScroll:true }); return true; }
|
|
18414
|
+
return false;
|
|
18415
|
+
}
|
|
18416
|
+
var visible = Array.prototype.slice.call(root.querySelectorAll('[role="treeitem"]')).filter(function(node) { return node.getClientRects().length > 0; });
|
|
18417
|
+
var index = visible.indexOf(item);
|
|
18418
|
+
var next = index;
|
|
18419
|
+
if (event.key === 'ArrowDown') next = Math.min(visible.length - 1, index + 1);
|
|
18420
|
+
else if (event.key === 'ArrowUp') next = Math.max(0, index - 1);
|
|
18421
|
+
else if (event.key === 'Home') next = 0;
|
|
18422
|
+
else if (event.key === 'End') next = visible.length - 1;
|
|
18423
|
+
else return false;
|
|
18424
|
+
if (next < 0 || !visible[next]) return false;
|
|
18425
|
+
event.preventDefault();
|
|
18426
|
+
visible[next].focus({ preventScroll:true });
|
|
18427
|
+
return true;
|
|
18428
|
+
};
|
|
18429
|
+
|
|
17226
18430
|
function waitForBrowserCreationFloor() {
|
|
17227
18431
|
var remaining = NEWMARK_BROWSER_MIN_CREATE_DELAY_MS - (Date.now() - newmarkRendererStartedAt);
|
|
17228
18432
|
if (remaining <= 0) return Promise.resolve();
|
|
@@ -17555,7 +18759,8 @@ function applyBackendConversations(items, activeId, workspaceId) {
|
|
|
17555
18759
|
updatedAt: item.updatedAt || '',
|
|
17556
18760
|
pinned: !!item.pinned,
|
|
17557
18761
|
pinnedAt: item.pinnedAt || '',
|
|
17558
|
-
order: Number(item.order || 0)
|
|
18762
|
+
order: Number(item.order || 0),
|
|
18763
|
+
branchCommunication: !!item.branchCommunication
|
|
17559
18764
|
});
|
|
17560
18765
|
}
|
|
17561
18766
|
// A stale list response can arrive between creating a conversation locally
|
|
@@ -17682,16 +18887,22 @@ function renderConversations() {
|
|
|
17682
18887
|
}
|
|
17683
18888
|
var div = document.createElement('div');
|
|
17684
18889
|
div.className = 'conv-item' + (conv.active ? ' active' : '');
|
|
18890
|
+
div.setAttribute('role', 'listitem');
|
|
18891
|
+
div.setAttribute('tabindex', conv.active ? '0' : '-1');
|
|
18892
|
+
div.setAttribute('aria-current', conv.active ? 'true' : 'false');
|
|
17685
18893
|
div.setAttribute('draggable', 'true');
|
|
17686
18894
|
div.setAttribute('data-conversation-id', String(conv.id || ''));
|
|
17687
18895
|
if (runtimeState && ['running', 'stopping', 'force_restarting'].indexOf(String(runtimeState.status || '')) >= 0) div.classList.add('marquee-border');
|
|
17688
18896
|
var runtimeBadge = runtimeState && runtimeState.status && runtimeState.status !== 'idle'
|
|
17689
18897
|
? '<span class="conv-runtime-badge ' + escAttr(String(runtimeState.status)) + '">' + esc(String(runtimeState.status)) + '</span>' : '';
|
|
17690
|
-
|
|
18898
|
+
var branchCommBadge = conv.branchCommunication
|
|
18899
|
+
? '<span class="conv-branch-comm-badge" title="' + escAttr(t('conversation.branchCommunicationBadge')) + '">' + esc(t('conversation.branchCommunicationBadge')) + '</span>' : '';
|
|
18900
|
+
div.innerHTML = '<span class="conv-summary" title="' + escAttr(String(conv.id || '')) + '">' + esc(displaySummary) + (conv.messageCount ? ' (' + esc(String(conv.messageCount)) + ')' : '') + '</span>' + branchCommBadge + runtimeBadge +
|
|
17691
18901
|
'<button class="conv-rename-btn" onclick="event.stopPropagation();window.editConversationName(' + i + ')" title="' + escAttr(t('conversation.rename')) + '">' + iconOnly('pencil', t('conversation.rename')) + '</button>' +
|
|
17692
18902
|
'<button class="conv-archive-btn" onclick="event.stopPropagation();window.archiveConv(this.closest(".conv-item").getAttribute("data-conversation-id"))" title="' + escAttr(t('conversation.archive')) + '">' + iconOnly('archive', t('conversation.archive')) + '</button>' +
|
|
17693
18903
|
'<button class="conv-pin-btn' + (conv.pinned ? ' active' : '') + '" onclick="event.stopPropagation();window.toggleConversationPinned(' + i + ')" title="' + escAttr(conv.pinned ? t('conversation.unpin') : t('conversation.pin')) + '">' + iconOnly('pin', conv.pinned ? t('conversation.unpin') : t('conversation.pin')) + '</button>';
|
|
17694
18904
|
div.onclick = function(idx) { return function() { window.switchConversation(idx); }; }(i);
|
|
18905
|
+
div.addEventListener('keydown', window.handleConversationKey);
|
|
17695
18906
|
div.addEventListener('dragstart', function(event) {
|
|
17696
18907
|
this.classList.add('dragging');
|
|
17697
18908
|
if (event.dataTransfer) { event.dataTransfer.effectAllowed = 'move'; event.dataTransfer.setData('text/plain', this.getAttribute('data-conversation-id') || ''); }
|
|
@@ -17721,6 +18932,30 @@ function renderConversations() {
|
|
|
17721
18932
|
updateWorkspaceGate();
|
|
17722
18933
|
}
|
|
17723
18934
|
|
|
18935
|
+
window.handleConversationKey = function(event) {
|
|
18936
|
+
if (!event || event.defaultPrevented || event.isComposing || event.key === 'Process' || event.keyCode === 229 || event.target !== event.currentTarget) return false;
|
|
18937
|
+
if (event.key === 'Enter' || event.key === ' ') return window.activateButtonLike(event);
|
|
18938
|
+
var items = Array.prototype.slice.call(document.querySelectorAll('#conversation-list .conv-item'));
|
|
18939
|
+
var index = items.indexOf(event.currentTarget);
|
|
18940
|
+
if (index < 0 || !items.length) return false;
|
|
18941
|
+
var next = index;
|
|
18942
|
+
if (event.key === 'ArrowDown') next = (index + 1) % items.length;
|
|
18943
|
+
else if (event.key === 'ArrowUp') next = (index - 1 + items.length) % items.length;
|
|
18944
|
+
else if (event.key === 'Home') next = 0;
|
|
18945
|
+
else if (event.key === 'End') next = items.length - 1;
|
|
18946
|
+
else return false;
|
|
18947
|
+
event.preventDefault();
|
|
18948
|
+
var nextId = items[next].getAttribute('data-conversation-id');
|
|
18949
|
+
items[next].click();
|
|
18950
|
+
requestAnimationFrame(function() {
|
|
18951
|
+
var replacement = Array.prototype.slice.call(document.querySelectorAll('#conversation-list .conv-item')).find(function(item) {
|
|
18952
|
+
return item.getAttribute('data-conversation-id') === nextId;
|
|
18953
|
+
});
|
|
18954
|
+
if (replacement) replacement.focus({ preventScroll:true });
|
|
18955
|
+
});
|
|
18956
|
+
return true;
|
|
18957
|
+
};
|
|
18958
|
+
|
|
17724
18959
|
window.newConversationOld = function() {
|
|
17725
18960
|
var id = 'conv-' + Date.now();
|
|
17726
18961
|
var summary = t('left.newChat') + ' ' + (state.conversations.length + 1);
|
|
@@ -17754,7 +18989,7 @@ window.archiveConvOld = function(idx) {
|
|
|
17754
18989
|
}
|
|
17755
18990
|
};
|
|
17756
18991
|
|
|
17757
|
-
window.newConversation = function(workspaceReference) {
|
|
18992
|
+
window.newConversation = function(workspaceReference, branchCommunication) {
|
|
17758
18993
|
if (workspaceReference && workspaceReference !== state.currentWorkspaceId) {
|
|
17759
18994
|
window.selectWorkspace(workspaceReference);
|
|
17760
18995
|
}
|
|
@@ -17784,6 +19019,13 @@ window.newConversation = function(workspaceReference) {
|
|
|
17784
19019
|
if (createdWorkspaceKey !== currentWorkspaceKey() || id !== String(activeConversationId() || 'default')) return;
|
|
17785
19020
|
state.activeBackendConversationId = String((s && s.conversationId) || id);
|
|
17786
19021
|
if (s) applyConversationSnapshot(s, id);
|
|
19022
|
+
if (branchCommunication && api.setConversationBranchCommunication) {
|
|
19023
|
+
api.setConversationBranchCommunication(target, true).then(function() {
|
|
19024
|
+
var convsNow = currentWorkspaceConversations();
|
|
19025
|
+
var created = convsNow.find(function(item){ return String(item && item.id) === id; });
|
|
19026
|
+
if (created) { created.branchCommunication = true; renderConversations(); }
|
|
19027
|
+
}).catch(function(){});
|
|
19028
|
+
}
|
|
17787
19029
|
}).then(function() {
|
|
17788
19030
|
if (createdWorkspaceKey !== currentWorkspaceKey() || id !== String(activeConversationId() || 'default')) return;
|
|
17789
19031
|
state.foregroundConversationHoldId = '';
|
|
@@ -17810,6 +19052,7 @@ window.showNewConversationPage = function() {
|
|
|
17810
19052
|
var html = '<div style="display:flex;flex-direction:column;gap:12px;padding:4px 2px;">' +
|
|
17811
19053
|
'<div style="font-size:12px;color:var(--text-dim);line-height:1.5;">' + esc(t('workspace.newConversationDesc')) + '</div>' +
|
|
17812
19054
|
'<div class="auto-input-group"><label>' + esc(t('status.workspace')) + '</label><select id="new-conv-ws">' + options + '</select></div>' +
|
|
19055
|
+
'<div class="auto-input-group" style="flex-direction:row;align-items:center;gap:8px;"><label style="display:flex;align-items:center;gap:6px;cursor:pointer;font-size:12px;"><input type="checkbox" id="new-conv-branch-comm" style="accent-color:var(--accent);">' + esc(t('conversation.branchCommunication')) + '</label></div>' +
|
|
17813
19056
|
'<div style="display:flex;gap:8px;">' +
|
|
17814
19057
|
'<button class="sec-btn primary" style="flex:1;" onclick="window.doNewConversationFromPage()">' + esc(t('workspace.createConversation')) + '</button>' +
|
|
17815
19058
|
'<button class="sec-btn" style="flex:1;" onclick="window.showNewWorkspaceDialog()">' + esc(t('workspace.createAction')) + '</button>' +
|
|
@@ -17826,11 +19069,13 @@ window.doNewConversationFromPage = function() {
|
|
|
17826
19069
|
window.showNewWorkspaceDialog();
|
|
17827
19070
|
return;
|
|
17828
19071
|
}
|
|
19072
|
+
var branchComm = document.getElementById('new-conv-branch-comm');
|
|
19073
|
+
var branchCommunication = !!(branchComm && branchComm.checked);
|
|
17829
19074
|
window.switchToWorkspace(identity).then(function(ws) {
|
|
17830
19075
|
state.currentWorkspace = (ws && ws.name) || state.currentWorkspace;
|
|
17831
19076
|
state.currentWorkspaceId = workspaceIdentity(ws) || state.currentWorkspaceId || identity;
|
|
17832
19077
|
window.closeSubWin();
|
|
17833
|
-
window.newConversation(state.currentWorkspaceId);
|
|
19078
|
+
window.newConversation(state.currentWorkspaceId, branchCommunication);
|
|
17834
19079
|
}).catch(function(err) {
|
|
17835
19080
|
showUiNotice(t('workspace.selectAction') + ': ' + err.message, 'error', 'workspace-new-conversation-' + identity);
|
|
17836
19081
|
});
|
|
@@ -17963,6 +19208,25 @@ window.archiveConv = function(conversationId) {
|
|
|
17963
19208
|
state.activeBackendConversationId = nextActiveId;
|
|
17964
19209
|
if (els['chat-area']) els['chat-area'].innerHTML = '';
|
|
17965
19210
|
}
|
|
19211
|
+
// Archiving is a destructive handoff: remove the target's Flow takeover
|
|
19212
|
+
// locally at click time as well as removing its conversation row. The
|
|
19213
|
+
// backend cancellation/manifest write is asynchronous; a late Flow
|
|
19214
|
+
// promise must not leave a visible running bubble over the replacement
|
|
19215
|
+
// conversation while the archive is already in flight.
|
|
19216
|
+
if (state.flowTakeovers) {
|
|
19217
|
+
var archivedFlowKey = runtimeKeyFor(targetRuntime.workspaceId, targetRuntime.conversationId);
|
|
19218
|
+
var archivedFlowRecord = state.flowTakeovers[archivedFlowKey];
|
|
19219
|
+
if (archivedFlowRecord) {
|
|
19220
|
+
archivedFlowRecord.running = false;
|
|
19221
|
+
archivedFlowRecord.paused = false;
|
|
19222
|
+
archivedFlowRecord.runtimeLease = null;
|
|
19223
|
+
archivedFlowRecord.queueLease = null;
|
|
19224
|
+
delete state.flowTakeovers[archivedFlowKey];
|
|
19225
|
+
}
|
|
19226
|
+
if (priorActiveId === targetId && window.renderFlowTakeover) {
|
|
19227
|
+
window.renderFlowTakeover(false, '', { target: targetRuntime });
|
|
19228
|
+
}
|
|
19229
|
+
}
|
|
17966
19230
|
setConversationRuntimeState(targetRuntime, 'idle', '');
|
|
17967
19231
|
setWorking(!!runningConversationRecord(activeConversationId()));
|
|
17968
19232
|
renderConversations();
|
|
@@ -18809,37 +20073,117 @@ window.reindexMemoryLab = function() {
|
|
|
18809
20073
|
});
|
|
18810
20074
|
};
|
|
18811
20075
|
|
|
18812
|
-
// === Plugin
|
|
18813
|
-
|
|
18814
|
-
|
|
20076
|
+
// === Plugin / Skills Market ===
|
|
20077
|
+
var PLUGIN_TABS = ['mcp', 'dsh', 'installed', 'market', 'github'];
|
|
20078
|
+
|
|
20079
|
+
function pluginText(key, values) {
|
|
20080
|
+
var output = t(key);
|
|
20081
|
+
Object.keys(values || {}).forEach(function(name) {
|
|
20082
|
+
output = output.replace(new RegExp('\\{' + name + '\\}', 'g'), function() { return String(values[name]); });
|
|
20083
|
+
});
|
|
20084
|
+
return output;
|
|
20085
|
+
}
|
|
20086
|
+
|
|
20087
|
+
function pluginRequestActive(tab, generation) {
|
|
20088
|
+
return generation === state.pluginPanelGeneration
|
|
20089
|
+
&& state.pluginActiveTab === tab
|
|
20090
|
+
&& !!(state.activeSubWindowView && state.activeSubWindowView.name === 'plugins')
|
|
20091
|
+
&& !!(els['sub-win-overlay'] && els['sub-win-overlay'].classList.contains('open'))
|
|
20092
|
+
&& !!document.getElementById('plugin-panel');
|
|
20093
|
+
}
|
|
20094
|
+
|
|
20095
|
+
function pluginPanelState(message, kind, retryCall) {
|
|
20096
|
+
return '<div class="plugin-panel-state' + (kind === 'error' ? ' error' : '') + '" role="' + (kind === 'error' ? 'alert' : 'status') + '"' + (kind === 'loading' ? ' aria-live="polite" aria-busy="true"' : '') + '>' +
|
|
20097
|
+
'<span>' + esc(message) + '</span>' +
|
|
20098
|
+
(retryCall ? '<button type="button" class="sec-btn" onclick="' + retryCall + '">' + esc(t('plugins.retry')) + '</button>' : '') +
|
|
20099
|
+
'</div>';
|
|
20100
|
+
}
|
|
20101
|
+
|
|
20102
|
+
function pluginTabMarkup(tab, label) {
|
|
20103
|
+
var selected = state.pluginActiveTab === tab;
|
|
20104
|
+
return '<button type="button" class="stab-btn' + (selected ? ' active' : '') + '" id="plugin-tab-' + tab + '" role="tab" aria-selected="' + (selected ? 'true' : 'false') + '" aria-controls="plugin-panel" tabindex="' + (selected ? '0' : '-1') + '" data-plugin-tab="' + tab + '" onclick="window.selectPluginTab(\'' + tab + '\')" onkeydown="window.handlePluginTabKey(event)">' + esc(label) + '</button>';
|
|
20105
|
+
}
|
|
20106
|
+
|
|
20107
|
+
window.syncPluginTabs = function(focusTab) {
|
|
20108
|
+
var labels = { mcp: t('plugins.tabMcp'), dsh: t('plugins.tabDsh'), installed: t('plugins.tabSkills'), market: t('plugins.tabMarket'), github: t('plugins.tabGithub') };
|
|
20109
|
+
PLUGIN_TABS.forEach(function(tab) {
|
|
20110
|
+
var button = document.getElementById('plugin-tab-' + tab);
|
|
20111
|
+
if (!button) return;
|
|
20112
|
+
var selected = tab === state.pluginActiveTab;
|
|
20113
|
+
button.classList.toggle('active', selected);
|
|
20114
|
+
button.setAttribute('aria-selected', selected ? 'true' : 'false');
|
|
20115
|
+
button.tabIndex = selected ? 0 : -1;
|
|
20116
|
+
button.textContent = labels[tab];
|
|
20117
|
+
});
|
|
20118
|
+
var tablist = document.querySelector('.plugin-tabs[role="tablist"]');
|
|
20119
|
+
if (tablist) tablist.setAttribute('aria-label', t('plugins.title'));
|
|
20120
|
+
if (els['sub-win-title']) els['sub-win-title'].textContent = t('plugins.title');
|
|
20121
|
+
var panel = document.getElementById('plugin-panel');
|
|
20122
|
+
if (panel) panel.setAttribute('aria-labelledby', 'plugin-tab-' + state.pluginActiveTab);
|
|
20123
|
+
if (focusTab) {
|
|
20124
|
+
var activeButton = document.getElementById('plugin-tab-' + state.pluginActiveTab);
|
|
20125
|
+
if (activeButton) activeButton.focus({ preventScroll: true });
|
|
20126
|
+
}
|
|
18815
20127
|
};
|
|
18816
20128
|
|
|
18817
|
-
|
|
18818
|
-
|
|
18819
|
-
var
|
|
18820
|
-
|
|
18821
|
-
|
|
18822
|
-
|
|
18823
|
-
|
|
18824
|
-
|
|
18825
|
-
|
|
18826
|
-
|
|
18827
|
-
|
|
18828
|
-
|
|
18829
|
-
|
|
18830
|
-
window.
|
|
18831
|
-
|
|
18832
|
-
|
|
18833
|
-
|
|
18834
|
-
|
|
20129
|
+
window.handlePluginTabKey = function(event) {
|
|
20130
|
+
if (!event || PLUGIN_TABS.indexOf(state.pluginActiveTab) < 0) return;
|
|
20131
|
+
var index = PLUGIN_TABS.indexOf(state.pluginActiveTab);
|
|
20132
|
+
if (event.key === 'ArrowRight') index = (index + 1) % PLUGIN_TABS.length;
|
|
20133
|
+
else if (event.key === 'ArrowLeft') index = (index - 1 + PLUGIN_TABS.length) % PLUGIN_TABS.length;
|
|
20134
|
+
else if (event.key === 'Home') index = 0;
|
|
20135
|
+
else if (event.key === 'End') index = PLUGIN_TABS.length - 1;
|
|
20136
|
+
else return;
|
|
20137
|
+
event.preventDefault();
|
|
20138
|
+
window.showPluginList(PLUGIN_TABS[index], { focusTab: true });
|
|
20139
|
+
};
|
|
20140
|
+
|
|
20141
|
+
window.selectPluginTab = function(tab) {
|
|
20142
|
+
window.showPluginList(tab, { focusTab: false });
|
|
20143
|
+
};
|
|
20144
|
+
|
|
20145
|
+
window.showPluginList = function(tab, options) {
|
|
20146
|
+
var requested = PLUGIN_TABS.indexOf(tab) >= 0 ? tab : (PLUGIN_TABS.indexOf(state.pluginActiveTab) >= 0 ? state.pluginActiveTab : 'mcp');
|
|
20147
|
+
var overlayOpen = !!(els['sub-win-overlay'] && els['sub-win-overlay'].classList.contains('open'));
|
|
20148
|
+
var pluginOpen = overlayOpen && state.activeSubWindowView && state.activeSubWindowView.name === 'plugins' && !!document.getElementById('plugin-panel');
|
|
20149
|
+
state.pluginActiveTab = requested;
|
|
20150
|
+
state.pluginPanelGeneration++;
|
|
20151
|
+
if (!pluginOpen) {
|
|
20152
|
+
var html = '<div class="settings-tabs plugin-tabs" role="tablist" aria-label="' + escAttr(t('plugins.title')) + '">' +
|
|
20153
|
+
pluginTabMarkup('mcp', t('plugins.tabMcp')) +
|
|
20154
|
+
pluginTabMarkup('dsh', t('plugins.tabDsh')) +
|
|
20155
|
+
pluginTabMarkup('installed', t('plugins.tabSkills')) +
|
|
20156
|
+
pluginTabMarkup('market', t('plugins.tabMarket')) +
|
|
20157
|
+
pluginTabMarkup('github', t('plugins.tabGithub')) +
|
|
20158
|
+
'</div><div id="plugin-panel" class="plugin-panel" role="tabpanel" tabindex="0" aria-labelledby="plugin-tab-' + requested + '"></div>';
|
|
20159
|
+
if (overlayOpen && state.activeSubWindowView) {
|
|
20160
|
+
window.openSubWin(t('plugins.title'), html);
|
|
20161
|
+
state.activeSubWindowView = { name: 'plugins', tab: requested };
|
|
20162
|
+
} else {
|
|
20163
|
+
state.activeSubWindowView = { name: 'plugins', tab: requested };
|
|
20164
|
+
window.openSubWin(t('plugins.title'), html);
|
|
20165
|
+
}
|
|
20166
|
+
if (els['sub-win']) els['sub-win'].classList.remove('memory-lab-window');
|
|
20167
|
+
} else {
|
|
20168
|
+
state.activeSubWindowView = { name: 'plugins', tab: requested };
|
|
20169
|
+
}
|
|
20170
|
+
window.syncPluginTabs(!pluginOpen || !!(options && options.focusTab));
|
|
20171
|
+
var panel = document.getElementById('plugin-panel');
|
|
20172
|
+
if (panel) panel.replaceChildren();
|
|
20173
|
+
if (requested === 'mcp') window.renderMcpManager();
|
|
20174
|
+
else if (requested === 'dsh') window.renderDshPlugin();
|
|
20175
|
+
else if (requested === 'market') window.renderSkillsMarket();
|
|
20176
|
+
else if (requested === 'github') window.renderGithubCliPanel();
|
|
18835
20177
|
else window.renderInstalledSkills();
|
|
18836
20178
|
};
|
|
18837
20179
|
|
|
18838
20180
|
window.renderInstalledSkills = function() {
|
|
18839
20181
|
var panel = document.getElementById('plugin-panel');
|
|
18840
|
-
if (!panel) return;
|
|
20182
|
+
if (!panel || state.pluginActiveTab !== 'installed') return;
|
|
20183
|
+
var generation = ++state.pluginPanelGeneration;
|
|
18841
20184
|
var render = function(items) {
|
|
18842
20185
|
state.skills = items || [];
|
|
20186
|
+
if (!pluginRequestActive('installed', generation)) return;
|
|
18843
20187
|
if (!items || !items.length) {
|
|
18844
20188
|
panel.innerHTML = '<div style="font-size:12px;color:var(--text-dim);padding:18px;text-align:center;">' + esc(t('plugins.noInstalled')) + '</div>';
|
|
18845
20189
|
return;
|
|
@@ -18880,14 +20224,15 @@ window.refreshSkillsRuntime = function(next) {
|
|
|
18880
20224
|
|
|
18881
20225
|
window.renderSkillsMarket = function() {
|
|
18882
20226
|
var panel = document.getElementById('plugin-panel');
|
|
18883
|
-
if (!panel) return;
|
|
20227
|
+
if (!panel || state.pluginActiveTab !== 'market') return;
|
|
20228
|
+
var generation = ++state.pluginPanelGeneration;
|
|
18884
20229
|
panel.innerHTML = '<div class="provider-card marquee-border">' + esc(t('plugins.discovering')) + '</div>';
|
|
18885
20230
|
state._skillMarketAll = [];
|
|
18886
20231
|
state._skillMarketSources = [];
|
|
18887
20232
|
var done = 0;
|
|
18888
20233
|
var finish = function() {
|
|
18889
20234
|
done++;
|
|
18890
|
-
if (done >= 2) window.renderSkillsMarketList();
|
|
20235
|
+
if (done >= 2 && pluginRequestActive('market', generation)) window.renderSkillsMarketList();
|
|
18891
20236
|
};
|
|
18892
20237
|
if (api.marketSkillSources) api.marketSkillSources().then(function(sources) {
|
|
18893
20238
|
state._skillMarketSources = sources || [];
|
|
@@ -18901,88 +20246,466 @@ window.renderSkillsMarket = function() {
|
|
|
18901
20246
|
else finish();
|
|
18902
20247
|
};
|
|
18903
20248
|
|
|
20249
|
+
var DSH_OFFICIAL_URLS = {
|
|
20250
|
+
repo: 'https://github.com/deepseek-ai/deepseek-harness',
|
|
20251
|
+
docs: 'https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/user/develop/basic/publish.md',
|
|
20252
|
+
npm: 'https://www.npmjs.com/package/@deepseek-ai/dsh'
|
|
20253
|
+
};
|
|
20254
|
+
|
|
20255
|
+
function dshCollection(value) {
|
|
20256
|
+
if (Array.isArray(value)) return value;
|
|
20257
|
+
if (value && typeof value === 'object') return Object.keys(value).map(function(key) {
|
|
20258
|
+
var item = value[key];
|
|
20259
|
+
if (item && typeof item === 'object' && !Array.isArray(item)) return Object.assign({ name: key }, item);
|
|
20260
|
+
return { name: key, value: item };
|
|
20261
|
+
});
|
|
20262
|
+
return [];
|
|
20263
|
+
}
|
|
20264
|
+
|
|
20265
|
+
function dshDisplayValue(value) {
|
|
20266
|
+
if (value === undefined || value === null || value === '') return t('plugins.dshNotAvailable');
|
|
20267
|
+
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') return String(value);
|
|
20268
|
+
try { return JSON.stringify(value); } catch (_) { return String(value); }
|
|
20269
|
+
}
|
|
20270
|
+
|
|
20271
|
+
function dshUniqueStrings(values) {
|
|
20272
|
+
var seen = Object.create(null);
|
|
20273
|
+
return dshCollection(values).map(function(value) {
|
|
20274
|
+
return typeof value === 'string' ? value : dshDisplayValue(value);
|
|
20275
|
+
}).filter(function(value) {
|
|
20276
|
+
var key = String(value || '');
|
|
20277
|
+
if (!key || seen[key]) return false;
|
|
20278
|
+
seen[key] = true;
|
|
20279
|
+
return true;
|
|
20280
|
+
});
|
|
20281
|
+
}
|
|
20282
|
+
|
|
20283
|
+
function dshListMarkup(items, emptyText, warning) {
|
|
20284
|
+
var values = dshCollection(items);
|
|
20285
|
+
if (!values.length) return '<div class="plugin-empty">' + esc(emptyText || t('plugins.dshNone')) + '</div>';
|
|
20286
|
+
return '<div class="dsh-list">' + values.map(function(item) {
|
|
20287
|
+
var label = item && typeof item === 'object'
|
|
20288
|
+
? (item.name || item.id || item.path || item.file || item.key || dshDisplayValue(item))
|
|
20289
|
+
: item;
|
|
20290
|
+
var detail = item && typeof item === 'object' ? (item.version || item.source || item.value || item.reason || '') : '';
|
|
20291
|
+
return '<div class="dsh-list-item' + (warning ? ' warning' : '') + '"><strong>' + esc(redactSensitiveText(dshDisplayValue(label))) + '</strong>' + (detail && String(detail) !== String(label) ? '<div class="provider-meta">' + esc(redactSensitiveText(dshDisplayValue(detail))) + '</div>' : '') + '</div>';
|
|
20292
|
+
}).join('') + '</div>';
|
|
20293
|
+
}
|
|
20294
|
+
|
|
20295
|
+
function dshLayerMarkup(profile) {
|
|
20296
|
+
var layers = dshCollection(profile && profile.layers);
|
|
20297
|
+
if (!layers.length) return '<div class="plugin-empty">' + esc(t('plugins.dshNone')) + '</div>';
|
|
20298
|
+
return '<div class="dsh-list">' + layers.map(function(layer, index) {
|
|
20299
|
+
var kind = layer && layer.kind ? String(layer.kind) : 'layer';
|
|
20300
|
+
var order = Number.isFinite(Number(layer && layer.order)) ? Number(layer.order) + 1 : index + 1;
|
|
20301
|
+
var file = layer && (layer.path || layer.file) || '';
|
|
20302
|
+
return '<div class="dsh-list-item"><strong>' + esc(order + '. ' + kind + (layer && layer.name ? ' · ' + layer.name : '')) + '</strong>' +
|
|
20303
|
+
(file ? '<div class="provider-meta">' + esc(redactSensitiveText(file)) + '</div>' : '') + '</div>';
|
|
20304
|
+
}).join('') + '</div>';
|
|
20305
|
+
}
|
|
20306
|
+
|
|
20307
|
+
window.openDshOfficial = function(kind) {
|
|
20308
|
+
var url = DSH_OFFICIAL_URLS[kind];
|
|
20309
|
+
if (!url || !api.openWebUrl) {
|
|
20310
|
+
showUiNotice(t('plugins.dshUnavailable'), 'error', 'dsh-web-url');
|
|
20311
|
+
return;
|
|
20312
|
+
}
|
|
20313
|
+
var generation = state.pluginPanelGeneration;
|
|
20314
|
+
Promise.resolve(api.openWebUrl(url)).then(function(result) {
|
|
20315
|
+
if (result && (result.ok === false || result.success === false || result.error)) throw new Error(result.error || t('plugins.dshUnavailable'));
|
|
20316
|
+
}).catch(function(error) {
|
|
20317
|
+
if (pluginRequestActive('dsh', generation)) showUiNotice(error && error.message ? error.message : String(error), 'error', 'dsh-web-url');
|
|
20318
|
+
});
|
|
20319
|
+
};
|
|
20320
|
+
|
|
20321
|
+
window.renderDshPlugin = function() {
|
|
20322
|
+
var panel = document.getElementById('plugin-panel');
|
|
20323
|
+
if (!panel || state.pluginActiveTab !== 'dsh') return;
|
|
20324
|
+
var generation = ++state.pluginPanelGeneration;
|
|
20325
|
+
panel.innerHTML = pluginPanelState(t('plugins.dshScanning'), 'loading');
|
|
20326
|
+
if (!api.discoverDshCompatibility) {
|
|
20327
|
+
panel.innerHTML = pluginPanelState(t('plugins.dshUnavailable'), 'error');
|
|
20328
|
+
return;
|
|
20329
|
+
}
|
|
20330
|
+
Promise.resolve(api.discoverDshCompatibility()).then(function(snapshot) {
|
|
20331
|
+
if (!pluginRequestActive('dsh', generation)) return;
|
|
20332
|
+
state.dshCompatibility = snapshot && typeof snapshot === 'object' ? snapshot : {};
|
|
20333
|
+
window.renderDshPluginContent();
|
|
20334
|
+
}).catch(function(error) {
|
|
20335
|
+
if (!pluginRequestActive('dsh', generation)) return;
|
|
20336
|
+
var message = t('plugins.dshLoadError') + (error && error.message ? ' ' + error.message : '');
|
|
20337
|
+
panel.innerHTML = pluginPanelState(message, 'error', 'window.renderDshPlugin()');
|
|
20338
|
+
});
|
|
20339
|
+
};
|
|
20340
|
+
|
|
20341
|
+
window.renderDshPluginContent = function() {
|
|
20342
|
+
var panel = document.getElementById('plugin-panel');
|
|
20343
|
+
if (!panel || state.pluginActiveTab !== 'dsh') return;
|
|
20344
|
+
var dsh = state.dshCompatibility || {};
|
|
20345
|
+
var cli = dsh.cli && typeof dsh.cli === 'object' ? dsh.cli : {};
|
|
20346
|
+
var pkg = dsh.package && typeof dsh.package === 'object' ? dsh.package : {};
|
|
20347
|
+
var update = dsh.update && typeof dsh.update === 'object' ? dsh.update : {};
|
|
20348
|
+
var cliPath = cli.path || cli.executable || cli.commandPath || dsh.cliPath || '';
|
|
20349
|
+
var cliVersion = cli.version || dsh.cliVersion || '';
|
|
20350
|
+
var packageVersion = pkg.version || (cli.package && cli.package.version) || cli.packageVersion || dsh.packageVersion || '';
|
|
20351
|
+
var updateChannel = update.channel || update.tag || dsh.updateChannel || '';
|
|
20352
|
+
var updateLocked = update.locked === true || update.versionLocked === true || update.isLocked === true;
|
|
20353
|
+
if (String(updateChannel).toLowerCase() === 'latest' && !updateLocked) updateChannel = t('plugins.dshLatestChannel');
|
|
20354
|
+
var candidates = dshCollection(dsh.mcpCandidates);
|
|
20355
|
+
var configFiles = dshCollection(dsh.configFiles);
|
|
20356
|
+
dshCollection(dsh.profiles).forEach(function(profile) {
|
|
20357
|
+
if (profile && typeof profile === 'object') configFiles = configFiles.concat(dshCollection(profile.configFiles));
|
|
20358
|
+
});
|
|
20359
|
+
configFiles = dshUniqueStrings(configFiles);
|
|
20360
|
+
var html = '<section class="dsh-hero" id="dsh-hero" aria-labelledby="dsh-title">' +
|
|
20361
|
+
'<div class="dsh-hero-head"><div class="dsh-hero-copy"><div class="dsh-title" id="dsh-title">' + esc(t('plugins.dshTitle')) + '</div>' +
|
|
20362
|
+
'<div class="dsh-description">' + esc(t('plugins.dshHelp')) + '</div></div><span class="plugin-status-badge preview">' + esc(t('plugins.dshPreview')) + '</span></div>' +
|
|
20363
|
+
'<div class="dsh-actions"><button type="button" class="sec-btn primary" id="dsh-rescan" onclick="window.renderDshPlugin()">' + esc(t('plugins.dshRescan')) + '</button>' +
|
|
20364
|
+
'<button type="button" class="sec-btn" id="dsh-official-repo" onclick="window.openDshOfficial(\'repo\')">' + esc(t('plugins.dshOfficialRepo')) + '</button>' +
|
|
20365
|
+
'<button type="button" class="sec-btn" id="dsh-official-docs" onclick="window.openDshOfficial(\'docs\')">' + esc(t('plugins.dshOfficialDocs')) + '</button>' +
|
|
20366
|
+
'<button type="button" class="sec-btn" id="dsh-official-npm" onclick="window.openDshOfficial(\'npm\')">' + esc(t('plugins.dshOfficialNpm')) + '</button></div></section>';
|
|
20367
|
+
html += '<div class="dsh-grid">' +
|
|
20368
|
+
'<section class="dsh-card" id="dsh-cli-card"><div class="dsh-card-title">' + esc(t('plugins.dshCli')) + '</div><dl class="dsh-kv">' +
|
|
20369
|
+
'<dt>' + esc(t('plugins.dshCliPath')) + '</dt><dd id="dsh-cli-path">' + esc(redactSensitiveText(dshDisplayValue(cliPath))) + '</dd>' +
|
|
20370
|
+
'<dt>' + esc(t('plugins.dshCliVersion')) + '</dt><dd id="dsh-cli-version">' + esc(dshDisplayValue(cliVersion)) + '</dd>' +
|
|
20371
|
+
'<dt>' + esc(t('plugins.dshPackageVersion')) + '</dt><dd id="dsh-package-version">' + esc(dshDisplayValue(packageVersion)) + '</dd></dl></section>' +
|
|
20372
|
+
'<section class="dsh-card" id="dsh-runtime-card"><div class="dsh-card-title">' + esc(t('plugins.dshReadonly')) + '</div><dl class="dsh-kv">' +
|
|
20373
|
+
'<dt>' + esc(t('plugins.dshHome')) + '</dt><dd id="dsh-home">' + esc(redactSensitiveText(dshDisplayValue(dsh.dshHome || dsh.home))) + '</dd>' +
|
|
20374
|
+
'<dt>' + esc(t('plugins.dshHomeSource')) + '</dt><dd id="dsh-home-source">' + esc(redactSensitiveText(dshDisplayValue(dsh.dshHomeSource || dsh.homeSource || (dsh.home && dsh.home.source)))) + '</dd>' +
|
|
20375
|
+
'<dt>' + esc(t('plugins.dshUpdateChannel')) + '</dt><dd id="dsh-update-channel">' + esc(dshDisplayValue(updateChannel)) + '</dd></dl>' +
|
|
20376
|
+
'<div class="dsh-description">' + esc(t('plugins.dshReadonlyDetail')) + '</div></section>' +
|
|
20377
|
+
'<section class="dsh-card" id="dsh-profiles-card"><div class="dsh-card-title">' + esc(t('plugins.dshProfiles')) + '</div>' + dshListMarkup(dsh.profiles) + '</section>' +
|
|
20378
|
+
'<section class="dsh-card" id="dsh-bundles-card"><div class="dsh-card-title">' + esc(t('plugins.dshBundles')) + '</div>' + dshListMarkup(dsh.bundles) + '</section>' +
|
|
20379
|
+
'<section class="dsh-card" id="dsh-warnings-card"><div class="dsh-card-title">' + esc(t('plugins.dshWarnings')) + '</div>' + dshListMarkup(dsh.warnings, t('plugins.dshNone'), true) + '</section>' +
|
|
20380
|
+
'<section class="dsh-card" id="dsh-unknown-keys-card"><div class="dsh-card-title">' + esc(t('plugins.dshUnknownKeys')) + '</div>' + dshListMarkup(dsh.unknownKeys) + '</section></div>';
|
|
20381
|
+
html += '<section class="plugin-section" id="dsh-config-files"><div class="plugin-section-head"><div class="plugin-section-title">' + esc(t('plugins.dshConfigFiles')) + '</div><span class="plugin-count-badge">' + configFiles.length + '</span></div>' + dshListMarkup(configFiles) + '</section>';
|
|
20382
|
+
html += '<section class="plugin-section" id="dsh-layers"><div class="plugin-section-head"><div class="plugin-section-title">' + esc(t('plugins.dshLayers')) + '</div></div><div class="mcp-field-help">' + esc(t('plugins.dshLayerOrder')) + '</div>';
|
|
20383
|
+
dshCollection(dsh.profiles).forEach(function(profile) {
|
|
20384
|
+
html += '<div class="dsh-layer-profile"><div class="plugin-section-title">' + esc(profile && (profile.name || profile.source) || t('plugins.dshNotAvailable')) + '</div>' + dshLayerMarkup(profile) + '</div>';
|
|
20385
|
+
});
|
|
20386
|
+
var homeFiles = dshCollection(dsh.homeConfigFiles);
|
|
20387
|
+
if (homeFiles.length) html += '<div class="dsh-layer-profile"><div class="plugin-section-title">' + esc(t('plugins.dshHomePatches')) + '</div>' + dshListMarkup(homeFiles) + '</div>';
|
|
20388
|
+
html += '<div class="mcp-field-help">' + esc(t('plugins.dshUpdateability')) + '</div></section>';
|
|
20389
|
+
html += '<section class="plugin-section" id="dsh-mcp-candidates"><div class="plugin-section-head"><div class="plugin-section-title">' + esc(t('plugins.dshMcpCandidates')) + '</div><span class="plugin-count-badge">' + candidates.length + '</span></div>' +
|
|
20390
|
+
'<div class="mcp-field-help">' + esc(t('plugins.mcpCandidateHelp')) + '</div>';
|
|
20391
|
+
if (!candidates.length) html += '<div class="plugin-empty">' + esc(t('plugins.dshNone')) + '</div>';
|
|
20392
|
+
candidates.forEach(function(candidate, index) {
|
|
20393
|
+
var name = candidate && (candidate.name || candidate.id) || ('MCP ' + (index + 1));
|
|
20394
|
+
var source = candidate && (candidate.source || candidate.path) || '';
|
|
20395
|
+
var reason = candidate && candidate.reason || '';
|
|
20396
|
+
var importable = !!(candidate && candidate.importable && candidate.template);
|
|
20397
|
+
html += '<div class="mcp-server-row" id="dsh-candidate-' + index + '" data-dsh-candidate-index="' + index + '"><div class="mcp-server-copy"><div class="mcp-server-title">' + esc(name) +
|
|
20398
|
+
'<span class="plugin-status-badge">' + esc(importable ? t('plugins.mcpReviewImport') : t('plugins.mcpReadonly')) + '</span></div>' +
|
|
20399
|
+
'<div class="mcp-server-meta">' + esc(redactSensitiveText(dshDisplayValue(source))) + '</div>' +
|
|
20400
|
+
(reason ? '<div class="mcp-server-meta">' + esc(redactSensitiveText(dshDisplayValue(reason))) + '</div>' : '') + '</div>' +
|
|
20401
|
+
(importable ? '<div class="mcp-row-actions"><button type="button" class="sec-btn" id="dsh-candidate-review-' + index + '" onclick="window.reviewDshMcpCandidate(' + index + ')">' + esc(t('plugins.mcpReviewImport')) + '</button></div>' : '') + '</div>';
|
|
20402
|
+
});
|
|
20403
|
+
html += '</section>';
|
|
20404
|
+
panel.innerHTML = html;
|
|
20405
|
+
};
|
|
20406
|
+
|
|
20407
|
+
function newMcpDraft(input, source) {
|
|
20408
|
+
input = input && typeof input === 'object' ? input : {};
|
|
20409
|
+
var transport = input.transport === 'http' ? 'http' : 'stdio';
|
|
20410
|
+
return {
|
|
20411
|
+
id: input.id || '',
|
|
20412
|
+
source: source || 'add',
|
|
20413
|
+
name: String(input.name || ''),
|
|
20414
|
+
transport: transport,
|
|
20415
|
+
command: String(input.command || ''),
|
|
20416
|
+
url: String(input.url || ''),
|
|
20417
|
+
argsText: JSON.stringify(Array.isArray(input.args) ? input.args : [], null, 2),
|
|
20418
|
+
cwd: String(input.cwd || ''),
|
|
20419
|
+
envText: input.env && typeof input.env === 'object' ? JSON.stringify(input.env, null, 2) : '',
|
|
20420
|
+
headersText: input.headers && typeof input.headers === 'object' ? JSON.stringify(input.headers, null, 2) : '',
|
|
20421
|
+
enabled: source === 'candidate' ? false : input.enabled !== false,
|
|
20422
|
+
envKeys: Array.isArray(input.envKeys) ? input.envKeys.slice() : [],
|
|
20423
|
+
headerKeys: Array.isArray(input.headerKeys) ? input.headerKeys.slice() : []
|
|
20424
|
+
};
|
|
20425
|
+
}
|
|
20426
|
+
|
|
20427
|
+
window.reviewDshMcpCandidate = function(index) {
|
|
20428
|
+
var candidates = dshCollection(state.dshCompatibility && state.dshCompatibility.mcpCandidates);
|
|
20429
|
+
var candidate = candidates[index];
|
|
20430
|
+
if (!candidate || !candidate.importable || !candidate.template) return;
|
|
20431
|
+
state.mcpEditingId = '';
|
|
20432
|
+
state.mcpDraft = newMcpDraft(Object.assign({}, candidate.template, {
|
|
20433
|
+
enabled: false,
|
|
20434
|
+
envKeys: Array.isArray(candidate.envKeys) ? candidate.envKeys : [],
|
|
20435
|
+
headerKeys: Array.isArray(candidate.headerKeys) ? candidate.headerKeys : []
|
|
20436
|
+
}), 'candidate');
|
|
20437
|
+
state.mcpFormFocusRequested = true;
|
|
20438
|
+
window.showPluginList('mcp');
|
|
20439
|
+
};
|
|
20440
|
+
|
|
18904
20441
|
window.renderMcpManager = function() {
|
|
18905
20442
|
var panel = document.getElementById('plugin-panel');
|
|
18906
|
-
if (!panel) return;
|
|
18907
|
-
|
|
20443
|
+
if (!panel || state.pluginActiveTab !== 'mcp') return;
|
|
20444
|
+
var generation = ++state.pluginPanelGeneration;
|
|
20445
|
+
panel.innerHTML = pluginPanelState(t('plugins.mcpRefreshing'), 'loading');
|
|
18908
20446
|
if (!api.listMcpServers) {
|
|
18909
|
-
panel.innerHTML =
|
|
20447
|
+
panel.innerHTML = pluginPanelState(t('plugins.mcpUnavailable'), 'error');
|
|
18910
20448
|
return;
|
|
18911
20449
|
}
|
|
18912
|
-
api.listMcpServers().then(function(result) {
|
|
20450
|
+
Promise.resolve(api.listMcpServers()).then(function(result) {
|
|
20451
|
+
if (!pluginRequestActive('mcp', generation)) return;
|
|
18913
20452
|
state.mcpServers = Array.isArray(result && result.servers) ? result.servers : [];
|
|
18914
20453
|
state.mcpDiscovered = Array.isArray(result && result.discovered) ? result.discovered : [];
|
|
18915
20454
|
window.renderMcpManagerContent();
|
|
18916
20455
|
}).catch(function(error) {
|
|
18917
|
-
|
|
20456
|
+
if (!pluginRequestActive('mcp', generation)) return;
|
|
20457
|
+
var message = t('plugins.mcpLoadError') + (error && error.message ? ' ' + error.message : '');
|
|
20458
|
+
panel.innerHTML = pluginPanelState(message, 'error', 'window.renderMcpManager()');
|
|
18918
20459
|
});
|
|
18919
20460
|
};
|
|
18920
20461
|
|
|
20462
|
+
function mcpSearchMatch(server, query) {
|
|
20463
|
+
server = server || {};
|
|
20464
|
+
if (!query) return true;
|
|
20465
|
+
var text = [server.name, server.transport, server.command, server.url, server.plugin, server.ecosystem, server.root]
|
|
20466
|
+
.concat(server.args || []).join(' ').toLowerCase();
|
|
20467
|
+
return text.indexOf(query) >= 0;
|
|
20468
|
+
}
|
|
20469
|
+
|
|
20470
|
+
function mcpSecretHelp(keys, keyName) {
|
|
20471
|
+
return keys && keys.length
|
|
20472
|
+
? pluginText(keyName, { keys: keys.join(', ') })
|
|
20473
|
+
: t('plugins.mcpNoSavedKeys');
|
|
20474
|
+
}
|
|
20475
|
+
|
|
20476
|
+
function renderMcpForm() {
|
|
20477
|
+
var draft = state.mcpDraft;
|
|
20478
|
+
if (!draft) return '';
|
|
20479
|
+
var pending = !!state.mcpMutationPending;
|
|
20480
|
+
var titleKey = draft.source === 'candidate' ? 'plugins.mcpReviewTitle' : (draft.id ? 'plugins.mcpEditTitle' : 'plugins.mcpAddTitle');
|
|
20481
|
+
var stdio = draft.transport !== 'http';
|
|
20482
|
+
return '<section class="mcp-form-card" id="mcp-form" aria-labelledby="mcp-form-title" aria-busy="' + (pending ? 'true' : 'false') + '">' +
|
|
20483
|
+
'<div class="mcp-form-head"><div class="mcp-form-copy"><div class="mcp-form-title" id="mcp-form-title">' + esc(t(titleKey)) + '</div><div class="mcp-form-subtitle">' + esc(t('plugins.mcpFormHelp')) + '</div></div></div>' +
|
|
20484
|
+
'<div class="mcp-field-grid"><div class="mcp-field"><label for="mcp-name">' + esc(t('plugins.mcpName')) + '</label><input class="mcp-input" id="mcp-name" value="' + escAttr(draft.name) + '" autocomplete="off"></div>' +
|
|
20485
|
+
'<div class="mcp-field"><label for="mcp-transport">' + esc(t('plugins.mcpTransport')) + '</label><select class="mcp-input" id="mcp-transport" onchange="window.updateMcpTransportForm()"><option value="stdio"' + (stdio ? ' selected' : '') + '>stdio</option><option value="http"' + (!stdio ? ' selected' : '') + '>http</option></select></div></div>' +
|
|
20486
|
+
'<div id="mcp-stdio-fields"' + (stdio ? '' : ' hidden') + '><div class="mcp-field"><label for="mcp-command">' + esc(t('plugins.mcpEndpointStdio')) + '</label><input class="mcp-input" id="mcp-command" value="' + escAttr(draft.command) + '" autocomplete="off"></div>' +
|
|
20487
|
+
'<div class="mcp-field"><label for="mcp-args">' + esc(t('plugins.mcpArgs')) + '</label><textarea class="mcp-input" id="mcp-args" spellcheck="false">' + esc(draft.argsText) + '</textarea></div>' +
|
|
20488
|
+
'<div class="mcp-field"><label for="mcp-cwd">' + esc(t('plugins.mcpCwd')) + '</label><input class="mcp-input" id="mcp-cwd" value="' + escAttr(draft.cwd) + '" autocomplete="off"></div>' +
|
|
20489
|
+
'<div class="mcp-field"><label for="mcp-env">' + esc(t('plugins.mcpEnv')) + '</label><textarea class="mcp-input" id="mcp-env" spellcheck="false" placeholder="{}">' + esc(draft.envText) + '</textarea><div class="mcp-field-help">' + esc(mcpSecretHelp(draft.envKeys, 'plugins.mcpSavedEnvKeys')) + ' ' + esc(t('plugins.mcpSecretsHelp')) + '</div></div></div>' +
|
|
20490
|
+
'<div id="mcp-http-fields"' + (!stdio ? '' : ' hidden') + '><div class="mcp-field"><label for="mcp-url">' + esc(t('plugins.mcpEndpointHttp')) + '</label><input class="mcp-input" id="mcp-url" value="' + escAttr(draft.url) + '" inputmode="url" autocomplete="url"></div>' +
|
|
20491
|
+
'<div class="mcp-field"><label for="mcp-headers">' + esc(t('plugins.mcpHeaders')) + '</label><textarea class="mcp-input" id="mcp-headers" spellcheck="false" placeholder="{}">' + esc(draft.headersText) + '</textarea><div class="mcp-field-help">' + esc(mcpSecretHelp(draft.headerKeys, 'plugins.mcpSavedHeaderKeys')) + ' ' + esc(t('plugins.mcpSecretsHelp')) + '</div></div></div>' +
|
|
20492
|
+
'<label class="mcp-enabled-check" for="mcp-enabled"><input id="mcp-enabled" type="checkbox"' + (draft.enabled ? ' checked' : '') + (pending ? ' disabled' : '') + '> ' + esc(t('plugins.mcpEnabled')) + '</label>' +
|
|
20493
|
+
'<div class="mcp-form-actions"><button type="button" class="sec-btn" id="mcp-cancel" onclick="window.cancelMcpForm()"' + (pending ? ' disabled' : '') + '>' + esc(t('common.cancel')) + '</button>' +
|
|
20494
|
+
'<button type="button" class="sec-btn primary" id="mcp-save" onclick="window.saveMcpServer()"' + (pending ? ' disabled' : '') + '>' + esc(pending ? t('plugins.mcpSaving') : t('plugins.mcpSave')) + '</button></div></section>';
|
|
20495
|
+
}
|
|
20496
|
+
|
|
18921
20497
|
window.renderMcpManagerContent = function() {
|
|
18922
20498
|
var panel = document.getElementById('plugin-panel');
|
|
18923
|
-
if (!panel) return;
|
|
18924
|
-
var
|
|
18925
|
-
var
|
|
18926
|
-
var
|
|
18927
|
-
var
|
|
18928
|
-
var
|
|
18929
|
-
|
|
18930
|
-
|
|
18931
|
-
'<input id="mcp-
|
|
18932
|
-
'<
|
|
18933
|
-
'<
|
|
18934
|
-
|
|
18935
|
-
|
|
18936
|
-
|
|
18937
|
-
|
|
18938
|
-
if (!servers.length) html += '<div class="settings-empty">' + esc(t('plugins.mcpNoServers')) + '</div>';
|
|
20499
|
+
if (!panel || state.pluginActiveTab !== 'mcp') return;
|
|
20500
|
+
var allServers = state.mcpServers || [];
|
|
20501
|
+
var allDiscovered = state.mcpDiscovered || [];
|
|
20502
|
+
var query = String(state.mcpSearchQuery || '').trim().toLowerCase();
|
|
20503
|
+
var servers = allServers.filter(function(server) { return mcpSearchMatch(server, query); });
|
|
20504
|
+
var discovered = allDiscovered.filter(function(server) { return mcpSearchMatch(server, query); });
|
|
20505
|
+
var pending = !!state.mcpMutationPending;
|
|
20506
|
+
var html = '<div class="plugin-toolbar"><div class="plugin-toolbar-copy"><div class="plugin-toolbar-title">' + esc(t('plugins.mcp')) + '</div><div class="plugin-toolbar-meta">' + esc(t('plugins.mcpHelp')) + '</div></div>' +
|
|
20507
|
+
'<input class="plugin-search" id="mcp-search" type="search" value="' + escAttr(state.mcpSearchQuery || '') + '" placeholder="' + escAttr(t('plugins.mcpSearch')) + '" aria-label="' + escAttr(t('plugins.mcpSearch')) + '" oninput="window.updateMcpSearch(this.value)">' +
|
|
20508
|
+
'<button type="button" class="sec-btn" id="mcp-refresh" onclick="window.renderMcpManager()"' + (pending ? ' disabled' : '') + '>' + esc(t('plugins.mcpRefresh')) + '</button>' +
|
|
20509
|
+
'<button type="button" class="sec-btn primary" id="mcp-add" onclick="window.openMcpAddForm()"' + (pending ? ' disabled' : '') + '>' + esc(t('plugins.mcpAdd')) + '</button></div>';
|
|
20510
|
+
html += renderMcpForm();
|
|
20511
|
+
html += '<section class="plugin-section" id="mcp-stored-section"><div class="plugin-section-head"><div class="plugin-section-title">' + esc(t('plugins.mcpStored')) + '</div><span class="plugin-count-badge">' + esc(pluginText('plugins.mcpConfiguredCount', { count: allServers.length })) + '</span></div>';
|
|
20512
|
+
if (!allServers.length) html += '<div class="plugin-empty">' + esc(t('plugins.mcpStoredEmpty')) + '</div>';
|
|
20513
|
+
else if (!servers.length) html += '<div class="plugin-empty">' + esc(t('plugins.mcpNoMatch')) + '</div>';
|
|
18939
20514
|
servers.forEach(function(server) {
|
|
18940
|
-
var
|
|
18941
|
-
|
|
18942
|
-
|
|
18943
|
-
'<
|
|
18944
|
-
'<
|
|
20515
|
+
var index = allServers.indexOf(server);
|
|
20516
|
+
var endpoint = server.transport === 'http' ? server.url : [server.command].concat(server.args || []).filter(Boolean).join(' ');
|
|
20517
|
+
html += '<div class="mcp-server-row" data-mcp-index="' + index + '"><div class="mcp-server-copy"><div class="mcp-server-title">' + esc(server.name || '') +
|
|
20518
|
+
'<span class="plugin-status-badge">' + esc(server.transport || 'stdio') + '</span><span class="plugin-status-badge' + (server.enabled ? ' enabled' : '') + '">' + esc(server.enabled ? t('plugins.mcpEnabledStatus') : t('plugins.mcpDisabledStatus')) + '</span></div>' +
|
|
20519
|
+
'<div class="mcp-server-meta">' + esc(endpoint || '') + '</div></div><div class="mcp-row-actions">' +
|
|
20520
|
+
'<button type="button" class="sec-btn" onclick="window.editMcpServerAt(' + index + ')"' + (pending ? ' disabled' : '') + '>' + esc(t('common.edit')) + '</button>' +
|
|
20521
|
+
'<button type="button" class="sec-btn" onclick="window.toggleMcpServerAt(' + index + ',' + (!server.enabled) + ')"' + (pending ? ' disabled' : '') + '>' + esc(server.enabled ? t('common.disable') : t('common.enable')) + '</button>' +
|
|
20522
|
+
'<button type="button" class="sec-btn" onclick="window.removeMcpServerAt(' + index + ')"' + (pending ? ' disabled' : '') + '>' + esc(t('common.remove')) + '</button></div></div>';
|
|
18945
20523
|
});
|
|
18946
|
-
html += '
|
|
18947
|
-
if (!
|
|
20524
|
+
html += '</section><section class="plugin-section" id="mcp-discovered-section"><div class="plugin-section-head"><div class="plugin-section-title">' + esc(t('plugins.mcpDiscovered')) + '</div><span class="plugin-count-badge">' + allDiscovered.length + '</span></div>';
|
|
20525
|
+
if (!allDiscovered.length) html += '<div class="plugin-empty">' + esc(t('plugins.mcpDiscoveredEmpty')) + '</div>';
|
|
20526
|
+
else if (!discovered.length) html += '<div class="plugin-empty">' + esc(t('plugins.mcpNoMatch')) + '</div>';
|
|
18948
20527
|
discovered.forEach(function(server) {
|
|
18949
|
-
html += '<div class="
|
|
20528
|
+
html += '<div class="mcp-server-row"><div class="mcp-server-copy"><div class="mcp-server-title">' + esc(server.name || '') +
|
|
20529
|
+
'<span class="plugin-status-badge">' + esc(server.ecosystem || t('plugins.mcpReadonly')) + '</span>' +
|
|
20530
|
+
'<span class="plugin-status-badge' + (server.enabled ? ' enabled' : '') + '">' + esc(server.enabled ? t('plugins.mcpEnabledStatus') : t('plugins.mcpDisabledStatus')) + '</span></div><div class="mcp-server-meta">' +
|
|
20531
|
+
esc([server.plugin, server.root].filter(Boolean).join(' · ')) + '</div></div><span class="plugin-status-badge">' + esc(t('plugins.mcpReadonly')) + '</span></div>';
|
|
18950
20532
|
});
|
|
20533
|
+
html += '</section>';
|
|
18951
20534
|
panel.innerHTML = html;
|
|
20535
|
+
window.updateMcpTransportForm(false);
|
|
20536
|
+
if (state.mcpFormFocusRequested) {
|
|
20537
|
+
state.mcpFormFocusRequested = false;
|
|
20538
|
+
requestAnimationFrame(function() {
|
|
20539
|
+
var form = document.getElementById('mcp-form');
|
|
20540
|
+
var input = document.getElementById('mcp-name');
|
|
20541
|
+
if (form) form.scrollIntoView({ block: 'nearest' });
|
|
20542
|
+
if (input) input.focus({ preventScroll: true });
|
|
20543
|
+
});
|
|
20544
|
+
}
|
|
20545
|
+
};
|
|
20546
|
+
|
|
20547
|
+
window.captureMcpDraftFromForm = function() {
|
|
20548
|
+
if (!state.mcpDraft || !document.getElementById('mcp-form')) return state.mcpDraft;
|
|
20549
|
+
var value = function(id) { var element = document.getElementById(id); return element ? element.value : ''; };
|
|
20550
|
+
state.mcpDraft.name = value('mcp-name');
|
|
20551
|
+
state.mcpDraft.transport = value('mcp-transport') === 'http' ? 'http' : 'stdio';
|
|
20552
|
+
state.mcpDraft.command = value('mcp-command');
|
|
20553
|
+
state.mcpDraft.url = value('mcp-url');
|
|
20554
|
+
state.mcpDraft.argsText = value('mcp-args');
|
|
20555
|
+
state.mcpDraft.cwd = value('mcp-cwd');
|
|
20556
|
+
state.mcpDraft.envText = value('mcp-env');
|
|
20557
|
+
state.mcpDraft.headersText = value('mcp-headers');
|
|
20558
|
+
var enabled = document.getElementById('mcp-enabled');
|
|
20559
|
+
state.mcpDraft.enabled = !!(enabled && enabled.checked);
|
|
20560
|
+
return state.mcpDraft;
|
|
20561
|
+
};
|
|
20562
|
+
|
|
20563
|
+
window.updateMcpTransportForm = function(capture) {
|
|
20564
|
+
if (capture !== false) window.captureMcpDraftFromForm();
|
|
20565
|
+
var transport = document.getElementById('mcp-transport');
|
|
20566
|
+
var stdio = document.getElementById('mcp-stdio-fields');
|
|
20567
|
+
var http = document.getElementById('mcp-http-fields');
|
|
20568
|
+
var isHttp = !!(transport && transport.value === 'http');
|
|
20569
|
+
if (state.mcpDraft) state.mcpDraft.transport = isHttp ? 'http' : 'stdio';
|
|
20570
|
+
if (stdio) stdio.hidden = isHttp;
|
|
20571
|
+
if (http) http.hidden = !isHttp;
|
|
20572
|
+
};
|
|
20573
|
+
|
|
20574
|
+
window.openMcpAddForm = function() {
|
|
20575
|
+
if (state.mcpMutationPending) return;
|
|
20576
|
+
state.mcpEditingId = '';
|
|
20577
|
+
state.mcpDraft = newMcpDraft({ enabled: false, transport: 'stdio', args: [] }, 'add');
|
|
20578
|
+
state.mcpFormFocusRequested = true;
|
|
20579
|
+
window.renderMcpManagerContent();
|
|
20580
|
+
};
|
|
20581
|
+
|
|
20582
|
+
window.editMcpServerAt = function(index) {
|
|
20583
|
+
if (state.mcpMutationPending) return;
|
|
20584
|
+
var server = (state.mcpServers || [])[index];
|
|
20585
|
+
if (!server) return;
|
|
20586
|
+
state.mcpEditingId = server.id || '';
|
|
20587
|
+
state.mcpDraft = newMcpDraft(server, 'edit');
|
|
20588
|
+
state.mcpFormFocusRequested = true;
|
|
20589
|
+
window.renderMcpManagerContent();
|
|
20590
|
+
};
|
|
20591
|
+
|
|
20592
|
+
window.cancelMcpForm = function() {
|
|
20593
|
+
if (state.mcpMutationPending) return;
|
|
20594
|
+
state.mcpEditingId = '';
|
|
20595
|
+
state.mcpDraft = null;
|
|
20596
|
+
window.renderMcpManagerContent();
|
|
20597
|
+
var addButton = document.getElementById('mcp-add');
|
|
20598
|
+
if (addButton) addButton.focus({ preventScroll: true });
|
|
18952
20599
|
};
|
|
18953
20600
|
|
|
18954
|
-
window.
|
|
18955
|
-
|
|
18956
|
-
|
|
18957
|
-
|
|
18958
|
-
|
|
18959
|
-
if (
|
|
20601
|
+
window.updateMcpSearch = function(value) {
|
|
20602
|
+
window.captureMcpDraftFromForm();
|
|
20603
|
+
state.mcpSearchQuery = String(value || '');
|
|
20604
|
+
window.renderMcpManagerContent();
|
|
20605
|
+
var search = document.getElementById('mcp-search');
|
|
20606
|
+
if (search) {
|
|
20607
|
+
search.focus({ preventScroll: true });
|
|
20608
|
+
search.setSelectionRange(search.value.length, search.value.length);
|
|
20609
|
+
}
|
|
18960
20610
|
};
|
|
18961
|
-
|
|
18962
|
-
|
|
20611
|
+
|
|
20612
|
+
function parseMcpObject(text, fieldLabel) {
|
|
20613
|
+
if (!String(text || '').trim()) return undefined;
|
|
20614
|
+
var parsed = JSON.parse(text);
|
|
20615
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error(pluginText('plugins.mcpInvalidObject', { field: fieldLabel }));
|
|
20616
|
+
return parsed;
|
|
20617
|
+
}
|
|
20618
|
+
|
|
20619
|
+
function mcpMutationUiActive(generation) {
|
|
20620
|
+
return generation === state.mcpMutationGeneration
|
|
20621
|
+
&& state.pluginActiveTab === 'mcp'
|
|
20622
|
+
&& !!(state.activeSubWindowView && state.activeSubWindowView.name === 'plugins')
|
|
20623
|
+
&& !!document.getElementById('plugin-panel');
|
|
20624
|
+
}
|
|
20625
|
+
|
|
18963
20626
|
window.saveMcpServer = function() {
|
|
18964
|
-
if (!api.upsertMcpServer) return;
|
|
18965
|
-
var
|
|
18966
|
-
|
|
18967
|
-
var
|
|
18968
|
-
var
|
|
18969
|
-
|
|
18970
|
-
var input = { id: state.mcpEditingId || undefined, name: name, transport: transport };
|
|
20627
|
+
if (!api.upsertMcpServer || state.mcpMutationPending) return;
|
|
20628
|
+
var draft = window.captureMcpDraftFromForm();
|
|
20629
|
+
if (!draft) return;
|
|
20630
|
+
var name = String(draft.name || '').trim();
|
|
20631
|
+
var transport = draft.transport === 'http' ? 'http' : 'stdio';
|
|
20632
|
+
if (!name) { showUiNotice(t('plugins.mcpRequiredName'), 'error', 'mcp-save'); return; }
|
|
20633
|
+
var input = { id: draft.id || state.mcpEditingId || undefined, name: name, transport: transport, enabled: !!draft.enabled };
|
|
18971
20634
|
try {
|
|
18972
|
-
if (transport === 'http') {
|
|
18973
|
-
|
|
20635
|
+
if (transport === 'http') {
|
|
20636
|
+
var url = String(draft.url || '').trim();
|
|
20637
|
+
if (!/^https?:\/\//i.test(url)) throw new Error(t('plugins.mcpRequiredUrl'));
|
|
20638
|
+
input.url = url;
|
|
20639
|
+
var headers = parseMcpObject(draft.headersText, t('plugins.mcpHeaders'));
|
|
20640
|
+
if (headers !== undefined) input.headers = headers;
|
|
20641
|
+
} else {
|
|
20642
|
+
var command = String(draft.command || '').trim();
|
|
20643
|
+
if (!command) throw new Error(t('plugins.mcpRequiredCommand'));
|
|
20644
|
+
var args = String(draft.argsText || '').trim() ? JSON.parse(draft.argsText) : [];
|
|
20645
|
+
if (!Array.isArray(args)) throw new Error(t('plugins.mcpInvalidArgs'));
|
|
20646
|
+
input.command = command;
|
|
20647
|
+
input.args = args;
|
|
20648
|
+
input.cwd = String(draft.cwd || '').trim() || undefined;
|
|
20649
|
+
var env = parseMcpObject(draft.envText, t('plugins.mcpEnv'));
|
|
20650
|
+
if (env !== undefined) input.env = env;
|
|
20651
|
+
}
|
|
18974
20652
|
} catch (error) {
|
|
18975
|
-
showUiNotice(error.message
|
|
20653
|
+
showUiNotice(error && error.message ? error.message : String(error), 'error', 'mcp-save');
|
|
18976
20654
|
return;
|
|
18977
20655
|
}
|
|
18978
|
-
|
|
18979
|
-
|
|
20656
|
+
var generation = ++state.mcpMutationGeneration;
|
|
20657
|
+
state.mcpMutationPending = true;
|
|
20658
|
+
window.renderMcpManagerContent();
|
|
20659
|
+
Promise.resolve(api.upsertMcpServer(input)).then(function(result) {
|
|
20660
|
+
if (!result || result.ok !== true) throw new Error(result && result.error || t('plugins.mcpMutationFailed'));
|
|
20661
|
+
if (Array.isArray(result.servers)) state.mcpServers = result.servers;
|
|
18980
20662
|
state.mcpEditingId = '';
|
|
18981
|
-
|
|
18982
|
-
|
|
20663
|
+
state.mcpDraft = null;
|
|
20664
|
+
if (mcpMutationUiActive(generation)) showUiNotice(t('plugins.mcpSaved'), 'success', 'mcp-save');
|
|
20665
|
+
}).catch(function(error) {
|
|
20666
|
+
if (mcpMutationUiActive(generation)) showUiNotice(error && error.message ? error.message : String(error), 'error', 'mcp-save');
|
|
20667
|
+
}).finally(function() {
|
|
20668
|
+
state.mcpMutationPending = false;
|
|
20669
|
+
if (mcpMutationUiActive(generation)) window.renderMcpManager();
|
|
20670
|
+
});
|
|
20671
|
+
};
|
|
20672
|
+
|
|
20673
|
+
window.toggleMcpServerAt = function(index, enabled) {
|
|
20674
|
+
if (!api.setMcpServerEnabled || state.mcpMutationPending) return;
|
|
20675
|
+
var server = (state.mcpServers || [])[index];
|
|
20676
|
+
if (!server) return;
|
|
20677
|
+
var generation = ++state.mcpMutationGeneration;
|
|
20678
|
+
state.mcpMutationPending = true;
|
|
20679
|
+
window.renderMcpManagerContent();
|
|
20680
|
+
Promise.resolve(api.setMcpServerEnabled(server.id, !!enabled)).then(function(result) {
|
|
20681
|
+
if (!result || result.ok !== true) throw new Error(result && result.error || t('plugins.mcpMutationFailed'));
|
|
20682
|
+
if (Array.isArray(result.servers)) state.mcpServers = result.servers;
|
|
20683
|
+
}).catch(function(error) {
|
|
20684
|
+
if (mcpMutationUiActive(generation)) showUiNotice(error && error.message ? error.message : String(error), 'error', 'mcp-toggle');
|
|
20685
|
+
}).finally(function() {
|
|
20686
|
+
state.mcpMutationPending = false;
|
|
20687
|
+
if (mcpMutationUiActive(generation)) window.renderMcpManager();
|
|
20688
|
+
});
|
|
20689
|
+
};
|
|
20690
|
+
|
|
20691
|
+
window.removeMcpServerAt = function(index) {
|
|
20692
|
+
if (!api.removeMcpServer || state.mcpMutationPending) return;
|
|
20693
|
+
var server = (state.mcpServers || [])[index];
|
|
20694
|
+
if (!server || !confirm(pluginText('plugins.mcpRemoveConfirm', { name: server.name || '' }))) return;
|
|
20695
|
+
var generation = ++state.mcpMutationGeneration;
|
|
20696
|
+
state.mcpMutationPending = true;
|
|
20697
|
+
window.renderMcpManagerContent();
|
|
20698
|
+
Promise.resolve(api.removeMcpServer(server.id)).then(function(result) {
|
|
20699
|
+
if (!result || result.ok !== true) throw new Error(result && result.error || t('plugins.mcpMutationFailed'));
|
|
20700
|
+
if (Array.isArray(result.servers)) state.mcpServers = result.servers;
|
|
20701
|
+
if (state.mcpEditingId === server.id) { state.mcpEditingId = ''; state.mcpDraft = null; }
|
|
20702
|
+
}).catch(function(error) {
|
|
20703
|
+
if (mcpMutationUiActive(generation)) showUiNotice(error && error.message ? error.message : String(error), 'error', 'mcp-remove');
|
|
20704
|
+
}).finally(function() {
|
|
20705
|
+
state.mcpMutationPending = false;
|
|
20706
|
+
if (mcpMutationUiActive(generation)) window.renderMcpManager();
|
|
20707
|
+
});
|
|
18983
20708
|
};
|
|
18984
|
-
window.toggleMcpServer = function(id, enabled) { if (api.setMcpServerEnabled) api.setMcpServerEnabled(id, enabled).then(window.renderMcpManager); };
|
|
18985
|
-
window.removeMcpServerFromUi = function(id) { if (api.removeMcpServer) api.removeMcpServer(id).then(window.renderMcpManager); };
|
|
18986
20709
|
|
|
18987
20710
|
window.filteredSkillMarket = function() {
|
|
18988
20711
|
var market = state._skillMarketAll || [];
|
|
@@ -19003,7 +20726,7 @@ window.filteredSkillMarket = function() {
|
|
|
19003
20726
|
|
|
19004
20727
|
window.renderSkillsMarketList = function() {
|
|
19005
20728
|
var panel = document.getElementById('plugin-panel');
|
|
19006
|
-
if (!panel) return;
|
|
20729
|
+
if (!panel || state.pluginActiveTab !== 'market' || !state.activeSubWindowView || state.activeSubWindowView.name !== 'plugins') return;
|
|
19007
20730
|
var market = window.filteredSkillMarket();
|
|
19008
20731
|
var total = (state._skillMarketAll || []).length;
|
|
19009
20732
|
var query = state.skillMarketQuery || '';
|
|
@@ -19272,13 +20995,14 @@ window.renderLeftWsList = function() {
|
|
|
19272
20995
|
var container = document.getElementById('left-ws-list');
|
|
19273
20996
|
if (!container) return;
|
|
19274
20997
|
var workspaces = state.workspaces || [];
|
|
20998
|
+
var hasActiveWorkspace = workspaces.some(function(item) { return workspaceIdentity(item) === String(state.currentWorkspaceId || ''); });
|
|
19275
20999
|
var html = '';
|
|
19276
21000
|
for (var i = 0; i < workspaces.length; i++) {
|
|
19277
21001
|
var ws = workspaces[i];
|
|
19278
21002
|
var identity = workspaceIdentity(ws);
|
|
19279
21003
|
var active = identity === String(state.currentWorkspaceId || '');
|
|
19280
21004
|
var runtimeStatus = workspaceRuntimeStatus(ws);
|
|
19281
|
-
html += '<div class="left-ws-item' + (active ? ' active' : '') + '" onclick="window.switchToWorkspace(\'' + escAttr(identity) + '\')">' +
|
|
21005
|
+
html += '<div class="left-ws-item' + (active ? ' active' : '') + '" role="listitem" tabindex="' + (active || (!hasActiveWorkspace && i === 0) ? '0' : '-1') + '" aria-current="' + (active ? 'true' : 'false') + '" onclick="window.switchToWorkspace(\'' + escAttr(identity) + '\')" onkeydown="window.handleWorkspaceKey(event)">' +
|
|
19282
21006
|
'<span class="ws-icon">' + esc((ws.name || '?')[0].toUpperCase()) + '</span>' +
|
|
19283
21007
|
'<span class="ws-label">' + esc(ws.name || t('workspace.untitled')) + '</span>' +
|
|
19284
21008
|
(runtimeStatus ? '<span class="ws-runtime-dot ' + escAttr(runtimeStatus) + '" title="' + escAttr(runtimeStatus) + '"></span>' : '') +
|
|
@@ -19291,6 +21015,24 @@ window.renderLeftWsList = function() {
|
|
|
19291
21015
|
appendDomNodesInBatches(container, Array.from(holder.children), 'workspace-list', 24);
|
|
19292
21016
|
};
|
|
19293
21017
|
|
|
21018
|
+
window.handleWorkspaceKey = function(event) {
|
|
21019
|
+
if (!event || event.defaultPrevented || event.isComposing || event.key === 'Process' || event.keyCode === 229 || event.target !== event.currentTarget) return false;
|
|
21020
|
+
if (event.key === 'Enter' || event.key === ' ') return window.activateButtonLike(event);
|
|
21021
|
+
var items = Array.prototype.slice.call(document.querySelectorAll('#left-ws-list .left-ws-item'));
|
|
21022
|
+
var index = items.indexOf(event.currentTarget);
|
|
21023
|
+
if (index < 0 || !items.length) return false;
|
|
21024
|
+
var next = index;
|
|
21025
|
+
if (event.key === 'ArrowDown' || event.key === 'ArrowRight') next = (index + 1) % items.length;
|
|
21026
|
+
else if (event.key === 'ArrowUp' || event.key === 'ArrowLeft') next = (index - 1 + items.length) % items.length;
|
|
21027
|
+
else if (event.key === 'Home') next = 0;
|
|
21028
|
+
else if (event.key === 'End') next = items.length - 1;
|
|
21029
|
+
else return false;
|
|
21030
|
+
event.preventDefault();
|
|
21031
|
+
items[next].focus({ preventScroll:true });
|
|
21032
|
+
items[next].click();
|
|
21033
|
+
return true;
|
|
21034
|
+
};
|
|
21035
|
+
|
|
19294
21036
|
window.toggleWorkspacePinned = function(identity) {
|
|
19295
21037
|
if (!identity || !api.setWorkspacePinned) return;
|
|
19296
21038
|
var nextPinned = false;
|
|
@@ -19395,7 +21137,7 @@ window.showNewWorkspaceDialog = function() {
|
|
|
19395
21137
|
'<label style="display:flex;align-items:center;gap:4px;font-size:12px;cursor:pointer;"><input type="radio" name="ws-type" value="ssh" onchange="window.toggleWsType()"> ' + esc(t('workspace.ssh')) + '</label>' +
|
|
19396
21138
|
'</div>' +
|
|
19397
21139
|
'<label id="ws-name-label-dlg" style="display:block;font-size:12px;color:var(--text-dim);margin-bottom:8px;">' + esc(t('workspace.name')) + '</label>' +
|
|
19398
|
-
'<input id="new-ws-input" style="width:100%;padding:8px 10px;border:1px solid var(--glass-border-2);border-radius:var(--radius-sm);background:var(--glass-bg-1);color:var(--text);font-size:13px;outline:none;box-sizing:border-box;" placeholder="' + escAttr(t('workspace.enterName')) + '" onkeydown="if(event.key===\'Enter\')window.doCreateWorkspace()">' +
|
|
21140
|
+
'<input id="new-ws-input" style="width:100%;padding:8px 10px;border:1px solid var(--glass-border-2);border-radius:var(--radius-sm);background:var(--glass-bg-1);color:var(--text);font-size:13px;outline:none;box-sizing:border-box;" placeholder="' + escAttr(t('workspace.enterName')) + '" onkeydown="if(event.key===\'Enter\'&&!event.isComposing&&event.key!==\'Process\'&&event.keyCode!==229)window.doCreateWorkspace()">' +
|
|
19399
21141
|
'<div id="ws-ext-path" style="display:none;margin-top:8px;">' +
|
|
19400
21142
|
'<label style="display:block;font-size:12px;color:var(--text-dim);margin-bottom:6px;">' + esc(t('workspace.folderPath')) + '</label>' +
|
|
19401
21143
|
'<div style="display:flex;gap:6px;">' +
|
|
@@ -19651,7 +21393,7 @@ window.openWorkspaceManager = async function() {
|
|
|
19651
21393
|
var ws = workspaces[i];
|
|
19652
21394
|
var identity = workspaceIdentity(ws);
|
|
19653
21395
|
var isActive = identity === String(state.currentWorkspaceId || '');
|
|
19654
|
-
listHtml += '<div style="display:flex;align-items:center;gap:8px;padding:8px 10px;margin:2px 0;border-radius:var(--radius-sm);background:' + (isActive ? 'var(--accent-glow)' : 'var(--glass-bg-1)') + ';cursor:pointer;" onclick="window.switchToWorkspace(\'' + escAttr(identity) + '\')">' +
|
|
21396
|
+
listHtml += '<div role="button" tabindex="0" style="display:flex;align-items:center;gap:8px;padding:8px 10px;margin:2px 0;border-radius:var(--radius-sm);background:' + (isActive ? 'var(--accent-glow)' : 'var(--glass-bg-1)') + ';cursor:pointer;" onclick="window.switchToWorkspace(\'' + escAttr(identity) + '\')" onkeydown="window.activateButtonLike(event)">' +
|
|
19655
21397
|
'<span style="width:24px;height:24px;border-radius:var(--radius-sm);background:linear-gradient(135deg,var(--accent),#7b93ff);color:#fff;font-size:11px;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0;">' + esc((ws.name || '?')[0].toUpperCase()) + '</span>' +
|
|
19656
21398
|
'<span style="flex:1;font-size:12px;color:var(--text);">' + esc(ws.name || t('workspace.untitled')) + '</span>' +
|
|
19657
21399
|
(isActive ? '<span style="font-size:10px;color:var(--accent2);">' + esc(t('workspace.current')) + '</span>' : '') +
|
|
@@ -19888,6 +21630,549 @@ function stopMarqueeJS() {
|
|
|
19888
21630
|
if (marqueeRAF) { cancelAnimationFrame(marqueeRAF); marqueeRAF = null; }
|
|
19889
21631
|
}
|
|
19890
21632
|
|
|
21633
|
+
// === Unified GUI Command Registry & Keyboard Routing ===
|
|
21634
|
+
function guiCommand(id, titleKey, category, options) {
|
|
21635
|
+
return Object.assign({ id: id, titleKey: titleKey, category: category, bindings: [], scope: 'palette', keywords: [] }, options || {});
|
|
21636
|
+
}
|
|
21637
|
+
|
|
21638
|
+
function guiIsMac() {
|
|
21639
|
+
return String(state.platform || navigator.platform || '').toLowerCase().indexOf('mac') >= 0;
|
|
21640
|
+
}
|
|
21641
|
+
|
|
21642
|
+
function guiBindingRecord(command, input) {
|
|
21643
|
+
return typeof input === 'string'
|
|
21644
|
+
? { keys: input, scope: command.scope || 'palette' }
|
|
21645
|
+
: { keys: String((input && input.keys) || ''), scope: String((input && input.scope) || command.scope || 'palette') };
|
|
21646
|
+
}
|
|
21647
|
+
|
|
21648
|
+
function guiDisplayBinding(binding) {
|
|
21649
|
+
var keys = typeof binding === 'string' ? binding : String((binding && binding.keys) || '');
|
|
21650
|
+
return keys.replace(/\bMod\b/g, guiIsMac() ? 'Cmd' : 'Ctrl').replace(/ /g, ' then ');
|
|
21651
|
+
}
|
|
21652
|
+
|
|
21653
|
+
function guiSetSelectValue(id, value) {
|
|
21654
|
+
var select = document.getElementById(id);
|
|
21655
|
+
if (!select) return false;
|
|
21656
|
+
select.value = value;
|
|
21657
|
+
select.dispatchEvent(new Event('change', { bubbles: true }));
|
|
21658
|
+
return true;
|
|
21659
|
+
}
|
|
21660
|
+
|
|
21661
|
+
function guiSubWindowOpen() {
|
|
21662
|
+
return !!(els['sub-win-overlay'] && els['sub-win-overlay'].classList.contains('open'));
|
|
21663
|
+
}
|
|
21664
|
+
|
|
21665
|
+
function guiFocusPrompt() {
|
|
21666
|
+
if (guiSubWindowOpen()) return false;
|
|
21667
|
+
if (els.prompt) {
|
|
21668
|
+
els.prompt.focus({ preventScroll: true });
|
|
21669
|
+
return true;
|
|
21670
|
+
}
|
|
21671
|
+
return false;
|
|
21672
|
+
}
|
|
21673
|
+
|
|
21674
|
+
function guiFocusTerminal() {
|
|
21675
|
+
if (guiSubWindowOpen()) return false;
|
|
21676
|
+
if (state.bottomCollapsed) window.toggleBottom();
|
|
21677
|
+
var input = document.querySelector('#terminal-body .terminal-pane.active .terminal-input') || document.querySelector('#terminal-body .terminal-input');
|
|
21678
|
+
if (input) {
|
|
21679
|
+
input.focus({ preventScroll: true });
|
|
21680
|
+
return true;
|
|
21681
|
+
}
|
|
21682
|
+
return false;
|
|
21683
|
+
}
|
|
21684
|
+
|
|
21685
|
+
function guiFocusBrowserAddress() {
|
|
21686
|
+
if (guiSubWindowOpen()) return false;
|
|
21687
|
+
window.switchRightTab('browser');
|
|
21688
|
+
requestAnimationFrame(function() {
|
|
21689
|
+
var input = document.getElementById('browser-url');
|
|
21690
|
+
if (input) { input.focus({ preventScroll: true }); input.select(); }
|
|
21691
|
+
});
|
|
21692
|
+
return true;
|
|
21693
|
+
}
|
|
21694
|
+
|
|
21695
|
+
function guiCycleConversation(direction) {
|
|
21696
|
+
var conversations = currentWorkspaceConversations ? currentWorkspaceConversations() : [];
|
|
21697
|
+
if (!conversations.length) return false;
|
|
21698
|
+
var current = Math.max(0, Math.min(conversations.length - 1, Number(state.activeConversation) || 0));
|
|
21699
|
+
var next = (current + direction + conversations.length) % conversations.length;
|
|
21700
|
+
window.switchConversation(next);
|
|
21701
|
+
return true;
|
|
21702
|
+
}
|
|
21703
|
+
|
|
21704
|
+
function guiHasSwitchableBranch() {
|
|
21705
|
+
var groups = state.conversationBranchGroups || [];
|
|
21706
|
+
var branches = state.conversationBranches || [];
|
|
21707
|
+
if (groups.length) return groups.some(function(group) { return (group.branches || []).length > 1; });
|
|
21708
|
+
return branches.length > 1;
|
|
21709
|
+
}
|
|
21710
|
+
|
|
21711
|
+
function guiToggleTheme() {
|
|
21712
|
+
var current = state.theme === 'light' ? 'light' : 'dark';
|
|
21713
|
+
window.setTheme(current === 'light' ? 'dark' : 'light');
|
|
21714
|
+
}
|
|
21715
|
+
|
|
21716
|
+
var NEWMARK_GUI_COMMANDS = [
|
|
21717
|
+
guiCommand('app.commandPalette', 'shortcuts.openPalette', 'general', { bindings: [{ keys:'Mod+Shift+P', scope:'global' }], run:function(){ window.openCommandSurface('palette'); } }),
|
|
21718
|
+
guiCommand('help.keyboardShortcuts', 'shortcuts.openHelp', 'general', { bindings: [{ keys:'F1', scope:'global' }], run:function(){ window.openCommandSurface('help'); } }),
|
|
21719
|
+
guiCommand('settings.open', 'settings.title', 'general', { bindings: [{ keys:'Mod+,', scope:'global' }, { keys:'Mod+K S', scope:'whenNotEditing' }], run:function(){ window.openSettings(); } }),
|
|
21720
|
+
guiCommand('window.minimize', 'top.minimize', 'general', { run:function(){ api.minimize(); } }),
|
|
21721
|
+
guiCommand('window.maximize', 'top.maximize', 'general', { run:function(){ api.maximize(); } }),
|
|
21722
|
+
guiCommand('view.toggleTheme', 'shortcuts.toggleTheme', 'general', { bindings:[{ keys:'Mod+K Q', scope:'whenNotEditing' }], run:guiToggleTheme }),
|
|
21723
|
+
|
|
21724
|
+
guiCommand('conversation.new', 'left.newChat', 'workspace', { bindings:[{ keys:'Mod+K N', scope:'whenNotEditing' }], run:function(){ if (state.currentWorkspaceId) window.newConversation(); else window.showNewConversationPage(); } }),
|
|
21725
|
+
guiCommand('conversation.next', 'shortcuts.nextConversation', 'workspace', { bindings:[{ keys:'Mod+Shift+ArrowRight', scope:'whenNotEditing' }], run:function(){ guiCycleConversation(1); }, available:function(){ return currentWorkspaceConversations().length > 1; } }),
|
|
21726
|
+
guiCommand('conversation.previous', 'shortcuts.previousConversation', 'workspace', { bindings:[{ keys:'Mod+Shift+ArrowLeft', scope:'whenNotEditing' }], run:function(){ guiCycleConversation(-1); }, available:function(){ return currentWorkspaceConversations().length > 1; } }),
|
|
21727
|
+
guiCommand('conversation.archive', 'archive.current', 'workspace', { run:function(){ window.archiveCurrent(); }, available:function(){ return !!state.currentWorkspaceId; } }),
|
|
21728
|
+
guiCommand('branch.previous', 'shortcuts.previousBranch', 'workspace', { bindings:[{ keys:'Alt+ArrowUp', scope:'whenNotEditing' }], run:function(){ window.switchConversationBranch(-1); }, available:function(){ return guiHasSwitchableBranch(); } }),
|
|
21729
|
+
guiCommand('branch.next', 'shortcuts.nextBranch', 'workspace', { bindings:[{ keys:'Alt+ArrowDown', scope:'whenNotEditing' }], run:function(){ window.switchConversationBranch(1); }, available:function(){ return guiHasSwitchableBranch(); } }),
|
|
21730
|
+
guiCommand('workspace.manager', 'workspace.manager', 'workspace', { bindings:[{ keys:'Mod+K W', scope:'whenNotEditing' }], run:function(){ window.openWorkspaceManager(); } }),
|
|
21731
|
+
guiCommand('workspace.new', 'workspace.new', 'workspace', { run:function(){ window.showNewWorkspaceDialog(); } }),
|
|
21732
|
+
guiCommand('workspace.settings', 'workspace.settingsTitle', 'workspace', { run:function(){ window.openWsSettings(); }, available:function(){ return !!state.currentWorkspaceId; } }),
|
|
21733
|
+
|
|
21734
|
+
guiCommand('view.plugins', 'plugins.title', 'navigation', { bindings:[{ keys:'Mod+K P', scope:'whenNotEditing' }], run:function(){ window.showPluginList(); } }),
|
|
21735
|
+
guiCommand('view.plugins.mcp', 'plugins.mcp', 'navigation', { run:function(){ window.showPluginList('mcp'); } }),
|
|
21736
|
+
guiCommand('view.plugins.dsh', 'plugins.dsh', 'navigation', { bindings:[{ keys:'Mod+K D', scope:'whenNotEditing' }], run:function(){ window.showPluginList('dsh'); } }),
|
|
21737
|
+
guiCommand('view.plugins.skills', 'plugins.management', 'navigation', { run:function(){ window.showPluginList('installed'); } }),
|
|
21738
|
+
guiCommand('view.plugins.market', 'plugins.market', 'navigation', { run:function(){ window.showPluginList('market'); } }),
|
|
21739
|
+
guiCommand('view.plugins.github', 'plugins.github', 'navigation', { run:function(){ window.showPluginList('github'); } }),
|
|
21740
|
+
guiCommand('view.memoryLab', 'memoryLab.title', 'navigation', { bindings:[{ keys:'Mod+K M', scope:'whenNotEditing' }], run:function(){ window.showMemoryLab(); } }),
|
|
21741
|
+
guiCommand('view.automation', 'automation.title', 'navigation', { bindings:[{ keys:'Mod+K A', scope:'whenNotEditing' }], run:function(){ window.showAutomationWindow(); } }),
|
|
21742
|
+
guiCommand('automation.new', 'automation.new', 'navigation', { run:function(){ window.showNewAutomationForm(); } }),
|
|
21743
|
+
guiCommand('view.flowEditor', 'flow.title', 'navigation', { bindings:[{ keys:'Mod+K F', scope:'whenNotEditing' }], run:function(){ window.showFlowEditor(); } }),
|
|
21744
|
+
guiCommand('flow.new', 'flow.new', 'navigation', { run:function(){ window.newFlowWork(); } }),
|
|
21745
|
+
|
|
21746
|
+
guiCommand('focus.primaryInput', 'shortcuts.focusPrimary', 'layout', { bindings:[{ keys:'Mod+K C', scope:'whenNotEditing' }], run:guiFocusPrompt, available:function(){ return !guiSubWindowOpen(); } }),
|
|
21747
|
+
guiCommand('focus.nextRegion', 'shortcuts.focusNext', 'layout', { bindings:[{ keys:'F6', scope:'global' }], run:function(){ window.cycleGuiRegionFocus(1); }, available:function(){ return !guiSubWindowOpen() && !window.commandSurfaceIsOpen(); } }),
|
|
21748
|
+
guiCommand('focus.previousRegion', 'shortcuts.focusPrevious', 'layout', { bindings:[{ keys:'Shift+F6', scope:'global' }], run:function(){ window.cycleGuiRegionFocus(-1); }, available:function(){ return !guiSubWindowOpen() && !window.commandSurfaceIsOpen(); } }),
|
|
21749
|
+
guiCommand('view.toggleLeft', 'shortcuts.toggleLeft', 'layout', { bindings:[{ keys:'Mod+B', scope:'whenNotEditing' }], run:function(){ window.toggleLeft(); } }),
|
|
21750
|
+
guiCommand('view.toggleWorkspacePanel', 'shortcuts.toggleWorkspacePanel', 'layout', { run:function(){ window.toggleSecondarySidebar(); } }),
|
|
21751
|
+
guiCommand('view.toggleRight', 'shortcuts.toggleRight', 'layout', { run:function(){ window.toggleRight(); } }),
|
|
21752
|
+
guiCommand('view.toggleTerminal', 'shortcuts.toggleTerminal', 'layout', { bindings:[{ keys:'Mod+`', scope:'whenNotEditing' }], run:function(){ window.toggleBottom(); } }),
|
|
21753
|
+
guiCommand('chat.scrollBottom', 'shortcuts.scrollBottom', 'layout', { bindings:[{ keys:'Mod+End', scope:'whenNotEditing' }], run:function(){ window.scrollToBottom(); } }),
|
|
21754
|
+
|
|
21755
|
+
guiCommand('right.files', 'right.files', 'navigation', { bindings:[{ keys:'Mod+K 1', scope:'whenNotEditing' }], run:function(){ window.switchRightTab('file-tree'); } }),
|
|
21756
|
+
guiCommand('right.editor', 'right.editor', 'navigation', { bindings:[{ keys:'Mod+K 2', scope:'whenNotEditing' }], run:function(){ window.switchRightTab('editor'); } }),
|
|
21757
|
+
guiCommand('right.plan', 'right.plan', 'navigation', { bindings:[{ keys:'Mod+K 3', scope:'whenNotEditing' }], run:function(){ window.switchRightTab('plan'); } }),
|
|
21758
|
+
guiCommand('right.subagents', 'right.subagents', 'navigation', { run:function(){ window.switchRightTab('subagent'); } }),
|
|
21759
|
+
guiCommand('right.browser', 'right.browser', 'navigation', { bindings:[{ keys:'Mod+K 4', scope:'whenNotEditing' }], run:function(){ window.switchRightTab('browser'); } }),
|
|
21760
|
+
guiCommand('right.status', 'right.status', 'navigation', { run:function(){ window.switchRightTab('status'); } }),
|
|
21761
|
+
guiCommand('right.archives', 'right.archives', 'navigation', { run:function(){ window.switchRightTab('archives'); } }),
|
|
21762
|
+
|
|
21763
|
+
guiCommand('mode.build', 'mode.build', 'input', { bindings:[{ keys:'Mod+1', scope:'whenNotEditing' }], run:function(){ guiSetSelectValue('mode-select','build'); } }),
|
|
21764
|
+
guiCommand('mode.plan', 'mode.plan', 'input', { bindings:[{ keys:'Mod+2', scope:'whenNotEditing' }], run:function(){ guiSetSelectValue('mode-select','plan'); } }),
|
|
21765
|
+
guiCommand('mode.goal', 'mode.goal', 'input', { bindings:[{ keys:'Mod+3', scope:'whenNotEditing' }], run:function(){ guiSetSelectValue('mode-select','goal'); } }),
|
|
21766
|
+
guiCommand('mode.flow', 'mode.flow', 'input', { bindings:[{ keys:'Mod+4', scope:'whenNotEditing' }], run:function(){ guiSetSelectValue('mode-select','flow'); } }),
|
|
21767
|
+
guiCommand('input.guide', 'input.guide', 'input', { bindings:[{ keys:'Mod+K G', scope:'whenNotEditing' }], run:function(){ window.setInputMode('guide'); } }),
|
|
21768
|
+
guiCommand('input.next', 'input.next', 'input', { bindings:[{ keys:'Mod+K E', scope:'whenNotEditing' }], run:function(){ window.setInputMode('next'); } }),
|
|
21769
|
+
guiCommand('goal.edit', 'goal.edit', 'input', { run:function(){ window.editGoal(); } }),
|
|
21770
|
+
guiCommand('goal.pauseResume', 'goal.pause', 'input', { bindings:[{ keys:'Mod+K Shift+G', scope:'whenNotEditing' }], run:function(){ window.toggleGoalPause(); }, available:function(){ return !!state.goalVisible; } }),
|
|
21771
|
+
|
|
21772
|
+
guiCommand('editor.save', 'common.save', 'editor', { bindings:[{ keys:'Mod+S', scope:'editor' }], run:function(){ window.saveEditor(); }, available:function(){ return !!state.editorPath; } }),
|
|
21773
|
+
guiCommand('editor.close', 'common.close', 'editor', { run:function(){ window.closeEditor(); }, available:function(){ return !!state.editorPath; } }),
|
|
21774
|
+
guiCommand('editor.markdownPreview', 'right.md', 'editor', { run:function(){ window.toggleEditorMarkdownPreview(); }, available:function(){ return !!state.editorPath; } }),
|
|
21775
|
+
guiCommand('editor.prediction', 'model.thinking', 'editor', { run:function(){ window.toggleEditorPrediction(); }, available:function(){ return !!state.editorPath; } }),
|
|
21776
|
+
guiCommand('editor.completion', 'model.validationCurrent', 'editor', { run:function(){ window.requestEditorCompletion({ force:true }); }, available:function(){ return !!state.editorPath; } }),
|
|
21777
|
+
|
|
21778
|
+
guiCommand('terminal.focus', 'shortcuts.focusTerminal', 'terminal', { bindings:[{ keys:'Mod+K T', scope:'whenNotEditing' }], run:guiFocusTerminal, available:function(){ return !guiSubWindowOpen(); } }),
|
|
21779
|
+
guiCommand('terminal.new', 'shortcuts.newTerminal', 'terminal', { run:function(){ window.addTerminalTab(); } }),
|
|
21780
|
+
guiCommand('terminal.clear', 'terminal.clear', 'terminal', { run:function(){ window.clearTerminal(); } }),
|
|
21781
|
+
|
|
21782
|
+
guiCommand('browser.focusAddress', 'shortcuts.focusBrowserAddress', 'browser', { bindings:[{ keys:'Mod+L', scope:'browser' }, { keys:'Mod+K B', scope:'whenNotEditing' }], run:guiFocusBrowserAddress, available:function(){ return !guiSubWindowOpen(); } }),
|
|
21783
|
+
guiCommand('browser.back', 'browser.back', 'browser', { bindings:[{ keys:'Alt+ArrowLeft', scope:'browser' }], run:function(){ window.browserBack(); } }),
|
|
21784
|
+
guiCommand('browser.forward', 'browser.forward', 'browser', { bindings:[{ keys:'Alt+ArrowRight', scope:'browser' }], run:function(){ window.browserForward(); } }),
|
|
21785
|
+
guiCommand('browser.reload', 'browser.reload', 'browser', { bindings:[{ keys:'Mod+R', scope:'browser' }, { keys:'F5', scope:'browser' }], run:function(){ window.browserReload(); } }),
|
|
21786
|
+
guiCommand('browser.computerUse', 'right.browser', 'browser', { run:function(){ window.toggleComputerUse(); } }),
|
|
21787
|
+
|
|
21788
|
+
guiCommand('settings.general', 'settings.general', 'context', { run:function(){ window.openSettings('general'); } }),
|
|
21789
|
+
guiCommand('settings.models', 'settings.models', 'context', { run:function(){ window.openSettings('models'); } }),
|
|
21790
|
+
guiCommand('settings.tools', 'settings.tools', 'context', { run:function(){ window.openSettings('tools'); } }),
|
|
21791
|
+
guiCommand('settings.archive', 'settings.archive', 'context', { run:function(){ window.openSettings('archive'); } }),
|
|
21792
|
+
guiCommand('settings.updates', 'settings.updates', 'context', { run:function(){ window.openSettings('updates'); } })
|
|
21793
|
+
];
|
|
21794
|
+
window.NEWMARK_GUI_COMMANDS = NEWMARK_GUI_COMMANDS;
|
|
21795
|
+
|
|
21796
|
+
window.activateButtonLike = function(event) {
|
|
21797
|
+
if (!event || event.defaultPrevented || event.isComposing || event.key === 'Process' || event.keyCode === 229) return false;
|
|
21798
|
+
if (event.key !== 'Enter' && event.key !== ' ') return false;
|
|
21799
|
+
if (event.target !== event.currentTarget) return false;
|
|
21800
|
+
event.preventDefault();
|
|
21801
|
+
event.currentTarget.click();
|
|
21802
|
+
return true;
|
|
21803
|
+
};
|
|
21804
|
+
|
|
21805
|
+
function guiCommandTitle(command) {
|
|
21806
|
+
return t(command.titleKey || command.id);
|
|
21807
|
+
}
|
|
21808
|
+
|
|
21809
|
+
function guiCommandCategory(command) {
|
|
21810
|
+
return t('shortcuts.category.' + (command.category || 'general'));
|
|
21811
|
+
}
|
|
21812
|
+
|
|
21813
|
+
function guiCommandAvailable(command) {
|
|
21814
|
+
try { return !command.available || command.available() !== false; }
|
|
21815
|
+
catch(e) { return false; }
|
|
21816
|
+
}
|
|
21817
|
+
|
|
21818
|
+
function guiKeyboardContext(event) {
|
|
21819
|
+
var target = event && event.target && event.target.nodeType === 1 ? event.target : document.activeElement;
|
|
21820
|
+
var closest = function(selector) { return target && target.closest ? target.closest(selector) : null; };
|
|
21821
|
+
var editable = !!(target && ((target.matches && target.matches('input, textarea, select, [role="textbox"], [role="combobox"]')) || target.isContentEditable || closest('[contenteditable]:not([contenteditable="false"])')));
|
|
21822
|
+
return {
|
|
21823
|
+
target: target,
|
|
21824
|
+
editable: editable,
|
|
21825
|
+
editor: !!closest('#native-editor, #panel-editor'),
|
|
21826
|
+
terminal: !!closest('#bottom, .terminal-pane'),
|
|
21827
|
+
browser: !!closest('#panel-browser, .browser-url-bar') || state.rightTab === 'browser' && !!closest('#right'),
|
|
21828
|
+
prompt: !!(els.prompt && (target === els.prompt || (els.prompt.contains && els.prompt.contains(target)))),
|
|
21829
|
+
dialog: !!closest('[role="dialog"]')
|
|
21830
|
+
};
|
|
21831
|
+
}
|
|
21832
|
+
|
|
21833
|
+
function guiBindingScopeMatches(scope, context) {
|
|
21834
|
+
if (scope === 'global') return true;
|
|
21835
|
+
if (scope === 'whenNotEditing') return !context.editable && !context.editor && !context.terminal && !context.browser && !context.dialog;
|
|
21836
|
+
if (scope === 'editor') return context.editor;
|
|
21837
|
+
if (scope === 'terminal') return context.terminal;
|
|
21838
|
+
if (scope === 'browser') return context.browser;
|
|
21839
|
+
if (scope === 'prompt') return context.prompt;
|
|
21840
|
+
if (scope === 'dialog') return context.dialog;
|
|
21841
|
+
return false;
|
|
21842
|
+
}
|
|
21843
|
+
|
|
21844
|
+
function guiEventSegment(event) {
|
|
21845
|
+
var key = String(event.key || '');
|
|
21846
|
+
if (!key || ['Control','Shift','Alt','Meta','AltGraph'].indexOf(key) >= 0) return '';
|
|
21847
|
+
var parts = [];
|
|
21848
|
+
var mac = guiIsMac();
|
|
21849
|
+
if ((mac && event.metaKey) || (!mac && event.ctrlKey)) parts.push('Mod');
|
|
21850
|
+
if ((mac && event.ctrlKey) || (!mac && event.metaKey)) parts.push(mac ? 'Ctrl' : 'Meta');
|
|
21851
|
+
if (event.altKey) parts.push('Alt');
|
|
21852
|
+
if (event.shiftKey) parts.push('Shift');
|
|
21853
|
+
var named = { ' ':'Space', 'Esc':'Escape', 'Left':'ArrowLeft', 'Right':'ArrowRight', 'Up':'ArrowUp', 'Down':'ArrowDown' };
|
|
21854
|
+
key = named[key] || key;
|
|
21855
|
+
if (key.length === 1 && /[a-z]/i.test(key)) key = key.toUpperCase();
|
|
21856
|
+
parts.push(key);
|
|
21857
|
+
return parts.join('+');
|
|
21858
|
+
}
|
|
21859
|
+
|
|
21860
|
+
var guiCommandSurfaceOriginFocus = null;
|
|
21861
|
+
var guiCommandSurfaceMode = 'palette';
|
|
21862
|
+
var guiCommandSurfaceMatches = [];
|
|
21863
|
+
var guiCommandSurfaceSelection = 0;
|
|
21864
|
+
var guiPendingChord = null;
|
|
21865
|
+
var guiPendingChordTimer = 0;
|
|
21866
|
+
|
|
21867
|
+
window.commandSurfaceIsOpen = function() {
|
|
21868
|
+
var overlay = document.getElementById('command-surface-overlay');
|
|
21869
|
+
return !!(overlay && overlay.classList.contains('open'));
|
|
21870
|
+
};
|
|
21871
|
+
|
|
21872
|
+
function guiClearChord() {
|
|
21873
|
+
guiPendingChord = null;
|
|
21874
|
+
if (guiPendingChordTimer) clearTimeout(guiPendingChordTimer);
|
|
21875
|
+
guiPendingChordTimer = 0;
|
|
21876
|
+
var hint = document.getElementById('shortcut-chord-hint');
|
|
21877
|
+
if (hint) hint.classList.remove('open');
|
|
21878
|
+
}
|
|
21879
|
+
|
|
21880
|
+
function guiShowChord(prefix, candidates) {
|
|
21881
|
+
guiClearChord();
|
|
21882
|
+
guiPendingChord = { prefix:prefix, candidates:candidates };
|
|
21883
|
+
var seconds = candidates.map(function(item){ return item.binding.keys.split(' ')[1]; }).filter(function(key,index,array){ return array.indexOf(key) === index; });
|
|
21884
|
+
var hint = document.getElementById('shortcut-chord-hint');
|
|
21885
|
+
if (hint) {
|
|
21886
|
+
hint.textContent = t('shortcuts.chordHint').replace('{prefix}', guiDisplayBinding(prefix)).replace('{keys}', seconds.join(' · '));
|
|
21887
|
+
hint.classList.add('open');
|
|
21888
|
+
}
|
|
21889
|
+
guiPendingChordTimer = setTimeout(guiClearChord, 1800);
|
|
21890
|
+
}
|
|
21891
|
+
|
|
21892
|
+
function guiNormalizeCommandSearchText(value) {
|
|
21893
|
+
return String(value || '')
|
|
21894
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
21895
|
+
.replace(/[._:/\\-]+/g, ' ')
|
|
21896
|
+
.replace(/\s+/g, ' ')
|
|
21897
|
+
.trim()
|
|
21898
|
+
.toLocaleLowerCase(uiLocale());
|
|
21899
|
+
}
|
|
21900
|
+
|
|
21901
|
+
function guiCommandSearchText(command) {
|
|
21902
|
+
var bindings = (command.bindings || []).map(guiDisplayBinding).join(' ');
|
|
21903
|
+
return guiNormalizeCommandSearchText([command.id, guiCommandTitle(command), guiCommandCategory(command), bindings].concat(command.keywords || []).join(' '));
|
|
21904
|
+
}
|
|
21905
|
+
|
|
21906
|
+
function guiCommandContextLabel(command) {
|
|
21907
|
+
var scopes = (command.bindings || []).map(function(binding){ return guiBindingRecord(command,binding).scope; });
|
|
21908
|
+
var scope = scopes[0] || command.scope || 'palette';
|
|
21909
|
+
if (scope === 'editor') return t('shortcuts.context.editor');
|
|
21910
|
+
if (scope === 'browser') return t('shortcuts.context.browser');
|
|
21911
|
+
if (scope === 'terminal') return t('shortcuts.context.terminal');
|
|
21912
|
+
if (scope === 'prompt') return t('shortcuts.context.prompt');
|
|
21913
|
+
if (scope === 'dialog') return t('shortcuts.context.dialog');
|
|
21914
|
+
return t('shortcuts.context.global');
|
|
21915
|
+
}
|
|
21916
|
+
|
|
21917
|
+
window.renderCommandSurface = function() {
|
|
21918
|
+
var list = document.getElementById('command-list');
|
|
21919
|
+
var search = document.getElementById('command-search');
|
|
21920
|
+
if (!list || !search) return;
|
|
21921
|
+
var query = guiNormalizeCommandSearchText(search.value);
|
|
21922
|
+
guiCommandSurfaceMatches = NEWMARK_GUI_COMMANDS.filter(function(command){ return !query || guiCommandSearchText(command).indexOf(query) >= 0; });
|
|
21923
|
+
if (guiCommandSurfaceSelection >= guiCommandSurfaceMatches.length) guiCommandSurfaceSelection = Math.max(0, guiCommandSurfaceMatches.length - 1);
|
|
21924
|
+
if (!guiCommandSurfaceMatches.length) {
|
|
21925
|
+
list.innerHTML = '<div class="command-empty">' + esc(t('shortcuts.noResults')) + '</div>';
|
|
21926
|
+
search.removeAttribute('aria-activedescendant');
|
|
21927
|
+
return;
|
|
21928
|
+
}
|
|
21929
|
+
var html = '';
|
|
21930
|
+
var priorCategory = '';
|
|
21931
|
+
for (var i = 0; i < guiCommandSurfaceMatches.length; i++) {
|
|
21932
|
+
var command = guiCommandSurfaceMatches[i];
|
|
21933
|
+
var category = guiCommandCategory(command);
|
|
21934
|
+
if (category !== priorCategory) {
|
|
21935
|
+
html += '<div class="command-category">' + esc(category) + '</div>';
|
|
21936
|
+
priorCategory = category;
|
|
21937
|
+
}
|
|
21938
|
+
var available = guiCommandAvailable(command);
|
|
21939
|
+
var keys = (command.bindings || []).map(function(binding){ return '<span class="command-key">' + esc(guiDisplayBinding(binding)) + '</span>'; }).join('');
|
|
21940
|
+
html += '<button type="button" class="command-option' + (i === guiCommandSurfaceSelection ? ' active' : '') + '" id="command-option-' + i + '" role="option" aria-selected="' + (i === guiCommandSurfaceSelection ? 'true' : 'false') + '" aria-disabled="' + (available ? 'false' : 'true') + '" tabindex="-1" onclick="window.executeCommandSurfaceIndex(' + i + ')">' +
|
|
21941
|
+
'<span><span class="command-option-title">' + esc(guiCommandTitle(command)) + '</span><span class="command-option-context">' + esc(guiCommandContextLabel(command)) + '</span></span>' +
|
|
21942
|
+
'<span class="command-shortcuts">' + keys + '</span></button>';
|
|
21943
|
+
}
|
|
21944
|
+
list.innerHTML = html;
|
|
21945
|
+
search.setAttribute('aria-activedescendant', 'command-option-' + guiCommandSurfaceSelection);
|
|
21946
|
+
var active = document.getElementById('command-option-' + guiCommandSurfaceSelection);
|
|
21947
|
+
if (active) active.scrollIntoView({ block:'nearest' });
|
|
21948
|
+
};
|
|
21949
|
+
|
|
21950
|
+
function guiMoveCommandSelection(delta, edge) {
|
|
21951
|
+
if (!guiCommandSurfaceMatches.length) return;
|
|
21952
|
+
if (edge === 'start') guiCommandSurfaceSelection = 0;
|
|
21953
|
+
else if (edge === 'end') guiCommandSurfaceSelection = guiCommandSurfaceMatches.length - 1;
|
|
21954
|
+
else guiCommandSurfaceSelection = (guiCommandSurfaceSelection + delta + guiCommandSurfaceMatches.length) % guiCommandSurfaceMatches.length;
|
|
21955
|
+
window.renderCommandSurface();
|
|
21956
|
+
}
|
|
21957
|
+
|
|
21958
|
+
window.openCommandSurface = function(mode) {
|
|
21959
|
+
var overlay = document.getElementById('command-surface-overlay');
|
|
21960
|
+
var search = document.getElementById('command-search');
|
|
21961
|
+
if (!overlay || !search) return;
|
|
21962
|
+
guiClearChord();
|
|
21963
|
+
if (!window.commandSurfaceIsOpen() && document.activeElement && typeof document.activeElement.focus === 'function') guiCommandSurfaceOriginFocus = document.activeElement;
|
|
21964
|
+
guiCommandSurfaceMode = mode === 'help' ? 'help' : 'palette';
|
|
21965
|
+
document.getElementById('command-surface-title').textContent = t(guiCommandSurfaceMode === 'help' ? 'shortcuts.helpTitle' : 'shortcuts.paletteTitle');
|
|
21966
|
+
document.getElementById('command-surface-subtitle').textContent = t(guiCommandSurfaceMode === 'help' ? 'shortcuts.helpSubtitle' : 'shortcuts.paletteSubtitle');
|
|
21967
|
+
document.getElementById('command-surface-footer').textContent = t('shortcuts.footer');
|
|
21968
|
+
search.setAttribute('placeholder', t(guiCommandSurfaceMode === 'help' ? 'shortcuts.searchShortcuts' : 'shortcuts.searchCommands'));
|
|
21969
|
+
search.value = '';
|
|
21970
|
+
guiCommandSurfaceSelection = 0;
|
|
21971
|
+
overlay.classList.add('open');
|
|
21972
|
+
updateApplicationInertState();
|
|
21973
|
+
window.renderCommandSurface();
|
|
21974
|
+
requestAnimationFrame(function(){ search.focus({ preventScroll:true }); });
|
|
21975
|
+
};
|
|
21976
|
+
|
|
21977
|
+
window.closeCommandSurface = function(options) {
|
|
21978
|
+
options = options || {};
|
|
21979
|
+
var overlay = document.getElementById('command-surface-overlay');
|
|
21980
|
+
if (!overlay || !overlay.classList.contains('open')) return;
|
|
21981
|
+
overlay.classList.remove('open');
|
|
21982
|
+
updateApplicationInertState();
|
|
21983
|
+
var restore = guiCommandSurfaceOriginFocus;
|
|
21984
|
+
guiCommandSurfaceOriginFocus = null;
|
|
21985
|
+
if (options.restoreFocus !== false) requestAnimationFrame(function(){ if (restore && restore.isConnected && typeof restore.focus === 'function') restore.focus({ preventScroll:true }); });
|
|
21986
|
+
return restore;
|
|
21987
|
+
};
|
|
21988
|
+
|
|
21989
|
+
window.executeGuiCommand = function(id, options) {
|
|
21990
|
+
var command = NEWMARK_GUI_COMMANDS.find(function(item){ return item.id === id; });
|
|
21991
|
+
if (!command || !guiCommandAvailable(command) || typeof command.run !== 'function') return false;
|
|
21992
|
+
try {
|
|
21993
|
+
var result = command.run(options || {});
|
|
21994
|
+
if (result && typeof result.catch === 'function') result.catch(function(error){ showUiNotice(error && error.message ? error.message : String(error), 'error', 'gui-command-' + id); });
|
|
21995
|
+
return true;
|
|
21996
|
+
} catch(error) {
|
|
21997
|
+
showUiNotice(error && error.message ? error.message : String(error), 'error', 'gui-command-' + id);
|
|
21998
|
+
return false;
|
|
21999
|
+
}
|
|
22000
|
+
};
|
|
22001
|
+
|
|
22002
|
+
window.executeCommandSurfaceIndex = function(index) {
|
|
22003
|
+
var command = guiCommandSurfaceMatches[index];
|
|
22004
|
+
if (!command || !guiCommandAvailable(command)) return false;
|
|
22005
|
+
var restore = window.closeCommandSurface({ restoreFocus:false });
|
|
22006
|
+
setTimeout(function(){
|
|
22007
|
+
window.executeGuiCommand(command.id, { source:'commandSurface' });
|
|
22008
|
+
requestAnimationFrame(function() {
|
|
22009
|
+
if (!guiSubWindowOpen() && !window.commandSurfaceIsOpen() && restore && restore.isConnected && typeof restore.focus === 'function') restore.focus({ preventScroll:true });
|
|
22010
|
+
});
|
|
22011
|
+
}, 0);
|
|
22012
|
+
return true;
|
|
22013
|
+
};
|
|
22014
|
+
|
|
22015
|
+
function guiVisible(element) {
|
|
22016
|
+
return !!(element && element.isConnected && element.getClientRects().length && !element.closest('[inert]'));
|
|
22017
|
+
}
|
|
22018
|
+
|
|
22019
|
+
function guiRegionTargets() {
|
|
22020
|
+
var activeTerminalInput = document.querySelector('#terminal-body .terminal-pane.active .terminal-input') || document.getElementById('bottom-toggle-btn');
|
|
22021
|
+
var activeRightTab = document.querySelector('#right-tabs .tab-btn[data-tab].active') || document.querySelector('#right-tabs .tab-btn[data-tab]');
|
|
22022
|
+
return [
|
|
22023
|
+
{ container:document.getElementById('left'), target:document.querySelector('#left-content .left-nav-icon') || document.querySelector('#left-thumb .lt-item') },
|
|
22024
|
+
{ container:document.getElementById('left-secondary'), target:document.querySelector('#left-secondary button, #conversation-list button, #conversation-list [tabindex="0"]') },
|
|
22025
|
+
{ container:document.getElementById('center'), target:els.prompt },
|
|
22026
|
+
{ container:document.getElementById('bottom'), target:activeTerminalInput },
|
|
22027
|
+
{ container:document.getElementById('right'), target:activeRightTab }
|
|
22028
|
+
].filter(function(region){ return guiVisible(region.container) && guiVisible(region.target); });
|
|
22029
|
+
}
|
|
22030
|
+
|
|
22031
|
+
window.cycleGuiRegionFocus = function(direction) {
|
|
22032
|
+
var regions = guiRegionTargets();
|
|
22033
|
+
if (!regions.length) return false;
|
|
22034
|
+
var active = document.activeElement;
|
|
22035
|
+
var current = regions.findIndex(function(region){ return region.container === active || region.container.contains(active); });
|
|
22036
|
+
var next = current < 0 ? (direction > 0 ? 0 : regions.length - 1) : (current + direction + regions.length) % regions.length;
|
|
22037
|
+
regions[next].target.focus({ preventScroll:true });
|
|
22038
|
+
return true;
|
|
22039
|
+
};
|
|
22040
|
+
|
|
22041
|
+
window.validateGuiCommandRegistry = function() {
|
|
22042
|
+
var errors = [];
|
|
22043
|
+
var ids = Object.create(null);
|
|
22044
|
+
var bindings = Object.create(null);
|
|
22045
|
+
for (var i = 0; i < NEWMARK_GUI_COMMANDS.length; i++) {
|
|
22046
|
+
var command = NEWMARK_GUI_COMMANDS[i];
|
|
22047
|
+
if (!command.id || ids[command.id]) errors.push('duplicate command id: ' + command.id);
|
|
22048
|
+
ids[command.id] = true;
|
|
22049
|
+
if (typeof command.run !== 'function') errors.push('missing command handler: ' + command.id);
|
|
22050
|
+
for (var j = 0; j < (command.bindings || []).length; j++) {
|
|
22051
|
+
var binding = guiBindingRecord(command, command.bindings[j]);
|
|
22052
|
+
if (!binding.keys) { errors.push('empty binding: ' + command.id); continue; }
|
|
22053
|
+
var identity = binding.scope + '::' + binding.keys;
|
|
22054
|
+
if (bindings[identity]) errors.push('binding conflict: ' + binding.keys + ' (' + binding.scope + ')');
|
|
22055
|
+
bindings[identity] = command.id;
|
|
22056
|
+
if (/\bMeta\b/.test(binding.keys) || /(?:^|\+)Mod\+Alt\+/.test(binding.keys)) errors.push('reserved modifier: ' + binding.keys);
|
|
22057
|
+
if (/^(Alt\+F4|Alt\+Tab|Mod\+Alt\+Delete|Mod\+Shift\+Escape)$/.test(binding.keys)) errors.push('reserved shortcut: ' + binding.keys);
|
|
22058
|
+
}
|
|
22059
|
+
}
|
|
22060
|
+
return errors;
|
|
22061
|
+
};
|
|
22062
|
+
|
|
22063
|
+
function guiManifestHash(value) {
|
|
22064
|
+
var input = String(value || '');
|
|
22065
|
+
var hash = 2166136261;
|
|
22066
|
+
for (var i = 0; i < input.length; i++) {
|
|
22067
|
+
hash ^= input.charCodeAt(i);
|
|
22068
|
+
hash = Math.imul(hash, 16777619);
|
|
22069
|
+
}
|
|
22070
|
+
return ('00000000' + (hash >>> 0).toString(16)).slice(-8);
|
|
22071
|
+
}
|
|
22072
|
+
|
|
22073
|
+
window.getGuiCommandManifest = function() {
|
|
22074
|
+
var commands = NEWMARK_GUI_COMMANDS.map(function(command) {
|
|
22075
|
+
return {
|
|
22076
|
+
id: command.id,
|
|
22077
|
+
category: command.category || 'general',
|
|
22078
|
+
bindings: (command.bindings || []).map(function(binding) {
|
|
22079
|
+
var record = guiBindingRecord(command, binding);
|
|
22080
|
+
return { keys: record.keys, scope: record.scope };
|
|
22081
|
+
})
|
|
22082
|
+
};
|
|
22083
|
+
});
|
|
22084
|
+
var serialized = JSON.stringify(commands);
|
|
22085
|
+
return {
|
|
22086
|
+
schemaVersion: 1,
|
|
22087
|
+
revision: 'fnv1a-' + guiManifestHash(serialized),
|
|
22088
|
+
commands: commands,
|
|
22089
|
+
errors: window.validateGuiCommandRegistry()
|
|
22090
|
+
};
|
|
22091
|
+
};
|
|
22092
|
+
|
|
22093
|
+
function guiHandleCommandKeydown(event) {
|
|
22094
|
+
if (!event || event.defaultPrevented || event.isComposing || event.key === 'Process' || event.keyCode === 229) return false;
|
|
22095
|
+
if (window.commandSurfaceIsOpen()) {
|
|
22096
|
+
if (event.key === 'Escape' && !event.repeat) { event.preventDefault(); event.stopPropagation(); window.closeCommandSurface(); return true; }
|
|
22097
|
+
if (event.key === 'Tab') return trapNewmarkDialogFocus(event, document.getElementById('command-surface'));
|
|
22098
|
+
return false;
|
|
22099
|
+
}
|
|
22100
|
+
if (event.repeat) return false;
|
|
22101
|
+
var segment = guiEventSegment(event);
|
|
22102
|
+
if (!segment) return false;
|
|
22103
|
+
if (guiPendingChord) {
|
|
22104
|
+
var match = guiPendingChord.candidates.find(function(item){ return item.binding.keys.split(' ')[1] === segment; });
|
|
22105
|
+
guiClearChord();
|
|
22106
|
+
event.preventDefault();
|
|
22107
|
+
event.stopPropagation();
|
|
22108
|
+
if (match) window.executeGuiCommand(match.command.id, { source:'shortcut' });
|
|
22109
|
+
return true;
|
|
22110
|
+
}
|
|
22111
|
+
var context = guiKeyboardContext(event);
|
|
22112
|
+
var direct = [];
|
|
22113
|
+
var chords = [];
|
|
22114
|
+
for (var i = 0; i < NEWMARK_GUI_COMMANDS.length; i++) {
|
|
22115
|
+
var command = NEWMARK_GUI_COMMANDS[i];
|
|
22116
|
+
if (!guiCommandAvailable(command)) continue;
|
|
22117
|
+
for (var j = 0; j < (command.bindings || []).length; j++) {
|
|
22118
|
+
var binding = guiBindingRecord(command, command.bindings[j]);
|
|
22119
|
+
if (!guiBindingScopeMatches(binding.scope, context)) continue;
|
|
22120
|
+
var pieces = binding.keys.split(' ');
|
|
22121
|
+
if (pieces[0] !== segment) continue;
|
|
22122
|
+
if (pieces.length === 1) direct.push({ command:command, binding:binding });
|
|
22123
|
+
else if (pieces.length === 2) chords.push({ command:command, binding:binding });
|
|
22124
|
+
}
|
|
22125
|
+
}
|
|
22126
|
+
if (direct.length) {
|
|
22127
|
+
event.preventDefault();
|
|
22128
|
+
event.stopPropagation();
|
|
22129
|
+
window.executeGuiCommand(direct[0].command.id, { source:'shortcut' });
|
|
22130
|
+
return true;
|
|
22131
|
+
}
|
|
22132
|
+
if (chords.length) {
|
|
22133
|
+
event.preventDefault();
|
|
22134
|
+
event.stopPropagation();
|
|
22135
|
+
guiShowChord(segment, chords);
|
|
22136
|
+
return true;
|
|
22137
|
+
}
|
|
22138
|
+
return false;
|
|
22139
|
+
}
|
|
22140
|
+
|
|
22141
|
+
function setupGuiKeyboard() {
|
|
22142
|
+
if (state._guiKeyboardReady) return;
|
|
22143
|
+
state._guiKeyboardReady = true;
|
|
22144
|
+
var errors = window.validateGuiCommandRegistry();
|
|
22145
|
+
if (errors.length) console.error('[Keyboard] command registry conflicts:', errors);
|
|
22146
|
+
var search = document.getElementById('command-search');
|
|
22147
|
+
if (search) {
|
|
22148
|
+
search.addEventListener('input', function(){ guiCommandSurfaceSelection = 0; window.renderCommandSurface(); });
|
|
22149
|
+
search.addEventListener('keydown', function(event){
|
|
22150
|
+
if (event.isComposing || event.key === 'Process' || event.keyCode === 229) return;
|
|
22151
|
+
if (event.key === 'ArrowDown') { event.preventDefault(); guiMoveCommandSelection(1); }
|
|
22152
|
+
else if (event.key === 'ArrowUp') { event.preventDefault(); guiMoveCommandSelection(-1); }
|
|
22153
|
+
else if (event.key === 'Home' && !event.ctrlKey && !event.metaKey) { event.preventDefault(); guiMoveCommandSelection(0,'start'); }
|
|
22154
|
+
else if (event.key === 'End' && !event.ctrlKey && !event.metaKey) { event.preventDefault(); guiMoveCommandSelection(0,'end'); }
|
|
22155
|
+
else if (event.key === 'Enter') { event.preventDefault(); window.executeCommandSurfaceIndex(guiCommandSurfaceSelection); }
|
|
22156
|
+
});
|
|
22157
|
+
}
|
|
22158
|
+
document.addEventListener('keydown', guiHandleCommandKeydown, true);
|
|
22159
|
+
if (api.onKeyboardCommand) api.onKeyboardCommand(function(payload){ if (payload && payload.id) window.executeGuiCommand(String(payload.id), { source:'browserGuest' }); });
|
|
22160
|
+
var attributes = [
|
|
22161
|
+
['#left-collapse-btn','view.toggleLeft'],
|
|
22162
|
+
['#bottom-toggle-btn','view.toggleTerminal'],
|
|
22163
|
+
['.sub-win-close','common.close']
|
|
22164
|
+
];
|
|
22165
|
+
for (var i = 0; i < attributes.length; i++) {
|
|
22166
|
+
var element = document.querySelector(attributes[i][0]);
|
|
22167
|
+
var command = NEWMARK_GUI_COMMANDS.find(function(item){ return item.id === attributes[i][1]; });
|
|
22168
|
+
if (!element || !command || !command.bindings.length) continue;
|
|
22169
|
+
var direct = guiBindingRecord(command,command.bindings[0]).keys;
|
|
22170
|
+
if (direct.indexOf(' ') < 0) element.setAttribute('aria-keyshortcuts', direct.replace(/\bMod\b/g, guiIsMac() ? 'Meta' : 'Control'));
|
|
22171
|
+
}
|
|
22172
|
+
var manifest = window.getGuiCommandManifest();
|
|
22173
|
+
document.documentElement.dataset.keyboardRegistry = manifest.errors.length ? 'invalid' : manifest.revision;
|
|
22174
|
+
}
|
|
22175
|
+
|
|
19891
22176
|
function schedulePostStartupUiRendering() {
|
|
19892
22177
|
if (state._postStartupUiRendering && state._postStartupUiRendering.cancel) state._postStartupUiRendering.cancel();
|
|
19893
22178
|
var tasks = [
|
|
@@ -19936,8 +22221,33 @@ function schedulePostStartupUiRendering() {
|
|
|
19936
22221
|
(function initResize() {
|
|
19937
22222
|
var handles = document.querySelectorAll('.resize-handle');
|
|
19938
22223
|
for (var i = 0; i < handles.length; i++) {
|
|
22224
|
+
var resizeTarget = handles[i].getAttribute('data-target');
|
|
22225
|
+
if (resizeTarget === 'left') { handles[i].setAttribute('aria-valuemin', '220'); handles[i].setAttribute('aria-valuemax', '460'); }
|
|
22226
|
+
if (resizeTarget === 'right') { handles[i].setAttribute('aria-valuemin', '340'); handles[i].setAttribute('aria-valuemax', '680'); }
|
|
22227
|
+
handles[i].addEventListener('keydown', function(e) {
|
|
22228
|
+
if (!e || e.defaultPrevented || e.isComposing || e.key === 'Process' || e.keyCode === 229 || e.ctrlKey || e.metaKey || e.altKey) return;
|
|
22229
|
+
var target = this.getAttribute('data-target');
|
|
22230
|
+
var side = this.getAttribute('data-side');
|
|
22231
|
+
var el = target === 'left' ? (els.left || document.getElementById('left')) : (target === 'right' ? (els.right || document.getElementById('right')) : null);
|
|
22232
|
+
if (!el || (target === 'left' && state.leftCollapsed) || (target === 'right' && state.rightCollapsed)) return;
|
|
22233
|
+
var min = target === 'left' ? 220 : 340;
|
|
22234
|
+
var max = target === 'left' ? 460 : 680;
|
|
22235
|
+
var size = el.offsetWidth;
|
|
22236
|
+
var delta = e.shiftKey ? 32 : 12;
|
|
22237
|
+
if (e.key === 'Home') size = min;
|
|
22238
|
+
else if (e.key === 'End') size = max;
|
|
22239
|
+
else if (e.key === 'ArrowLeft') size += side === 'left' ? delta : -delta;
|
|
22240
|
+
else if (e.key === 'ArrowRight') size += side === 'left' ? -delta : delta;
|
|
22241
|
+
else return;
|
|
22242
|
+
e.preventDefault();
|
|
22243
|
+
size = Math.max(min, Math.min(max, size));
|
|
22244
|
+
if (target === 'left') { setLeftWidthPx(size); state.leftWidth = size; }
|
|
22245
|
+
else window.setRightWidthPx(size);
|
|
22246
|
+
this.setAttribute('aria-valuenow', String(Math.round(size)));
|
|
22247
|
+
});
|
|
19939
22248
|
handles[i].addEventListener('mousedown', function(e) {
|
|
19940
22249
|
e.preventDefault();
|
|
22250
|
+
var handle = this;
|
|
19941
22251
|
var target = this.getAttribute('data-target');
|
|
19942
22252
|
var side = this.getAttribute('data-side');
|
|
19943
22253
|
var el = target === 'left' ? els.left : (target === 'right' ? els.right : null);
|
|
@@ -19957,10 +22267,12 @@ function schedulePostStartupUiRendering() {
|
|
|
19957
22267
|
var leftSize = Math.max(220, Math.min(460, newSize));
|
|
19958
22268
|
setLeftWidthPx(leftSize);
|
|
19959
22269
|
state.leftWidth = leftSize;
|
|
22270
|
+
handle.setAttribute('aria-valuenow', String(Math.round(leftSize)));
|
|
19960
22271
|
} else if (side === 'left') {
|
|
19961
22272
|
var newSize2 = startSize - dx;
|
|
19962
22273
|
var rightSize = Math.max(340, Math.min(680, newSize2));
|
|
19963
22274
|
window.setRightWidthPx(rightSize);
|
|
22275
|
+
handle.setAttribute('aria-valuenow', String(Math.round(rightSize)));
|
|
19964
22276
|
} else if (side === 'top') {
|
|
19965
22277
|
var newSize3 = startSize - dy;
|
|
19966
22278
|
el.style.height = Math.max(0, Math.min(400, newSize3)) + 'px';
|
|
@@ -20059,6 +22371,10 @@ function schedulePostStartupUiRendering() {
|
|
|
20059
22371
|
var startupHydrationError = null;
|
|
20060
22372
|
cacheEls();
|
|
20061
22373
|
setupAgentWorkEvents();
|
|
22374
|
+
if (api.onEditorCompletionDelta && !state._editorCompletionDeltaReady) {
|
|
22375
|
+
state._editorCompletionDeltaReady = true;
|
|
22376
|
+
api.onEditorCompletionDelta(function(payload) { window.applyEditorCompletionDelta(payload); });
|
|
22377
|
+
}
|
|
20062
22378
|
if (api.onBrowserEnsureGuest) {
|
|
20063
22379
|
api.onBrowserEnsureGuest(function(target) {
|
|
20064
22380
|
cancelBrowserGuestIdleDestroy();
|
|
@@ -20171,6 +22487,7 @@ function schedulePostStartupUiRendering() {
|
|
|
20171
22487
|
startupHydrationError = e;
|
|
20172
22488
|
}
|
|
20173
22489
|
applyUiAppearance();
|
|
22490
|
+
setupGuiKeyboard();
|
|
20174
22491
|
window.renderContextWindow();
|
|
20175
22492
|
if (api.onAutomationUpdated) {
|
|
20176
22493
|
api.onAutomationUpdated(function() {
|
|
@@ -20216,12 +22533,12 @@ function schedulePostStartupUiRendering() {
|
|
|
20216
22533
|
|
|
20217
22534
|
function stopRunningFromEscape(event) {
|
|
20218
22535
|
if (!event || event.key !== 'Escape' || event.defaultPrevented || escapeBelongsToFocusedControl(event)) return false;
|
|
20219
|
-
if (currentFlowRunning() && flowTakeoverMatchesCurrent()
|
|
22536
|
+
if (currentFlowRunning() && flowTakeoverMatchesCurrent()) {
|
|
20220
22537
|
event.preventDefault();
|
|
20221
22538
|
window.stopFlowRun();
|
|
20222
22539
|
return true;
|
|
20223
22540
|
}
|
|
20224
|
-
if (isCurrentConversationRunning()
|
|
22541
|
+
if (isCurrentConversationRunning()) {
|
|
20225
22542
|
event.preventDefault();
|
|
20226
22543
|
window.stopCurrentConversation();
|
|
20227
22544
|
return true;
|
|
@@ -20234,22 +22551,30 @@ function schedulePostStartupUiRendering() {
|
|
|
20234
22551
|
// after focus moved to the chat, title bar, button, or another non-editor
|
|
20235
22552
|
// surface. Modal/editor/select Escape behavior remains owned by that UI.
|
|
20236
22553
|
document.addEventListener('keydown', function(event) {
|
|
22554
|
+
if (!event || event.defaultPrevented || event.repeat || event.isComposing || event.key === 'Process' || event.keyCode === 229) return;
|
|
22555
|
+
if (event.key === 'Escape' && !event.defaultPrevented && els['sub-win-overlay'] && els['sub-win-overlay'].classList.contains('open')) {
|
|
22556
|
+
event.preventDefault();
|
|
22557
|
+
event.stopPropagation();
|
|
22558
|
+
window.closeSubWin();
|
|
22559
|
+
return;
|
|
22560
|
+
}
|
|
20237
22561
|
if (stopRunningFromEscape(event)) event.stopPropagation();
|
|
20238
22562
|
});
|
|
20239
22563
|
|
|
20240
22564
|
if (els.prompt) {
|
|
20241
22565
|
els.prompt.addEventListener('keydown', function(e) {
|
|
20242
|
-
if (e.key === '
|
|
22566
|
+
if (e.isComposing || e.key === 'Process' || e.keyCode === 229) return;
|
|
22567
|
+
if (e.key === 'Escape' && currentFlowRunning() && flowTakeoverMatchesCurrent()) {
|
|
20243
22568
|
e.preventDefault();
|
|
20244
22569
|
window.stopFlowRun();
|
|
20245
22570
|
return;
|
|
20246
22571
|
}
|
|
20247
|
-
if (e.key === 'Escape' && isCurrentConversationRunning()
|
|
22572
|
+
if (e.key === 'Escape' && isCurrentConversationRunning()) {
|
|
20248
22573
|
e.preventDefault();
|
|
20249
22574
|
window.stopCurrentConversation();
|
|
20250
22575
|
return;
|
|
20251
22576
|
}
|
|
20252
|
-
if (e.key === 'Enter' && e.ctrlKey) {
|
|
22577
|
+
if (e.key === 'Enter' && (e.ctrlKey || e.metaKey) && !e.altKey && !e.shiftKey) {
|
|
20253
22578
|
e.preventDefault();
|
|
20254
22579
|
if (state.mode === 'flow' || (currentFlowRunning() && flowTakeoverMatchesCurrent())) {
|
|
20255
22580
|
window.submitCurrentAction();
|
|
@@ -20259,9 +22584,9 @@ function schedulePostStartupUiRendering() {
|
|
|
20259
22584
|
window.sendMessage(opposite);
|
|
20260
22585
|
return;
|
|
20261
22586
|
}
|
|
20262
|
-
if (e.key === 'Enter' && !e.shiftKey) {
|
|
22587
|
+
if (e.key === 'Enter' && !e.shiftKey && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
20263
22588
|
e.preventDefault();
|
|
20264
|
-
window.submitCurrentAction();
|
|
22589
|
+
window.submitCurrentAction('enter');
|
|
20265
22590
|
}
|
|
20266
22591
|
});
|
|
20267
22592
|
els.prompt.addEventListener('input', function() {
|
|
@@ -20356,10 +22681,10 @@ function schedulePostStartupUiRendering() {
|
|
|
20356
22681
|
els['editor-textarea'].addEventListener('select', window.handleEditorCaretChange);
|
|
20357
22682
|
els['editor-textarea'].addEventListener('keyup', window.handleEditorCaretChange);
|
|
20358
22683
|
els['editor-textarea'].addEventListener('keydown', function(e) {
|
|
22684
|
+
if (e.isComposing || e.key === 'Process' || e.keyCode === 229) return;
|
|
20359
22685
|
if (state.editorCompletionText && e.key === 'Tab') { e.preventDefault(); window.acceptEditorCompletion(); return; }
|
|
20360
22686
|
if (e.key === 'Escape' && (state.editorCompletionText || (els['editor-completion'] && els['editor-completion'].classList.contains('open')))) { e.preventDefault(); window.dismissEditorCompletion(); return; }
|
|
20361
22687
|
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 's') { e.preventDefault(); window.saveEditor(); return; }
|
|
20362
|
-
if ((e.ctrlKey && e.key === ' ') || (e.altKey && e.key === '\\')) { e.preventDefault(); window.requestEditorCompletion(); return; }
|
|
20363
22688
|
if (state.editorVimEnabled && e.key === 'Escape') { state.editorVimMode = 'normal'; state.editorVimPending = ''; e.preventDefault(); window.renderNativeEditor(); return; }
|
|
20364
22689
|
if (window.handleEditorVimKey(e)) return;
|
|
20365
22690
|
});
|