newmark-agent 0.3.12 → 0.4.2
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 +1259 -132
- package/dist/conversation-utility-host.js +3 -0
- package/dist/core/agent.d.ts +139 -5
- package/dist/core/agent.js +964 -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 +15 -0
- package/dist/core/toolPolicy.js +174 -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 +52 -6
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.js +39 -2
- package/dist/tools/nativeTools.js +6 -1
- package/dist/tui/src/app.js +24 -0
- package/dist/tui/src/i18n.js +151 -0
- package/dist/tui/src/render.js +152 -61
- package/dist/tui/src/state.js +83 -0
- package/dist/ui/index.html +2669 -234
- package/dist/ui/lucide-sprite.svg +31 -0
- package/dist/wsl-agent-host.bundle.cjs +1259 -132
- package/dist/wsl-agent-host.js +3 -0
- package/package.json +6 -10
- package/Flow/Electron-Debug-Release.Flow.json +0 -43
- package/Flow/Flow.md +0 -9
- package/Flow/UI-Feature-Integration.Flow.json +0 -96
package/dist/ui/index.html
CHANGED
|
@@ -10,6 +10,9 @@ try {
|
|
|
10
10
|
if (startupQuery.get('startupPrewarm') === '1' && Number(startupQuery.get('startupAttempt') || 0) > 0) {
|
|
11
11
|
document.documentElement.classList.add('startup-prewarm');
|
|
12
12
|
}
|
|
13
|
+
if (sessionStorage.getItem('newmark-config-reloading') === '1') {
|
|
14
|
+
document.documentElement.classList.add('config-reloading');
|
|
15
|
+
}
|
|
13
16
|
} catch {}
|
|
14
17
|
</script>
|
|
15
18
|
<style>
|
|
@@ -136,6 +139,21 @@ try {
|
|
|
136
139
|
--duration-normal: 250ms;
|
|
137
140
|
--duration-slow: 400ms;
|
|
138
141
|
|
|
142
|
+
/* Stable Newmark semantic layers. Components depend on meaning, not on an
|
|
143
|
+
upstream developer-preview framework's private tokens or brand palette. */
|
|
144
|
+
--nm-surface-canvas: var(--app-bg);
|
|
145
|
+
--nm-surface-sunken: var(--glass-bg-1);
|
|
146
|
+
--nm-surface-raised: var(--glass-bg-2);
|
|
147
|
+
--nm-surface-overlay: var(--modal-surface);
|
|
148
|
+
--nm-label-primary: var(--text-bright);
|
|
149
|
+
--nm-label-secondary: var(--text);
|
|
150
|
+
--nm-label-tertiary: var(--text-dim);
|
|
151
|
+
--nm-state-info: var(--accent);
|
|
152
|
+
--nm-state-success: var(--accent2);
|
|
153
|
+
--nm-state-warning: #f4c95d;
|
|
154
|
+
--nm-state-danger: #ff7785;
|
|
155
|
+
--nm-focus-ring: 0 0 0 3px var(--accent-glow);
|
|
156
|
+
|
|
139
157
|
/* Layout sizes */
|
|
140
158
|
--left-width: 200px;
|
|
141
159
|
--left-secondary-width: 220px;
|
|
@@ -264,6 +282,7 @@ html, body {
|
|
|
264
282
|
}
|
|
265
283
|
|
|
266
284
|
.startup-prewarm #startup-cover { display: flex; }
|
|
285
|
+
.config-reloading #startup-cover { display: flex; }
|
|
267
286
|
|
|
268
287
|
.startup-cover-shell {
|
|
269
288
|
width: min(520px, calc(100vw - 48px));
|
|
@@ -338,6 +357,19 @@ html, body {
|
|
|
338
357
|
border: 0;
|
|
339
358
|
}
|
|
340
359
|
button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus { outline: none; }
|
|
360
|
+
:where(button, select, input, textarea, [contenteditable], [tabindex]):focus-visible {
|
|
361
|
+
outline: 2px solid var(--accent);
|
|
362
|
+
outline-offset: 2px;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
@media (prefers-reduced-motion: reduce) {
|
|
366
|
+
*, *::before, *::after {
|
|
367
|
+
scroll-behavior: auto !important;
|
|
368
|
+
animation-duration: 0.01ms !important;
|
|
369
|
+
animation-iteration-count: 1 !important;
|
|
370
|
+
transition-duration: 0.01ms !important;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
341
373
|
::-webkit-scrollbar { width: 4px; height: 4px; }
|
|
342
374
|
::-webkit-scrollbar-track { background: transparent; }
|
|
343
375
|
::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.10); border-radius: var(--radius-full); }
|
|
@@ -527,6 +559,24 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
527
559
|
flex-shrink: 0;
|
|
528
560
|
}
|
|
529
561
|
|
|
562
|
+
button.lt-item,
|
|
563
|
+
button.left-nav-icon {
|
|
564
|
+
border: 0;
|
|
565
|
+
background: transparent;
|
|
566
|
+
font-family: var(--font-ui);
|
|
567
|
+
text-align: left;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
button.left-nav-icon { width: calc(100% - 12px); }
|
|
571
|
+
|
|
572
|
+
.lt-item:focus-visible,
|
|
573
|
+
.left-nav-icon:focus-visible {
|
|
574
|
+
outline: none;
|
|
575
|
+
color: var(--text-bright);
|
|
576
|
+
background: var(--control-hover-bg);
|
|
577
|
+
box-shadow: inset 0 0 0 2px var(--accent);
|
|
578
|
+
}
|
|
579
|
+
|
|
530
580
|
.lt-item:hover {
|
|
531
581
|
background: var(--glass-bg-2);
|
|
532
582
|
color: var(--text);
|
|
@@ -749,6 +799,14 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
749
799
|
overflow: hidden;
|
|
750
800
|
}
|
|
751
801
|
|
|
802
|
+
button.left-ws-item {
|
|
803
|
+
width: 100%;
|
|
804
|
+
border: 0;
|
|
805
|
+
background: transparent;
|
|
806
|
+
font-family: var(--font-ui);
|
|
807
|
+
text-align: left;
|
|
808
|
+
}
|
|
809
|
+
|
|
752
810
|
.left-ws-item:hover { background: var(--glass-bg-2); }
|
|
753
811
|
.left-ws-item.active { background: var(--accent-glow); color: var(--text-bright); }
|
|
754
812
|
|
|
@@ -1005,6 +1063,19 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
1005
1063
|
.conv-archive-btn:hover,
|
|
1006
1064
|
.conv-rename-btn:hover { background: rgba(255,255,255,0.1); color: var(--text-bright); }
|
|
1007
1065
|
|
|
1066
|
+
.conv-archive-btn.archiving { cursor: default; border-color: var(--accent); }
|
|
1067
|
+
.conv-archive-spinner {
|
|
1068
|
+
width: 11px;
|
|
1069
|
+
height: 11px;
|
|
1070
|
+
border: 2px solid var(--border);
|
|
1071
|
+
border-top-color: var(--accent);
|
|
1072
|
+
border-radius: 50%;
|
|
1073
|
+
animation: conv-archive-spin 0.7s linear infinite;
|
|
1074
|
+
}
|
|
1075
|
+
@keyframes conv-archive-spin {
|
|
1076
|
+
to { transform: rotate(360deg); }
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1008
1079
|
.conv-item.dragging { opacity: 0.58; }
|
|
1009
1080
|
.conv-item.drag-over { border-color: var(--accent); background: rgba(91,120,255,0.14); }
|
|
1010
1081
|
.conv-rename-input {
|
|
@@ -1055,6 +1126,11 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
1055
1126
|
}
|
|
1056
1127
|
|
|
1057
1128
|
.resize-handle:hover { background: var(--accent); }
|
|
1129
|
+
.resize-handle:focus-visible {
|
|
1130
|
+
outline: none;
|
|
1131
|
+
background: var(--accent);
|
|
1132
|
+
box-shadow: 0 0 0 2px var(--accent-glow);
|
|
1133
|
+
}
|
|
1058
1134
|
|
|
1059
1135
|
.resize-handle[data-side="left"] {
|
|
1060
1136
|
cursor: col-resize;
|
|
@@ -1883,12 +1959,12 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
1883
1959
|
|
|
1884
1960
|
.terminal-output {
|
|
1885
1961
|
flex: 1;
|
|
1886
|
-
overflow
|
|
1962
|
+
overflow: auto;
|
|
1887
1963
|
padding: 8px 12px;
|
|
1888
1964
|
font-family: var(--font-mono);
|
|
1889
1965
|
font-size: 12px;
|
|
1890
1966
|
color: var(--text-dim);
|
|
1891
|
-
white-space: pre
|
|
1967
|
+
white-space: pre;
|
|
1892
1968
|
line-height: 1.5;
|
|
1893
1969
|
}
|
|
1894
1970
|
|
|
@@ -2373,9 +2449,9 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
2373
2449
|
.conversation-work-event.error { color: #ff8888; }
|
|
2374
2450
|
.conversation-work-event-content { min-width: 0; white-space: pre-wrap; word-break: break-word; }
|
|
2375
2451
|
.conversation-work-event.narrative { display: block; color: var(--text); font-size: 13px; line-height: 1.65; padding: 3px 1px 7px; }
|
|
2376
|
-
.conversation-work-event.activity-summary { font-size:
|
|
2452
|
+
.conversation-work-event.activity-summary { font-size: 11px; font-weight: 400; color: var(--text-dim); padding: 2px 0; }
|
|
2377
2453
|
.conversation-work-activity { margin: 0; padding: 0; }
|
|
2378
|
-
.conversation-work-activity > summary { display: grid; grid-template-columns: 17px minmax(0,1fr) 10px; gap: 8px; align-items: center; min-height: 28px; cursor: pointer; list-style: none; color: var(--text); font-size:
|
|
2454
|
+
.conversation-work-activity > summary { display: grid; grid-template-columns: 17px minmax(0,1fr) 10px; gap: 8px; align-items: center; min-height: 28px; cursor: pointer; list-style: none; color: var(--text-dim); font-size: 11px; font-weight: 400; }
|
|
2379
2455
|
.conversation-work-activity > summary::-webkit-details-marker { display: none; }
|
|
2380
2456
|
.conversation-work-activity > summary .nm-icon { color: var(--text-dim); }
|
|
2381
2457
|
.conversation-work-activity-chevron { width: 7px; height: 7px; border-right: 1px solid var(--text-dim); border-bottom: 1px solid var(--text-dim); transform: rotate(-45deg); transition: transform 140ms ease; }
|
|
@@ -2419,6 +2495,8 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
2419
2495
|
.conversation-work-subagent-chip.completed .conversation-work-subagent-status { color: var(--accent2); }
|
|
2420
2496
|
.conversation-work-command-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2421
2497
|
.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; }
|
|
2498
|
+
.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; }
|
|
2499
|
+
.conversation-work-thought-pending { color: var(--text-dim); font-style: italic; }
|
|
2422
2500
|
.conversation-work-files { margin-top: 1px; }
|
|
2423
2501
|
.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
2502
|
.conversation-work-files > summary::-webkit-details-marker,
|
|
@@ -2524,7 +2602,7 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
2524
2602
|
.shell-block {
|
|
2525
2603
|
margin: 8px 0;
|
|
2526
2604
|
border-radius: var(--radius-md);
|
|
2527
|
-
background:
|
|
2605
|
+
background: var(--nm-surface-sunken);
|
|
2528
2606
|
border: 1px solid var(--glass-border-1);
|
|
2529
2607
|
overflow: hidden;
|
|
2530
2608
|
}
|
|
@@ -2550,7 +2628,7 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
2550
2628
|
font-family: var(--font-mono);
|
|
2551
2629
|
font-size: 12px;
|
|
2552
2630
|
color: var(--text-dim);
|
|
2553
|
-
white-space: pre
|
|
2631
|
+
white-space: pre;
|
|
2554
2632
|
line-height: 1.5;
|
|
2555
2633
|
max-height: 400px;
|
|
2556
2634
|
overflow: auto;
|
|
@@ -2583,6 +2661,23 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
2583
2661
|
.diff-block-header .arrow { transition: transform var(--duration-fast) var(--ease-out-expo); font-size: 9px; }
|
|
2584
2662
|
.diff-block.collapsed .diff-block-header .arrow { transform: rotate(-90deg); }
|
|
2585
2663
|
|
|
2664
|
+
button.shell-block-header,
|
|
2665
|
+
button.diff-block-header,
|
|
2666
|
+
button.flow-item-header,
|
|
2667
|
+
button.work-review-head,
|
|
2668
|
+
button.todo-item {
|
|
2669
|
+
width: 100%;
|
|
2670
|
+
border: 0;
|
|
2671
|
+
font-family: var(--font-ui);
|
|
2672
|
+
text-align: left;
|
|
2673
|
+
}
|
|
2674
|
+
|
|
2675
|
+
button.shell-block-header { background: rgba(255,255,255,0.03); }
|
|
2676
|
+
button.diff-block-header,
|
|
2677
|
+
button.flow-item-header,
|
|
2678
|
+
button.work-review-head,
|
|
2679
|
+
button.todo-item { background: transparent; }
|
|
2680
|
+
|
|
2586
2681
|
.diff-stat { display: flex; gap: 8px; margin-left: auto; }
|
|
2587
2682
|
.diff-add { color: var(--accent2); font-size: 11px; }
|
|
2588
2683
|
.diff-del { color: #ff6666; font-size: 11px; }
|
|
@@ -2958,6 +3053,8 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
2958
3053
|
.work-review-actions { display:flex; align-items:center; gap:5px; }
|
|
2959
3054
|
.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
3055
|
.work-review-btn:hover { background:var(--control-hover-bg); border-color:var(--border-hover); }
|
|
3056
|
+
.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; }
|
|
3057
|
+
.work-review-toggle:hover { background:var(--control-hover-bg); border-color:var(--border-hover); }
|
|
2961
3058
|
.work-review-list { border-top:1px solid var(--glass-border-1); }
|
|
2962
3059
|
.work-review.collapsed .work-review-list { display: none; }
|
|
2963
3060
|
.work-review-head { cursor: pointer; }
|
|
@@ -3057,6 +3154,20 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
3057
3154
|
font: 9px var(--font-mono);
|
|
3058
3155
|
}
|
|
3059
3156
|
|
|
3157
|
+
.conv-branch-comm-icon {
|
|
3158
|
+
width: 20px;
|
|
3159
|
+
height: 20px;
|
|
3160
|
+
border-radius: var(--radius-sm);
|
|
3161
|
+
border: 1px solid var(--border);
|
|
3162
|
+
background: transparent;
|
|
3163
|
+
color: var(--accent);
|
|
3164
|
+
display: flex;
|
|
3165
|
+
align-items: center;
|
|
3166
|
+
justify-content: center;
|
|
3167
|
+
flex-shrink: 0;
|
|
3168
|
+
}
|
|
3169
|
+
.conv-branch-comm-icon .nm-icon { width: 11px; height: 11px; }
|
|
3170
|
+
|
|
3060
3171
|
.conv-runtime-badge.running { color: var(--accent2); }
|
|
3061
3172
|
.conv-runtime-badge.stopping,
|
|
3062
3173
|
.conv-runtime-badge.force_restarting { color: #ffd27a; }
|
|
@@ -3391,9 +3502,47 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
3391
3502
|
flex: 0 0 auto;
|
|
3392
3503
|
}
|
|
3393
3504
|
|
|
3505
|
+
#context-inspector {
|
|
3506
|
+
position: absolute;
|
|
3507
|
+
right: -8px;
|
|
3508
|
+
bottom: calc(100% + 10px);
|
|
3509
|
+
z-index: 80;
|
|
3510
|
+
display: none;
|
|
3511
|
+
width: min(320px, calc(100vw - 24px));
|
|
3512
|
+
padding: 12px;
|
|
3513
|
+
border: 1px solid var(--glass-border-2);
|
|
3514
|
+
border-radius: var(--radius-lg);
|
|
3515
|
+
background: var(--modal-surface);
|
|
3516
|
+
box-shadow: var(--shadow-lg);
|
|
3517
|
+
backdrop-filter: blur(var(--glass-blur-3)) saturate(1.08);
|
|
3518
|
+
color: var(--text);
|
|
3519
|
+
font-size: 10px;
|
|
3520
|
+
line-height: 1.45;
|
|
3521
|
+
}
|
|
3522
|
+
#context-inspector.open { display: block; animation: model-menu-in 150ms var(--ease-out-expo); }
|
|
3523
|
+
.context-inspector-head { display:flex; align-items:flex-start; gap:8px; margin-bottom:10px; }
|
|
3524
|
+
.context-inspector-title { flex:1; min-width:0; color:var(--text-bright); font-size:12px; font-weight:700; }
|
|
3525
|
+
.context-inspector-subtitle { margin-top:2px; color:var(--text-dim); font-size:9px; }
|
|
3526
|
+
.context-inspector-close { width:22px; height:22px; padding:0; border:0; border-radius:var(--radius-sm); background:transparent; color:var(--text-dim); cursor:pointer; }
|
|
3527
|
+
.context-inspector-close:hover, .context-inspector-close:focus-visible { color:var(--text-bright); background:var(--control-hover-bg); outline:none; }
|
|
3528
|
+
.context-inspector-meter { height:6px; margin:8px 0 10px; overflow:hidden; border-radius:var(--radius-full); background:rgba(168,168,168,.18); }
|
|
3529
|
+
.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); }
|
|
3530
|
+
.context-inspector-grid { display:grid; grid-template-columns:1fr 1fr; gap:7px; }
|
|
3531
|
+
.context-inspector-cell { padding:7px 8px; border:1px solid var(--glass-border-1); border-radius:var(--radius-sm); background:var(--glass-bg-1); }
|
|
3532
|
+
.context-inspector-label { display:block; color:var(--text-dim); font-size:9px; }
|
|
3533
|
+
.context-inspector-value { display:block; margin-top:2px; color:var(--text-bright); font:600 10px var(--font-mono); }
|
|
3534
|
+
.context-inspector-section { margin-top:10px; padding-top:9px; border-top:1px solid var(--glass-border-1); }
|
|
3535
|
+
.context-inspector-section-title { color:var(--text-bright); font-size:10px; font-weight:650; }
|
|
3536
|
+
.context-inspector-meta { margin-top:3px; color:var(--text-dim); overflow-wrap:anywhere; }
|
|
3537
|
+
.context-inspector-actions { display:flex; align-items:center; gap:7px; margin-top:10px; }
|
|
3538
|
+
.context-inspector-actions .sec-btn { flex:1; min-width:0; }
|
|
3539
|
+
.context-inspector-actions .sec-btn:disabled { opacity:.55; cursor:wait; }
|
|
3540
|
+
|
|
3394
3541
|
#context-token-ring {
|
|
3395
3542
|
width: 16px;
|
|
3396
3543
|
height: 16px;
|
|
3544
|
+
padding: 0;
|
|
3545
|
+
border: 0;
|
|
3397
3546
|
border-radius: 50%;
|
|
3398
3547
|
background: conic-gradient(#a8a8a8 0deg, rgba(168,168,168,0.22) 0deg);
|
|
3399
3548
|
cursor: default;
|
|
@@ -3601,6 +3750,124 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
3601
3750
|
50% { box-shadow: 0 0 24px rgba(91,120,255,0.5), 0 0 60px rgba(91,120,255,0.15); }
|
|
3602
3751
|
}
|
|
3603
3752
|
|
|
3753
|
+
/* ============================================================
|
|
3754
|
+
KEYBOARD COMMAND SURFACE
|
|
3755
|
+
============================================================ */
|
|
3756
|
+
.command-surface-overlay {
|
|
3757
|
+
position: fixed;
|
|
3758
|
+
inset: 0;
|
|
3759
|
+
z-index: 320;
|
|
3760
|
+
display: flex;
|
|
3761
|
+
align-items: flex-start;
|
|
3762
|
+
justify-content: center;
|
|
3763
|
+
padding: min(12vh, 96px) 18px 18px;
|
|
3764
|
+
background: color-mix(in srgb, var(--nm-surface-canvas) 62%, transparent);
|
|
3765
|
+
opacity: 0;
|
|
3766
|
+
visibility: hidden;
|
|
3767
|
+
pointer-events: none;
|
|
3768
|
+
transition: opacity var(--duration-fast) var(--ease-out-expo), visibility 0ms linear var(--duration-fast);
|
|
3769
|
+
}
|
|
3770
|
+
|
|
3771
|
+
.command-surface-overlay.open {
|
|
3772
|
+
opacity: 1;
|
|
3773
|
+
visibility: visible;
|
|
3774
|
+
pointer-events: auto;
|
|
3775
|
+
transition-delay: 0ms, 0ms;
|
|
3776
|
+
}
|
|
3777
|
+
|
|
3778
|
+
.command-surface {
|
|
3779
|
+
width: min(680px, calc(100vw - 36px));
|
|
3780
|
+
max-height: min(680px, calc(100vh - 132px));
|
|
3781
|
+
display: flex;
|
|
3782
|
+
flex-direction: column;
|
|
3783
|
+
overflow: hidden;
|
|
3784
|
+
border: 1px solid var(--glass-border-2);
|
|
3785
|
+
border-radius: var(--radius-xl);
|
|
3786
|
+
background: var(--nm-surface-overlay);
|
|
3787
|
+
box-shadow: var(--shadow-lg);
|
|
3788
|
+
backdrop-filter: blur(var(--glass-blur-3)) saturate(150%);
|
|
3789
|
+
transform: translateY(-8px) scale(0.985);
|
|
3790
|
+
transition: transform var(--duration-fast) var(--ease-out-expo);
|
|
3791
|
+
}
|
|
3792
|
+
|
|
3793
|
+
.command-surface-overlay.open .command-surface { transform: translateY(0) scale(1); }
|
|
3794
|
+
.command-surface-header { display:flex; align-items:flex-start; gap:12px; padding:14px 16px 10px; }
|
|
3795
|
+
.command-surface-heading { flex:1; min-width:0; }
|
|
3796
|
+
.command-surface-title { color:var(--text-bright); font-size:14px; font-weight:700; }
|
|
3797
|
+
.command-surface-subtitle { margin-top:3px; color:var(--text-dim); font-size:10px; line-height:1.45; }
|
|
3798
|
+
.command-surface-close { width:28px; height:28px; border:0; border-radius:var(--radius-sm); background:transparent; color:var(--text-dim); cursor:pointer; }
|
|
3799
|
+
.command-surface-close:hover { color:var(--text-bright); background:var(--control-hover-bg); }
|
|
3800
|
+
.command-search-wrap { padding:0 14px 12px; }
|
|
3801
|
+
.command-search {
|
|
3802
|
+
width:100%;
|
|
3803
|
+
height:40px;
|
|
3804
|
+
box-sizing:border-box;
|
|
3805
|
+
padding:0 12px;
|
|
3806
|
+
border:1px solid var(--glass-border-2);
|
|
3807
|
+
border-radius:var(--radius-md);
|
|
3808
|
+
background:var(--control-bg);
|
|
3809
|
+
color:var(--text);
|
|
3810
|
+
font:12px var(--font-ui);
|
|
3811
|
+
}
|
|
3812
|
+
.command-search:focus { border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-glow); }
|
|
3813
|
+
.command-list { min-height:96px; overflow:auto; padding:0 8px 8px; }
|
|
3814
|
+
.command-category { padding:9px 9px 5px; color:var(--text-dim); font-size:9px; font-weight:700; letter-spacing:.07em; text-transform:uppercase; }
|
|
3815
|
+
.command-option {
|
|
3816
|
+
width:100%;
|
|
3817
|
+
min-height:42px;
|
|
3818
|
+
display:grid;
|
|
3819
|
+
grid-template-columns:minmax(0,1fr) auto;
|
|
3820
|
+
align-items:center;
|
|
3821
|
+
gap:12px;
|
|
3822
|
+
padding:6px 9px;
|
|
3823
|
+
border:1px solid transparent;
|
|
3824
|
+
border-radius:var(--radius-md);
|
|
3825
|
+
background:transparent;
|
|
3826
|
+
color:var(--text);
|
|
3827
|
+
text-align:left;
|
|
3828
|
+
cursor:pointer;
|
|
3829
|
+
font-family:var(--font-ui);
|
|
3830
|
+
}
|
|
3831
|
+
.command-option.active,
|
|
3832
|
+
.command-option:hover { background:var(--control-hover-bg); border-color:var(--glass-border-1); }
|
|
3833
|
+
.command-option[aria-disabled="true"] { opacity:.48; cursor:not-allowed; }
|
|
3834
|
+
.command-option-title { display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:12px; }
|
|
3835
|
+
.command-option-context { display:block; margin-top:2px; color:var(--text-dim); font-size:9px; }
|
|
3836
|
+
.command-shortcuts { display:flex; justify-content:flex-end; gap:4px; }
|
|
3837
|
+
.command-key {
|
|
3838
|
+
min-width:22px;
|
|
3839
|
+
padding:3px 6px;
|
|
3840
|
+
border:1px solid var(--glass-border-2);
|
|
3841
|
+
border-bottom-color:var(--border-hover);
|
|
3842
|
+
border-radius:5px;
|
|
3843
|
+
background:var(--glass-bg-1);
|
|
3844
|
+
color:var(--text-dim);
|
|
3845
|
+
font:10px var(--font-mono);
|
|
3846
|
+
text-align:center;
|
|
3847
|
+
white-space:nowrap;
|
|
3848
|
+
}
|
|
3849
|
+
.command-empty { padding:24px 12px; color:var(--text-dim); font-size:11px; text-align:center; }
|
|
3850
|
+
.command-surface-footer { padding:8px 14px 10px; border-top:1px solid var(--glass-border-1); color:var(--text-dim); font-size:9px; }
|
|
3851
|
+
.shortcut-chord-hint {
|
|
3852
|
+
position:fixed;
|
|
3853
|
+
z-index:330;
|
|
3854
|
+
left:50%;
|
|
3855
|
+
bottom:22px;
|
|
3856
|
+
max-width:min(520px, calc(100vw - 32px));
|
|
3857
|
+
padding:7px 10px;
|
|
3858
|
+
border:1px solid var(--glass-border-2);
|
|
3859
|
+
border-radius:var(--radius-md);
|
|
3860
|
+
background:var(--modal-surface);
|
|
3861
|
+
color:var(--text);
|
|
3862
|
+
box-shadow:var(--shadow-md);
|
|
3863
|
+
font:10px var(--font-mono);
|
|
3864
|
+
opacity:0;
|
|
3865
|
+
visibility:hidden;
|
|
3866
|
+
transform:translate(-50%, 4px);
|
|
3867
|
+
transition:opacity var(--duration-fast) var(--ease-out-expo), transform var(--duration-fast) var(--ease-out-expo), visibility 0ms linear var(--duration-fast);
|
|
3868
|
+
}
|
|
3869
|
+
.shortcut-chord-hint.open { opacity:1; visibility:visible; transform:translate(-50%, 0); transition-delay:0ms; }
|
|
3870
|
+
|
|
3604
3871
|
/* ============================================================
|
|
3605
3872
|
SUB-WINDOW SYSTEM
|
|
3606
3873
|
============================================================ */
|
|
@@ -3702,6 +3969,7 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
3702
3969
|
}
|
|
3703
3970
|
|
|
3704
3971
|
.sub-win-close:hover { background: rgba(255,68,68,0.15); color: #ff6666; }
|
|
3972
|
+
.sub-win-close:focus-visible { outline:none; color:#ff7777; box-shadow:inset 0 0 0 2px currentColor; }
|
|
3705
3973
|
|
|
3706
3974
|
.sub-win-body {
|
|
3707
3975
|
flex: 1;
|
|
@@ -3734,6 +4002,81 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
3734
4002
|
|
|
3735
4003
|
.stab-btn:hover { background: rgba(255,255,255,0.05); color: var(--text); }
|
|
3736
4004
|
.stab-btn.active { background: rgba(91,120,255,0.12); color: var(--accent); border-color: rgba(91,120,255,0.25); }
|
|
4005
|
+
.stab-btn:focus-visible { outline:none; border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-glow); color:var(--text-bright); }
|
|
4006
|
+
|
|
4007
|
+
.plugin-tabs { overflow-x:auto; scrollbar-width:thin; }
|
|
4008
|
+
.plugin-tabs .stab-btn { flex:0 0 auto; }
|
|
4009
|
+
.plugin-panel { min-height:180px; margin-top:10px; }
|
|
4010
|
+
.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; }
|
|
4011
|
+
.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); }
|
|
4012
|
+
.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); }
|
|
4013
|
+
.plugin-panel-state.error { border-color:var(--notice-error-border); color:var(--notice-error-text); }
|
|
4014
|
+
.plugin-panel-state .sec-btn { flex:0 0 auto; margin-left:auto; }
|
|
4015
|
+
.plugin-toolbar { display:flex; align-items:center; gap:8px; margin-bottom:12px; }
|
|
4016
|
+
.plugin-toolbar-copy { flex:1; min-width:0; }
|
|
4017
|
+
.plugin-toolbar-title { color:var(--text-bright); font-size:13px; font-weight:650; }
|
|
4018
|
+
.plugin-toolbar-meta { margin-top:2px; color:var(--text-dim); font-size:10px; }
|
|
4019
|
+
.plugin-toolbar .sec-btn { flex:0 0 auto; }
|
|
4020
|
+
.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); }
|
|
4021
|
+
.plugin-search:focus { border-color:var(--accent); box-shadow:0 0 0 2px var(--accent-glow); }
|
|
4022
|
+
.plugin-section { margin-top:14px; }
|
|
4023
|
+
.plugin-section-head { display:flex; align-items:center; gap:8px; margin-bottom:8px; }
|
|
4024
|
+
.plugin-section-title { color:var(--text-bright); font-size:12px; font-weight:650; }
|
|
4025
|
+
.plugin-count-badge,
|
|
4026
|
+
.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; }
|
|
4027
|
+
.plugin-status-badge.enabled { border-color:color-mix(in srgb, var(--accent2) 45%, transparent); color:var(--accent2); }
|
|
4028
|
+
.plugin-status-badge.preview { border-color:color-mix(in srgb, var(--accent) 45%, transparent); color:var(--text-accent); }
|
|
4029
|
+
.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; }
|
|
4030
|
+
.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); }
|
|
4031
|
+
.mcp-form-head { display:flex; align-items:flex-start; gap:10px; margin-bottom:12px; }
|
|
4032
|
+
.mcp-form-copy { flex:1; min-width:0; }
|
|
4033
|
+
.mcp-form-title { color:var(--text-bright); font-size:13px; font-weight:650; }
|
|
4034
|
+
.mcp-form-subtitle { margin-top:2px; color:var(--text-dim); font-size:10px; line-height:1.45; }
|
|
4035
|
+
.mcp-field-grid { display:grid; grid-template-columns:minmax(0,1fr) 130px; gap:10px; }
|
|
4036
|
+
.mcp-field { display:flex; flex-direction:column; gap:5px; margin-bottom:10px; }
|
|
4037
|
+
.mcp-field label { color:var(--text); font-size:10px; font-weight:600; }
|
|
4038
|
+
.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); }
|
|
4039
|
+
textarea.mcp-input { min-height:76px; resize:vertical; font-family:var(--font-mono); line-height:1.5; }
|
|
4040
|
+
.mcp-input:focus { border-color:var(--accent); box-shadow:0 0 0 2px var(--accent-glow); }
|
|
4041
|
+
.mcp-field-help { margin-top:-1px; color:var(--text-dim); font-size:9px; line-height:1.45; word-break:break-word; }
|
|
4042
|
+
.mcp-enabled-check { display:inline-flex; align-items:center; gap:7px; color:var(--text); font-size:10px; cursor:pointer; }
|
|
4043
|
+
.mcp-enabled-check input { accent-color:var(--accent); }
|
|
4044
|
+
.mcp-form-actions { display:flex; align-items:center; justify-content:flex-end; gap:8px; margin-top:4px; }
|
|
4045
|
+
.mcp-form-actions .sec-btn { flex:0 0 auto; }
|
|
4046
|
+
.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); }
|
|
4047
|
+
.mcp-server-copy { flex:1; min-width:0; }
|
|
4048
|
+
.mcp-server-title { display:flex; align-items:center; gap:6px; flex-wrap:wrap; color:var(--text-bright); font-size:12px; font-weight:650; }
|
|
4049
|
+
.mcp-server-meta { margin-top:4px; color:var(--text-dim); font:10px/1.45 var(--font-mono); overflow-wrap:anywhere; }
|
|
4050
|
+
.mcp-row-actions { display:flex; align-items:center; gap:5px; flex-wrap:wrap; justify-content:flex-end; }
|
|
4051
|
+
.mcp-row-actions .sec-btn { flex:0 0 auto; }
|
|
4052
|
+
.dsh-hero { padding:14px; border:1px solid var(--glass-border-2); border-radius:var(--radius-md); background:var(--glass-bg-1); }
|
|
4053
|
+
.dsh-hero-head { display:flex; align-items:flex-start; gap:10px; }
|
|
4054
|
+
.dsh-hero-copy { flex:1; min-width:0; }
|
|
4055
|
+
.dsh-title { color:var(--text-bright); font-size:14px; font-weight:700; }
|
|
4056
|
+
.dsh-description { margin-top:5px; color:var(--text-dim); font-size:11px; line-height:1.55; }
|
|
4057
|
+
.dsh-actions { display:flex; flex-wrap:wrap; gap:7px; margin-top:11px; }
|
|
4058
|
+
.dsh-actions .sec-btn { flex:0 0 auto; }
|
|
4059
|
+
.dsh-grid { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:10px; margin-top:10px; }
|
|
4060
|
+
.dsh-card { min-width:0; padding:11px; border:1px solid var(--glass-border-1); border-radius:var(--radius-md); background:var(--glass-bg-1); }
|
|
4061
|
+
.dsh-card-title { color:var(--text-bright); font-size:11px; font-weight:650; }
|
|
4062
|
+
.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; }
|
|
4063
|
+
.dsh-kv dt { color:var(--text-dim); }
|
|
4064
|
+
.dsh-kv dd { color:var(--text); overflow-wrap:anywhere; }
|
|
4065
|
+
.dsh-list { display:flex; flex-direction:column; gap:6px; margin-top:8px; }
|
|
4066
|
+
.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; }
|
|
4067
|
+
.dsh-list-item.warning { border-color:var(--notice-error-border); color:var(--notice-error-text); }
|
|
4068
|
+
.dsh-layer-profile { margin-top:10px; padding-top:9px; border-top:1px solid var(--glass-border-1); }
|
|
4069
|
+
.dsh-candidate-actions { display:flex; align-items:center; gap:7px; margin-top:7px; }
|
|
4070
|
+
.dsh-candidate-actions .sec-btn { flex:0 0 auto; }
|
|
4071
|
+
|
|
4072
|
+
@media (max-width: 560px) {
|
|
4073
|
+
.sub-win { width:calc(100vw - 20px); min-width:0; }
|
|
4074
|
+
.plugin-toolbar { align-items:stretch; flex-wrap:wrap; }
|
|
4075
|
+
.plugin-search { width:100%; order:3; }
|
|
4076
|
+
.mcp-field-grid, .dsh-grid { grid-template-columns:1fr; }
|
|
4077
|
+
.mcp-server-row { align-items:flex-start; flex-direction:column; }
|
|
4078
|
+
.mcp-row-actions { width:100%; justify-content:flex-start; }
|
|
4079
|
+
}
|
|
3737
4080
|
|
|
3738
4081
|
.stab-panel {
|
|
3739
4082
|
display: none;
|
|
@@ -4687,6 +5030,32 @@ html.newmark-memory-overview-viewer body {
|
|
|
4687
5030
|
.auto-input-group select:focus,
|
|
4688
5031
|
.auto-input-group textarea:focus { border-color: var(--accent); }
|
|
4689
5032
|
|
|
5033
|
+
.auto-input-group.checkbox-row {
|
|
5034
|
+
display: flex;
|
|
5035
|
+
padding: 9px 11px;
|
|
5036
|
+
border: 1px solid var(--border);
|
|
5037
|
+
border-radius: var(--radius-md);
|
|
5038
|
+
background: var(--glass-bg-1);
|
|
5039
|
+
}
|
|
5040
|
+
.auto-input-group.checkbox-row label {
|
|
5041
|
+
display: flex;
|
|
5042
|
+
align-items: center;
|
|
5043
|
+
gap: 8px;
|
|
5044
|
+
margin: 0;
|
|
5045
|
+
cursor: pointer;
|
|
5046
|
+
font-size: 12px;
|
|
5047
|
+
color: var(--text);
|
|
5048
|
+
}
|
|
5049
|
+
.auto-input-group.checkbox-row input[type="checkbox"] {
|
|
5050
|
+
width: 15px;
|
|
5051
|
+
height: 15px;
|
|
5052
|
+
flex-shrink: 0;
|
|
5053
|
+
accent-color: var(--accent);
|
|
5054
|
+
cursor: pointer;
|
|
5055
|
+
margin: 0;
|
|
5056
|
+
padding: 0;
|
|
5057
|
+
}
|
|
5058
|
+
|
|
4690
5059
|
.auto-conditions {
|
|
4691
5060
|
display: flex;
|
|
4692
5061
|
gap: 8px;
|
|
@@ -4806,6 +5175,89 @@ html.newmark-memory-overview-viewer body {
|
|
|
4806
5175
|
|
|
4807
5176
|
.hidden { display: none !important; }
|
|
4808
5177
|
.no-select { user-select: none; -webkit-user-select: none; }
|
|
5178
|
+
|
|
5179
|
+
/* ============================================================
|
|
5180
|
+
NEWMARK CONVERSATION HIERARCHY (三级字体体系)
|
|
5181
|
+
最终回复 > Build 内联历史 > 工具调用 toolcall
|
|
5182
|
+
保持原有 DOM 结构不变,仅通过字体大小/行高/不透明度体现差异。
|
|
5183
|
+
============================================================ */
|
|
5184
|
+
|
|
5185
|
+
/* --- Level 1: 最终回复(最大、最醒目) --- */
|
|
5186
|
+
.chat-msg.assistant {
|
|
5187
|
+
font-size: 15px;
|
|
5188
|
+
line-height: 1.72;
|
|
5189
|
+
}
|
|
5190
|
+
|
|
5191
|
+
/* Build 块内的最终回复同样以 Level 1 呈现 */
|
|
5192
|
+
.chat-msg.run-final-response {
|
|
5193
|
+
font-size: 15px;
|
|
5194
|
+
line-height: 1.72;
|
|
5195
|
+
}
|
|
5196
|
+
|
|
5197
|
+
/* 用户消息保持可读的稍大字号 */
|
|
5198
|
+
.chat-msg.user {
|
|
5199
|
+
font-size: 14px;
|
|
5200
|
+
line-height: 1.65;
|
|
5201
|
+
}
|
|
5202
|
+
|
|
5203
|
+
/* --- Level 2: Build 内联历史(中等字号) --- */
|
|
5204
|
+
.conversation-work-event.narrative {
|
|
5205
|
+
font-size: 13px;
|
|
5206
|
+
line-height: 1.6;
|
|
5207
|
+
opacity: 0.9;
|
|
5208
|
+
}
|
|
5209
|
+
|
|
5210
|
+
/* Build 块标题保持中等偏小,作为历史导航 */
|
|
5211
|
+
.conversation-work-run-head {
|
|
5212
|
+
font-size: 12px;
|
|
5213
|
+
opacity: 0.78;
|
|
5214
|
+
}
|
|
5215
|
+
|
|
5216
|
+
/* --- Level 3: 工具调用 toolcall(最小、最淡、等宽) --- */
|
|
5217
|
+
.tool-event-summary {
|
|
5218
|
+
font-size: 11px;
|
|
5219
|
+
font-family: var(--font-mono);
|
|
5220
|
+
opacity: 0.78;
|
|
5221
|
+
}
|
|
5222
|
+
|
|
5223
|
+
.tool-event-content {
|
|
5224
|
+
font-size: 11px;
|
|
5225
|
+
font-family: var(--font-mono);
|
|
5226
|
+
line-height: 1.45;
|
|
5227
|
+
opacity: 0.72;
|
|
5228
|
+
color: var(--text-dim);
|
|
5229
|
+
}
|
|
5230
|
+
|
|
5231
|
+
/* 工具调用外的活动/状态项也归入 Level 3 */
|
|
5232
|
+
.conversation-work-event:not(.narrative):not(.guide):not(.error) {
|
|
5233
|
+
font-size: 11px;
|
|
5234
|
+
line-height: 1.45;
|
|
5235
|
+
opacity: 0.72;
|
|
5236
|
+
font-family: var(--font-mono);
|
|
5237
|
+
}
|
|
5238
|
+
|
|
5239
|
+
.conversation-work-event.activity-summary {
|
|
5240
|
+
font-size: 11px;
|
|
5241
|
+
}
|
|
5242
|
+
|
|
5243
|
+
/* 工具调用活动列表项保持最小字号 */
|
|
5244
|
+
.conversation-work-activity-item {
|
|
5245
|
+
font-size: 10.5px;
|
|
5246
|
+
opacity: 0.68;
|
|
5247
|
+
}
|
|
5248
|
+
|
|
5249
|
+
/* --- 层级间距调整,强化视觉层次 --- */
|
|
5250
|
+
.chat-msg.assistant { margin-top: 2px; }
|
|
5251
|
+
.chat-msg.run-final-response { margin-bottom: 6px; }
|
|
5252
|
+
.conversation-work-run { margin: 4px 0 7px; }
|
|
5253
|
+
|
|
5254
|
+
/* 浅色主题下放宽不透明度,保证可读性 */
|
|
5255
|
+
.light .tool-event-content,
|
|
5256
|
+
.light .tool-event-summary,
|
|
5257
|
+
.light .conversation-work-event:not(.narrative):not(.guide):not(.error) {
|
|
5258
|
+
opacity: 0.8;
|
|
5259
|
+
}
|
|
5260
|
+
|
|
4809
5261
|
</style>
|
|
4810
5262
|
</head>
|
|
4811
5263
|
<body>
|
|
@@ -4923,6 +5375,11 @@ html.newmark-memory-overview-viewer body {
|
|
|
4923
5375
|
<symbol id="folder" viewBox="0 0 24 24">
|
|
4924
5376
|
<path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z" />
|
|
4925
5377
|
</symbol>
|
|
5378
|
+
<symbol id="git-branch" viewBox="0 0 24 24">
|
|
5379
|
+
<path d="M15 6a9 9 0 0 0-9 9V3" />
|
|
5380
|
+
<circle cx="18" cy="6" r="3" />
|
|
5381
|
+
<circle cx="6" cy="18" r="3" />
|
|
5382
|
+
</symbol>
|
|
4926
5383
|
<symbol id="globe" viewBox="0 0 24 24">
|
|
4927
5384
|
<circle cx="12" cy="12" r="10" />
|
|
4928
5385
|
<path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20" />
|
|
@@ -4941,6 +5398,14 @@ html.newmark-memory-overview-viewer body {
|
|
|
4941
5398
|
<circle cx="15" cy="5" r="1" />
|
|
4942
5399
|
<circle cx="15" cy="19" r="1" />
|
|
4943
5400
|
</symbol>
|
|
5401
|
+
<symbol id="group" viewBox="0 0 24 24">
|
|
5402
|
+
<path d="M3 7V5c0-1.1.9-2 2-2h2" />
|
|
5403
|
+
<path d="M17 3h2c1.1 0 2 .9 2 2v2" />
|
|
5404
|
+
<path d="M21 17v2c0 1.1-.9 2-2 2h-2" />
|
|
5405
|
+
<path d="M7 21H5c-1.1 0-2-.9-2-2v-2" />
|
|
5406
|
+
<rect width="7" height="5" x="7" y="7" rx="1" />
|
|
5407
|
+
<rect width="7" height="5" x="10" y="12" rx="1" />
|
|
5408
|
+
</symbol>
|
|
4944
5409
|
<symbol id="image" viewBox="0 0 24 24">
|
|
4945
5410
|
<rect width="18" height="18" x="3" y="3" rx="2" ry="2" />
|
|
4946
5411
|
<circle cx="9" cy="9" r="2" />
|
|
@@ -4968,6 +5433,14 @@ html.newmark-memory-overview-viewer body {
|
|
|
4968
5433
|
<path d="m3 17 2 2 4-4" />
|
|
4969
5434
|
<path d="m3 7 2 2 4-4" />
|
|
4970
5435
|
</symbol>
|
|
5436
|
+
<symbol id="list" viewBox="0 0 24 24">
|
|
5437
|
+
<path d="M3 5h.01" />
|
|
5438
|
+
<path d="M3 12h.01" />
|
|
5439
|
+
<path d="M3 19h.01" />
|
|
5440
|
+
<path d="M8 5h13" />
|
|
5441
|
+
<path d="M8 12h13" />
|
|
5442
|
+
<path d="M8 19h13" />
|
|
5443
|
+
</symbol>
|
|
4971
5444
|
<symbol id="loader-circle" viewBox="0 0 24 24">
|
|
4972
5445
|
<path d="M21 12a9 9 0 1 1-6.219-8.56" />
|
|
4973
5446
|
</symbol>
|
|
@@ -5008,6 +5481,9 @@ html.newmark-memory-overview-viewer body {
|
|
|
5008
5481
|
<path d="m5 9-3 3 3 3" />
|
|
5009
5482
|
<path d="m9 5 3-3 3 3" />
|
|
5010
5483
|
</symbol>
|
|
5484
|
+
<symbol id="navigation" viewBox="0 0 24 24">
|
|
5485
|
+
<polygon points="3 11 22 2 13 21 11 13 3 11" />
|
|
5486
|
+
</symbol>
|
|
5011
5487
|
<symbol id="octagon-x" viewBox="0 0 24 24">
|
|
5012
5488
|
<path d="m15 9-6 6" />
|
|
5013
5489
|
<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 +5496,13 @@ html.newmark-memory-overview-viewer body {
|
|
|
5020
5496
|
<path d="M3 3h6l6 18h6" />
|
|
5021
5497
|
<path d="M14 3h7" />
|
|
5022
5498
|
</symbol>
|
|
5499
|
+
<symbol id="palette" viewBox="0 0 24 24">
|
|
5500
|
+
<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" />
|
|
5501
|
+
<circle cx="13.5" cy="6.5" r=".5" fill="currentColor" />
|
|
5502
|
+
<circle cx="17.5" cy="10.5" r=".5" fill="currentColor" />
|
|
5503
|
+
<circle cx="6.5" cy="12.5" r=".5" fill="currentColor" />
|
|
5504
|
+
<circle cx="8.5" cy="7.5" r=".5" fill="currentColor" />
|
|
5505
|
+
</symbol>
|
|
5023
5506
|
<symbol id="panel-left-open" viewBox="0 0 24 24">
|
|
5024
5507
|
<rect width="18" height="18" x="3" y="3" rx="2" />
|
|
5025
5508
|
<path d="M9 3v18" />
|
|
@@ -5231,37 +5714,37 @@ html.newmark-memory-overview-viewer body {
|
|
|
5231
5714
|
<!-- Left Sidebar -->
|
|
5232
5715
|
<div id="left">
|
|
5233
5716
|
<div id="left-thumb">
|
|
5234
|
-
<
|
|
5235
|
-
<
|
|
5236
|
-
<
|
|
5237
|
-
<
|
|
5238
|
-
<
|
|
5239
|
-
<
|
|
5240
|
-
<
|
|
5717
|
+
<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>
|
|
5718
|
+
<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>
|
|
5719
|
+
<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>
|
|
5720
|
+
<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>
|
|
5721
|
+
<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>
|
|
5722
|
+
<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>
|
|
5723
|
+
<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
5724
|
</div>
|
|
5242
5725
|
<div id="left-content">
|
|
5243
5726
|
<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
|
-
<
|
|
5727
|
+
<button type="button" class="left-nav-icon" onclick="window.showNewConversationPage()" title="New conversation">
|
|
5245
5728
|
<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
|
-
<
|
|
5729
|
+
</button>
|
|
5730
|
+
<button type="button" class="left-nav-icon" onclick="window.showPluginList()">
|
|
5248
5731
|
<span class="icon"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#plug"></use></svg></span><span>Plugins</span>
|
|
5249
|
-
</
|
|
5250
|
-
<
|
|
5732
|
+
</button>
|
|
5733
|
+
<button type="button" class="left-nav-icon" onclick="window.showMemoryLab()">
|
|
5251
5734
|
<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
|
-
<
|
|
5735
|
+
</button>
|
|
5736
|
+
<button type="button" class="left-nav-icon" onclick="window.showAutomationWindow()">
|
|
5254
5737
|
<span class="icon"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#calendar"></use></svg></span><span>Automation</span>
|
|
5255
|
-
</
|
|
5256
|
-
<
|
|
5738
|
+
</button>
|
|
5739
|
+
<button type="button" class="left-nav-icon" onclick="window.showFlowEditor()">
|
|
5257
5740
|
<span class="icon"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#workflow"></use></svg></span><span>Flow</span>
|
|
5258
|
-
</
|
|
5259
|
-
<
|
|
5741
|
+
</button>
|
|
5742
|
+
<button type="button" class="left-nav-icon" onclick="window.openSettings()">
|
|
5260
5743
|
<span class="icon"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#settings"></use></svg></span><span>Settings</span>
|
|
5261
|
-
</
|
|
5744
|
+
</button>
|
|
5262
5745
|
<div id="left-ws-section">
|
|
5263
5746
|
<div id="left-ws-header">Workspaces</div>
|
|
5264
|
-
<div id="left-ws-list"></div>
|
|
5747
|
+
<div id="left-ws-list" role="list" aria-label="Workspaces"></div>
|
|
5265
5748
|
<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
5749
|
</div>
|
|
5267
5750
|
</div>
|
|
@@ -5275,11 +5758,11 @@ html.newmark-memory-overview-viewer body {
|
|
|
5275
5758
|
<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
5759
|
<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
5760
|
</div>
|
|
5278
|
-
|
|
5761
|
+
<div id="conversation-list" role="list" aria-label="Conversations"></div>
|
|
5279
5762
|
</div>
|
|
5280
5763
|
|
|
5281
5764
|
<!-- 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>
|
|
5765
|
+
<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
5766
|
|
|
5284
5767
|
<!-- Center Stack (chat + terminal) -->
|
|
5285
5768
|
<div id="center-stack">
|
|
@@ -5305,7 +5788,7 @@ html.newmark-memory-overview-viewer body {
|
|
|
5305
5788
|
<div id="todo-header" class="stack-row" onclick="window.toggleTodoCollapse()">
|
|
5306
5789
|
<span id="todo-header-label" class="stack-title">Task</span>
|
|
5307
5790
|
<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>
|
|
5791
|
+
<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
5792
|
</span>
|
|
5310
5793
|
</div>
|
|
5311
5794
|
<div id="todo-list"></div>
|
|
@@ -5317,7 +5800,7 @@ html.newmark-memory-overview-viewer body {
|
|
|
5317
5800
|
<span id="queue-header-label" class="stack-title">Next</span>
|
|
5318
5801
|
<span class="stack-actions">
|
|
5319
5802
|
<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>
|
|
5803
|
+
<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
5804
|
</span>
|
|
5322
5805
|
</div>
|
|
5323
5806
|
<div id="queue-list"></div>
|
|
@@ -5361,8 +5844,9 @@ html.newmark-memory-overview-viewer body {
|
|
|
5361
5844
|
<div class="model-select-menu" id="model-select-menu" role="listbox" aria-label="Model" popover="manual"></div>
|
|
5362
5845
|
</div>
|
|
5363
5846
|
<div class="context-token-wrap">
|
|
5364
|
-
<
|
|
5847
|
+
<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
5848
|
<div id="context-token-tooltip"></div>
|
|
5849
|
+
<div id="context-inspector" role="dialog" aria-label="Context management" aria-live="polite"></div>
|
|
5366
5850
|
</div>
|
|
5367
5851
|
<select class="tool-select" id="intel-select">
|
|
5368
5852
|
<option value="low">low</option>
|
|
@@ -5376,7 +5860,7 @@ html.newmark-memory-overview-viewer body {
|
|
|
5376
5860
|
<button class="mode-toggle-btn active" data-mode="guide" onclick="window.setInputMode('guide')">Guide</button>
|
|
5377
5861
|
<button class="mode-toggle-btn" data-mode="next" onclick="window.setInputMode('next')">Next</button>
|
|
5378
5862
|
</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>
|
|
5863
|
+
<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
5864
|
</div>
|
|
5381
5865
|
</div>
|
|
5382
5866
|
</div>
|
|
@@ -5384,7 +5868,7 @@ html.newmark-memory-overview-viewer body {
|
|
|
5384
5868
|
<!-- Bottom Terminal -->
|
|
5385
5869
|
<div id="bottom" class="open">
|
|
5386
5870
|
<div id="bottom-header">
|
|
5387
|
-
<div id="terminal-tabs"></div>
|
|
5871
|
+
<div id="terminal-tabs" role="tablist" aria-label="Terminals"></div>
|
|
5388
5872
|
<select id="terminal-shell-select" onchange="window.spawnTerminal(this.value)">
|
|
5389
5873
|
<option value="powershell" data-platform-shell="win32">PowerShell</option>
|
|
5390
5874
|
<option value="cmd" data-platform-shell="win32">CMD</option>
|
|
@@ -5402,7 +5886,7 @@ html.newmark-memory-overview-viewer body {
|
|
|
5402
5886
|
<div class="terminal-output"><span style="color:var(--text-dim);opacity:0.5;">Terminal ready</span></div>
|
|
5403
5887
|
<div class="terminal-input-row">
|
|
5404
5888
|
<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()">
|
|
5889
|
+
<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
5890
|
</div>
|
|
5407
5891
|
</div>
|
|
5408
5892
|
</div>
|
|
@@ -5410,25 +5894,25 @@ html.newmark-memory-overview-viewer body {
|
|
|
5410
5894
|
</div>
|
|
5411
5895
|
|
|
5412
5896
|
<!-- Right Resize Handle -->
|
|
5413
|
-
<div class="resize-handle" data-side="left" data-target="right" title="Resize right sidebar"></div>
|
|
5897
|
+
<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
5898
|
|
|
5415
5899
|
<!-- Right Sidebar -->
|
|
5416
5900
|
<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>
|
|
5901
|
+
<div id="right-tabs" role="tablist" aria-label="Right sidebar">
|
|
5902
|
+
<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>
|
|
5903
|
+
<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>
|
|
5904
|
+
<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>
|
|
5905
|
+
<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>
|
|
5906
|
+
<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
5907
|
<div class="tab-divider"></div>
|
|
5424
5908
|
<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
5909
|
</div>
|
|
5426
5910
|
<div id="right-content">
|
|
5427
|
-
<div class="tab-panel active" id="panel-file-tree">
|
|
5911
|
+
<div class="tab-panel active" id="panel-file-tree" role="tabpanel" aria-labelledby="right-tab-file-tree">
|
|
5428
5912
|
<div style="font-size:11px;color:var(--text-dim);margin-bottom:8px;">Workspace file tree</div>
|
|
5429
|
-
<div id="file-tree-container"></div>
|
|
5913
|
+
<div id="file-tree-container" role="tree"></div>
|
|
5430
5914
|
</div>
|
|
5431
|
-
<div class="tab-panel" id="panel-editor">
|
|
5915
|
+
<div class="tab-panel" id="panel-editor" role="tabpanel" aria-labelledby="right-tab-editor" hidden>
|
|
5432
5916
|
<div class="editor-toolbar">
|
|
5433
5917
|
<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
5918
|
<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 +5928,22 @@ html.newmark-memory-overview-viewer body {
|
|
|
5444
5928
|
<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
5929
|
</div>
|
|
5446
5930
|
</div>
|
|
5447
|
-
<div class="tab-panel" id="panel-plan">
|
|
5931
|
+
<div class="tab-panel" id="panel-plan" role="tabpanel" aria-labelledby="right-tab-plan" hidden>
|
|
5448
5932
|
<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
5933
|
<div id="conversation-plan-content"></div>
|
|
5450
5934
|
<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
5935
|
<div id="linked-plan-content" class="linked-plan-reader md-rendered" aria-live="polite"></div>
|
|
5452
5936
|
</div>
|
|
5453
|
-
<div class="tab-panel" id="panel-subagent">
|
|
5937
|
+
<div class="tab-panel" id="panel-subagent" role="tabpanel" aria-labelledby="right-tab-subagent" hidden>
|
|
5454
5938
|
<div style="font-size:11px;color:var(--text-dim);margin-bottom:8px;">Subagents</div>
|
|
5455
5939
|
<div id="subagent-list"></div>
|
|
5456
5940
|
</div>
|
|
5457
|
-
<div class="tab-panel" id="panel-browser">
|
|
5941
|
+
<div class="tab-panel" id="panel-browser" role="tabpanel" aria-labelledby="right-tab-browser" hidden>
|
|
5458
5942
|
<div class="browser-url-bar">
|
|
5459
5943
|
<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
5944
|
<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
5945
|
<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)">
|
|
5946
|
+
<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
5947
|
<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
5948
|
<button class="shell-btn" id="computer-use-toggle" onclick="window.toggleComputerUse()" title="ComputerUse: enabled for this conversation" aria-pressed="true">CU</button>
|
|
5465
5949
|
</div>
|
|
@@ -5476,7 +5960,7 @@ html.newmark-memory-overview-viewer body {
|
|
|
5476
5960
|
|
|
5477
5961
|
<!-- ========== SUB-WINDOW OVERLAY ========== -->
|
|
5478
5962
|
<div class="sub-win-overlay" id="sub-win-overlay" onclick="if(event.target===this)window.closeSubWin()">
|
|
5479
|
-
<div class="sub-win" id="sub-win">
|
|
5963
|
+
<div class="sub-win" id="sub-win" role="dialog" aria-modal="true" aria-labelledby="sub-win-title" tabindex="-1">
|
|
5480
5964
|
<div class="sub-win-header" id="sub-win-header">
|
|
5481
5965
|
<span class="sub-win-title" id="sub-win-title">Window</span>
|
|
5482
5966
|
<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 +5968,21 @@ html.newmark-memory-overview-viewer body {
|
|
|
5484
5968
|
<div class="sub-win-body" id="sub-win-body"></div>
|
|
5485
5969
|
</div>
|
|
5486
5970
|
</div>
|
|
5971
|
+
<div class="command-surface-overlay" id="command-surface-overlay" onclick="if(event.target===this)window.closeCommandSurface()">
|
|
5972
|
+
<section class="command-surface" id="command-surface" role="dialog" aria-modal="true" aria-labelledby="command-surface-title" tabindex="-1">
|
|
5973
|
+
<header class="command-surface-header">
|
|
5974
|
+
<div class="command-surface-heading">
|
|
5975
|
+
<div class="command-surface-title" id="command-surface-title"></div>
|
|
5976
|
+
<div class="command-surface-subtitle" id="command-surface-subtitle"></div>
|
|
5977
|
+
</div>
|
|
5978
|
+
<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>
|
|
5979
|
+
</header>
|
|
5980
|
+
<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>
|
|
5981
|
+
<div class="command-list" id="command-list" role="listbox"></div>
|
|
5982
|
+
<footer class="command-surface-footer" id="command-surface-footer"></footer>
|
|
5983
|
+
</section>
|
|
5984
|
+
</div>
|
|
5985
|
+
<div class="shortcut-chord-hint" id="shortcut-chord-hint" role="status" aria-live="polite"></div>
|
|
5487
5986
|
<script>
|
|
5488
5987
|
/* ============================================================
|
|
5489
5988
|
NEWMARK AGENT - Complete UI Controller v2.0
|
|
@@ -5579,6 +6078,8 @@ var state = {
|
|
|
5579
6078
|
automationItems: [],
|
|
5580
6079
|
contextCompression: null,
|
|
5581
6080
|
contextWindow: null,
|
|
6081
|
+
contextInspectorOpen: false,
|
|
6082
|
+
contextMutationPending: false,
|
|
5582
6083
|
flowWorks: [],
|
|
5583
6084
|
activeAgentRunning: false,
|
|
5584
6085
|
editorPath: '',
|
|
@@ -5596,6 +6097,9 @@ var state = {
|
|
|
5596
6097
|
editorCompletionText: '',
|
|
5597
6098
|
editorCompletionRequest: 0,
|
|
5598
6099
|
editorCompletionAnchor: null,
|
|
6100
|
+
editorCompletionCache: [],
|
|
6101
|
+
editorCompletionInFlight: false,
|
|
6102
|
+
editorCompletionStreamText: '',
|
|
5599
6103
|
editorCaretSignature: '',
|
|
5600
6104
|
editorPredictionEnabled: true,
|
|
5601
6105
|
editorCompletionTimer: null,
|
|
@@ -5651,7 +6155,14 @@ var state = {
|
|
|
5651
6155
|
githubOverviewPendingRepo: '',
|
|
5652
6156
|
mcpServers: [],
|
|
5653
6157
|
mcpDiscovered: [],
|
|
6158
|
+
dshCompatibility: null,
|
|
5654
6159
|
mcpEditingId: '',
|
|
6160
|
+
mcpDraft: null,
|
|
6161
|
+
mcpSearchQuery: '',
|
|
6162
|
+
mcpMutationPending: false,
|
|
6163
|
+
mcpMutationGeneration: 0,
|
|
6164
|
+
mcpFormFocusRequested: false,
|
|
6165
|
+
pluginPanelGeneration: 0,
|
|
5655
6166
|
skillMarketQuery: '',
|
|
5656
6167
|
memoryLab: null,
|
|
5657
6168
|
memoryLabComponentContents: {},
|
|
@@ -5720,6 +6231,48 @@ var NEWMARK_I18N = {
|
|
|
5720
6231
|
en: {
|
|
5721
6232
|
'app.ready': 'Ready',
|
|
5722
6233
|
'app.subtitle': 'Enter an instruction to begin. Enter sends. Shift+Enter inserts a newline.',
|
|
6234
|
+
'shortcuts.paletteTitle': 'Command palette',
|
|
6235
|
+
'shortcuts.helpTitle': 'Keyboard shortcuts',
|
|
6236
|
+
'shortcuts.paletteSubtitle': 'Search every registered Newmark GUI command. Shortcuts never replace standard editing keys.',
|
|
6237
|
+
'shortcuts.helpSubtitle': 'Common desktop keys plus conflict-safe Newmark command chords.',
|
|
6238
|
+
'shortcuts.searchCommands': 'Search commands...',
|
|
6239
|
+
'shortcuts.searchShortcuts': 'Search commands or shortcuts...',
|
|
6240
|
+
'shortcuts.noResults': 'No matching commands.',
|
|
6241
|
+
'shortcuts.footer': 'Up/Down navigate · Enter runs · Esc closes · Tab stays inside this dialog',
|
|
6242
|
+
'shortcuts.category.general': 'General',
|
|
6243
|
+
'shortcuts.category.navigation': 'Navigation',
|
|
6244
|
+
'shortcuts.category.workspace': 'Workspace and chat',
|
|
6245
|
+
'shortcuts.category.layout': 'Layout and focus',
|
|
6246
|
+
'shortcuts.category.input': 'Input and modes',
|
|
6247
|
+
'shortcuts.category.editor': 'Editor',
|
|
6248
|
+
'shortcuts.category.browser': 'Browser',
|
|
6249
|
+
'shortcuts.category.terminal': 'Terminal',
|
|
6250
|
+
'shortcuts.category.context': 'Context controls',
|
|
6251
|
+
'shortcuts.context.global': 'Application',
|
|
6252
|
+
'shortcuts.context.prompt': 'Prompt',
|
|
6253
|
+
'shortcuts.context.editor': 'Editor only',
|
|
6254
|
+
'shortcuts.context.browser': 'Browser only',
|
|
6255
|
+
'shortcuts.context.terminal': 'Terminal only',
|
|
6256
|
+
'shortcuts.context.dialog': 'Dialog',
|
|
6257
|
+
'shortcuts.openPalette': 'Open command palette',
|
|
6258
|
+
'shortcuts.openHelp': 'Show keyboard shortcuts',
|
|
6259
|
+
'shortcuts.focusPrimary': 'Focus primary input',
|
|
6260
|
+
'shortcuts.focusNext': 'Focus next application region',
|
|
6261
|
+
'shortcuts.focusPrevious': 'Focus previous application region',
|
|
6262
|
+
'shortcuts.toggleLeft': 'Toggle left sidebar',
|
|
6263
|
+
'shortcuts.toggleWorkspacePanel': 'Toggle workspace and conversation panel',
|
|
6264
|
+
'shortcuts.toggleRight': 'Toggle right sidebar',
|
|
6265
|
+
'shortcuts.toggleTerminal': 'Toggle terminal',
|
|
6266
|
+
'shortcuts.nextConversation': 'Next conversation',
|
|
6267
|
+
'shortcuts.previousConversation': 'Previous conversation',
|
|
6268
|
+
'shortcuts.nextBranch': 'Next branch',
|
|
6269
|
+
'shortcuts.previousBranch': 'Previous branch',
|
|
6270
|
+
'shortcuts.scrollBottom': 'Scroll chat to bottom',
|
|
6271
|
+
'shortcuts.newTerminal': 'New terminal',
|
|
6272
|
+
'shortcuts.focusTerminal': 'Focus terminal input',
|
|
6273
|
+
'shortcuts.focusBrowserAddress': 'Focus browser address',
|
|
6274
|
+
'shortcuts.toggleTheme': 'Toggle light and dark theme',
|
|
6275
|
+
'shortcuts.chordHint': '{prefix} waiting for: {keys}',
|
|
5723
6276
|
'top.minimize': 'Minimize',
|
|
5724
6277
|
'top.maximize': 'Maximize',
|
|
5725
6278
|
'top.close': 'Close',
|
|
@@ -5731,12 +6284,14 @@ var NEWMARK_I18N = {
|
|
|
5731
6284
|
'left.flow': 'Flow',
|
|
5732
6285
|
'left.settings': 'Settings',
|
|
5733
6286
|
'left.workspaces': 'Workspaces',
|
|
6287
|
+
'left.conversations': 'Conversations',
|
|
5734
6288
|
'left.new': 'New',
|
|
5735
6289
|
'left.collapse': 'Collapse left sidebar',
|
|
5736
6290
|
'left.collapseSecondary': 'Collapse workspace panel',
|
|
5737
6291
|
'input.placeholder': 'Input instruction...',
|
|
5738
6292
|
'input.send': 'Send',
|
|
5739
6293
|
'input.stop': 'Stop',
|
|
6294
|
+
'input.continue': 'Continue',
|
|
5740
6295
|
'input.guide': 'Guide',
|
|
5741
6296
|
'input.next': 'Next',
|
|
5742
6297
|
'mode.build': 'Build',
|
|
@@ -5986,6 +6541,7 @@ var NEWMARK_I18N = {
|
|
|
5986
6541
|
'model.yes': 'yes',
|
|
5987
6542
|
'model.notChecked': 'not checked',
|
|
5988
6543
|
'archive.current': 'Archive current chat',
|
|
6544
|
+
'archive.archiving': 'Archiving...',
|
|
5989
6545
|
'archive.empty': 'No archives yet.',
|
|
5990
6546
|
'archive.loading': 'Loading workspace archives...',
|
|
5991
6547
|
'archive.unavailable': 'Archive list unavailable',
|
|
@@ -6066,7 +6622,13 @@ var NEWMARK_I18N = {
|
|
|
6066
6622
|
'flow.noAvailable': 'No workflows are available to run.',
|
|
6067
6623
|
'flow.started': 'Flow started',
|
|
6068
6624
|
'plugins.title': 'Plugins',
|
|
6625
|
+
'plugins.tabMcp': 'MCP',
|
|
6626
|
+
'plugins.tabDsh': 'DSH Plugin',
|
|
6627
|
+
'plugins.tabSkills': 'Skills',
|
|
6628
|
+
'plugins.tabMarket': 'Market',
|
|
6629
|
+
'plugins.tabGithub': 'GitHub',
|
|
6069
6630
|
'plugins.mcp': 'MCP Management',
|
|
6631
|
+
'plugins.dsh': 'DSH Plugin',
|
|
6070
6632
|
'plugins.management': 'Skills Management',
|
|
6071
6633
|
'plugins.market': 'Skills Market',
|
|
6072
6634
|
'plugins.github': 'GitHub CLI',
|
|
@@ -6124,6 +6686,74 @@ var NEWMARK_I18N = {
|
|
|
6124
6686
|
'plugins.mcpNoServers': 'No user MCP servers.',
|
|
6125
6687
|
'plugins.mcpDiscovered': 'Discovered from plugins',
|
|
6126
6688
|
'plugins.mcpStored': 'User MCP servers',
|
|
6689
|
+
'plugins.mcpConfiguredCount': '{count} configured',
|
|
6690
|
+
'plugins.mcpSearch': 'Search MCP servers...',
|
|
6691
|
+
'plugins.mcpNoMatch': 'No MCP servers match this search.',
|
|
6692
|
+
'plugins.mcpRefresh': 'Refresh',
|
|
6693
|
+
'plugins.mcpRefreshing': 'Refreshing MCP servers...',
|
|
6694
|
+
'plugins.mcpLoadError': 'MCP servers could not be loaded.',
|
|
6695
|
+
'plugins.mcpUnavailable': 'MCP management is unavailable in this interface.',
|
|
6696
|
+
'plugins.mcpAddTitle': 'Add MCP server',
|
|
6697
|
+
'plugins.mcpEditTitle': 'Edit MCP server',
|
|
6698
|
+
'plugins.mcpReviewTitle': 'Review MCP candidate',
|
|
6699
|
+
'plugins.mcpFormHelp': 'Review every field before saving. Imported candidates always start disabled.',
|
|
6700
|
+
'plugins.mcpEnabled': 'Enable this server after saving',
|
|
6701
|
+
'plugins.mcpEndpointStdio': 'Command',
|
|
6702
|
+
'plugins.mcpEndpointHttp': 'Server URL',
|
|
6703
|
+
'plugins.mcpCwd': 'Working directory (optional)',
|
|
6704
|
+
'plugins.mcpSecretsHelp': 'When editing, leave blank to preserve saved values; enter {} to clear them. Secret values are never displayed.',
|
|
6705
|
+
'plugins.mcpSavedEnvKeys': 'Saved environment keys: {keys}',
|
|
6706
|
+
'plugins.mcpSavedHeaderKeys': 'Saved header keys: {keys}',
|
|
6707
|
+
'plugins.mcpNoSavedKeys': 'No saved keys.',
|
|
6708
|
+
'plugins.mcpInvalidArgs': 'Arguments must be a JSON array.',
|
|
6709
|
+
'plugins.mcpInvalidObject': '{field} must be a JSON object.',
|
|
6710
|
+
'plugins.mcpRequiredName': 'Enter a server name.',
|
|
6711
|
+
'plugins.mcpRequiredCommand': 'Enter a command for this stdio server.',
|
|
6712
|
+
'plugins.mcpRequiredUrl': 'Enter an http(s) URL for this server.',
|
|
6713
|
+
'plugins.mcpSaving': 'Saving...',
|
|
6714
|
+
'plugins.mcpSaved': 'MCP server saved.',
|
|
6715
|
+
'plugins.mcpEnabledStatus': 'Enabled',
|
|
6716
|
+
'plugins.mcpDisabledStatus': 'Disabled',
|
|
6717
|
+
'plugins.mcpMutationFailed': 'MCP operation failed.',
|
|
6718
|
+
'plugins.mcpRemoveConfirm': 'Remove MCP server "{name}"?',
|
|
6719
|
+
'plugins.mcpReadonly': 'Read-only metadata',
|
|
6720
|
+
'plugins.mcpDiscoveredEmpty': 'No MCP metadata was discovered from installed plugins.',
|
|
6721
|
+
'plugins.mcpStoredEmpty': 'No user MCP servers yet. Add one or review a compatible DSH candidate.',
|
|
6722
|
+
'plugins.mcpReviewImport': 'Review and import',
|
|
6723
|
+
'plugins.mcpCandidateHelp': 'This only pre-fills the MCP form. Nothing is installed, executed, or enabled automatically.',
|
|
6724
|
+
'plugins.retry': 'Retry',
|
|
6725
|
+
'plugins.dshTitle': 'DSH Plugin compatibility',
|
|
6726
|
+
'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.',
|
|
6727
|
+
'plugins.dshPreview': 'Developer preview',
|
|
6728
|
+
'plugins.dshRescan': 'Rescan',
|
|
6729
|
+
'plugins.dshScanning': 'Scanning DSH compatibility...',
|
|
6730
|
+
'plugins.dshLoadError': 'DSH compatibility information could not be loaded.',
|
|
6731
|
+
'plugins.dshUnavailable': 'DSH discovery is unavailable in this interface.',
|
|
6732
|
+
'plugins.dshCli': 'CLI and package',
|
|
6733
|
+
'plugins.dshCliPath': 'CLI path',
|
|
6734
|
+
'plugins.dshCliVersion': 'CLI version',
|
|
6735
|
+
'plugins.dshPackageVersion': 'Package version',
|
|
6736
|
+
'plugins.dshHome': 'DSH_HOME',
|
|
6737
|
+
'plugins.dshHomeSource': 'Home source',
|
|
6738
|
+
'plugins.dshConfigFiles': 'Configuration files',
|
|
6739
|
+
'plugins.dshLayers': 'Configuration layer order',
|
|
6740
|
+
'plugins.dshLayerOrder': 'Later layers override earlier rows; unknown keys remain visible and untouched.',
|
|
6741
|
+
'plugins.dshHomePatches': 'Home-level patches',
|
|
6742
|
+
'plugins.dshUpdateability': 'Updateability: use official DSH tooling or edit the shown patch files; Newmark never rewrites them.',
|
|
6743
|
+
'plugins.dshUpdateChannel': 'Update channel',
|
|
6744
|
+
'plugins.dshLatestChannel': 'latest (not locked)',
|
|
6745
|
+
'plugins.dshProfiles': 'Profiles',
|
|
6746
|
+
'plugins.dshBundles': 'Bundles',
|
|
6747
|
+
'plugins.dshWarnings': 'Warnings',
|
|
6748
|
+
'plugins.dshUnknownKeys': 'Unknown keys',
|
|
6749
|
+
'plugins.dshMcpCandidates': 'MCP candidates',
|
|
6750
|
+
'plugins.dshNone': 'None discovered',
|
|
6751
|
+
'plugins.dshNotAvailable': 'Not available',
|
|
6752
|
+
'plugins.dshOfficialRepo': 'Official repository',
|
|
6753
|
+
'plugins.dshOfficialDocs': 'Documentation',
|
|
6754
|
+
'plugins.dshOfficialNpm': 'npm package',
|
|
6755
|
+
'plugins.dshReadonly': 'Read-only compatibility policy',
|
|
6756
|
+
'plugins.dshReadonlyDetail': 'Newmark only reads local compatibility metadata. Use official DSH tooling to install, execute, update, or change DSH configuration.',
|
|
6127
6757
|
'workspace.new': 'New workspace',
|
|
6128
6758
|
'workspace.type': 'Type',
|
|
6129
6759
|
'workspace.internal': 'Internal workspace',
|
|
@@ -6223,6 +6853,21 @@ var NEWMARK_I18N = {
|
|
|
6223
6853
|
'status.contextModeModel': 'model',
|
|
6224
6854
|
'status.messages': 'messages',
|
|
6225
6855
|
'status.noCompression': 'No compression event in this conversation',
|
|
6856
|
+
'status.contextInspector': 'Context management',
|
|
6857
|
+
'status.contextInspectorHint': 'DSH-inspired live budget; visible chat history stays unchanged.',
|
|
6858
|
+
'status.activeBuild': 'Active Build',
|
|
6859
|
+
'status.longHistory': 'Long history',
|
|
6860
|
+
'status.trigger': 'Trigger',
|
|
6861
|
+
'status.retention': 'Retention',
|
|
6862
|
+
'status.hotCache': 'Hot cache',
|
|
6863
|
+
'status.coldArchive': 'Cold archive',
|
|
6864
|
+
'status.lastCompression': 'Last compression',
|
|
6865
|
+
'status.noCompressionShort': 'No compression yet',
|
|
6866
|
+
'status.compressNow': 'Compress now',
|
|
6867
|
+
'status.compressing': 'Compressing...',
|
|
6868
|
+
'status.compressedNow': 'Context compressed.',
|
|
6869
|
+
'status.compressionFailed': 'Context compression failed.',
|
|
6870
|
+
'status.compressionBusy': 'Compression is unavailable while this conversation is running.',
|
|
6226
6871
|
'status.recentFiles': 'Recent file changes',
|
|
6227
6872
|
'status.noFileChanges': 'No file changes recorded for the latest run.',
|
|
6228
6873
|
'status.pendingOptions': 'Pending options',
|
|
@@ -6243,6 +6888,8 @@ var NEWMARK_I18N = {
|
|
|
6243
6888
|
'conversation.reorderFailed': 'Could not save the conversation order.',
|
|
6244
6889
|
'conversation.pin': 'Pin conversation',
|
|
6245
6890
|
'conversation.unpin': 'Unpin conversation',
|
|
6891
|
+
'conversation.branchCommunication': 'Allow branch communication',
|
|
6892
|
+
'conversation.branchCommunicationBadge': 'Branch communication',
|
|
6246
6893
|
'conversation.loadingIsolated': 'Loading isolated conversation...',
|
|
6247
6894
|
'conversation.locked': 'Current conversation is locked while the agent is working.',
|
|
6248
6895
|
'queue.next': 'Next',
|
|
@@ -6286,6 +6933,48 @@ var NEWMARK_I18N = {
|
|
|
6286
6933
|
zh: {
|
|
6287
6934
|
'app.ready': '就绪',
|
|
6288
6935
|
'app.subtitle': '输入指令开始。Enter 发送,Shift+Enter 换行。',
|
|
6936
|
+
'shortcuts.paletteTitle': '命令面板',
|
|
6937
|
+
'shortcuts.helpTitle': '键盘快捷键',
|
|
6938
|
+
'shortcuts.paletteSubtitle': '搜索并执行所有已注册的 Newmark GUI 命令;不会覆盖标准文本编辑按键。',
|
|
6939
|
+
'shortcuts.helpSubtitle': '通用桌面快捷键与避免冲突的 Newmark 命令序列。',
|
|
6940
|
+
'shortcuts.searchCommands': '搜索命令...',
|
|
6941
|
+
'shortcuts.searchShortcuts': '搜索命令或快捷键...',
|
|
6942
|
+
'shortcuts.noResults': '没有匹配的命令。',
|
|
6943
|
+
'shortcuts.footer': '上/下选择 · Enter 执行 · Esc 关闭 · Tab 保持在对话框内',
|
|
6944
|
+
'shortcuts.category.general': '通用',
|
|
6945
|
+
'shortcuts.category.navigation': '导航',
|
|
6946
|
+
'shortcuts.category.workspace': '工作区与对话',
|
|
6947
|
+
'shortcuts.category.layout': '布局与焦点',
|
|
6948
|
+
'shortcuts.category.input': '输入与模式',
|
|
6949
|
+
'shortcuts.category.editor': '编辑器',
|
|
6950
|
+
'shortcuts.category.browser': '浏览器',
|
|
6951
|
+
'shortcuts.category.terminal': '终端',
|
|
6952
|
+
'shortcuts.category.context': '上下文操作',
|
|
6953
|
+
'shortcuts.context.global': '应用',
|
|
6954
|
+
'shortcuts.context.prompt': '输入框',
|
|
6955
|
+
'shortcuts.context.editor': '仅编辑器',
|
|
6956
|
+
'shortcuts.context.browser': '仅浏览器',
|
|
6957
|
+
'shortcuts.context.terminal': '仅终端',
|
|
6958
|
+
'shortcuts.context.dialog': '对话框',
|
|
6959
|
+
'shortcuts.openPalette': '打开命令面板',
|
|
6960
|
+
'shortcuts.openHelp': '显示键盘快捷键',
|
|
6961
|
+
'shortcuts.focusPrimary': '聚焦主要输入框',
|
|
6962
|
+
'shortcuts.focusNext': '聚焦下一个应用区域',
|
|
6963
|
+
'shortcuts.focusPrevious': '聚焦上一个应用区域',
|
|
6964
|
+
'shortcuts.toggleLeft': '切换左侧边栏',
|
|
6965
|
+
'shortcuts.toggleWorkspacePanel': '切换工作区与对话面板',
|
|
6966
|
+
'shortcuts.toggleRight': '切换右侧边栏',
|
|
6967
|
+
'shortcuts.toggleTerminal': '切换终端',
|
|
6968
|
+
'shortcuts.nextConversation': '下一个对话',
|
|
6969
|
+
'shortcuts.previousConversation': '上一个对话',
|
|
6970
|
+
'shortcuts.nextBranch': '下一个分支',
|
|
6971
|
+
'shortcuts.previousBranch': '上一个分支',
|
|
6972
|
+
'shortcuts.scrollBottom': '滚动到对话底部',
|
|
6973
|
+
'shortcuts.newTerminal': '新建终端',
|
|
6974
|
+
'shortcuts.focusTerminal': '聚焦终端输入框',
|
|
6975
|
+
'shortcuts.focusBrowserAddress': '聚焦浏览器地址栏',
|
|
6976
|
+
'shortcuts.toggleTheme': '切换明暗主题',
|
|
6977
|
+
'shortcuts.chordHint': '{prefix} 等待:{keys}',
|
|
6289
6978
|
'top.minimize': '最小化',
|
|
6290
6979
|
'top.maximize': '最大化',
|
|
6291
6980
|
'top.close': '关闭',
|
|
@@ -6297,12 +6986,14 @@ var NEWMARK_I18N = {
|
|
|
6297
6986
|
'left.flow': '工作流',
|
|
6298
6987
|
'left.settings': '设置',
|
|
6299
6988
|
'left.workspaces': '工作区',
|
|
6989
|
+
'left.conversations': '对话',
|
|
6300
6990
|
'left.new': '新建',
|
|
6301
6991
|
'left.collapse': '折叠左侧栏',
|
|
6302
6992
|
'left.collapseSecondary': '折叠工作区面板',
|
|
6303
6993
|
'input.placeholder': '输入指令...',
|
|
6304
6994
|
'input.send': '发送',
|
|
6305
6995
|
'input.stop': '停止',
|
|
6996
|
+
'input.continue': '继续',
|
|
6306
6997
|
'input.guide': 'Guide',
|
|
6307
6998
|
'input.next': 'Next',
|
|
6308
6999
|
'mode.build': 'Build',
|
|
@@ -6552,6 +7243,7 @@ var NEWMARK_I18N = {
|
|
|
6552
7243
|
'model.yes': '是',
|
|
6553
7244
|
'model.notChecked': '未校验',
|
|
6554
7245
|
'archive.current': '归档当前对话',
|
|
7246
|
+
'archive.archiving': '归档中...',
|
|
6555
7247
|
'archive.empty': '暂无归档。',
|
|
6556
7248
|
'archive.loading': '正在加载工作区归档...',
|
|
6557
7249
|
'archive.unavailable': '归档列表不可用',
|
|
@@ -6632,7 +7324,13 @@ var NEWMARK_I18N = {
|
|
|
6632
7324
|
'flow.noAvailable': '当前没有可运行的工作流。',
|
|
6633
7325
|
'flow.started': 'Flow 已启动',
|
|
6634
7326
|
'plugins.title': '插件',
|
|
7327
|
+
'plugins.tabMcp': 'MCP',
|
|
7328
|
+
'plugins.tabDsh': 'DSH Plugin',
|
|
7329
|
+
'plugins.tabSkills': 'Skills',
|
|
7330
|
+
'plugins.tabMarket': 'Market',
|
|
7331
|
+
'plugins.tabGithub': 'GitHub',
|
|
6635
7332
|
'plugins.mcp': 'MCP 管理',
|
|
7333
|
+
'plugins.dsh': 'DSH Plugin',
|
|
6636
7334
|
'plugins.management': 'Skills 管理',
|
|
6637
7335
|
'plugins.market': 'Skills Market',
|
|
6638
7336
|
'plugins.github': 'GitHub CLI',
|
|
@@ -6690,6 +7388,74 @@ var NEWMARK_I18N = {
|
|
|
6690
7388
|
'plugins.mcpNoServers': '暂无用户 MCP 服务器。',
|
|
6691
7389
|
'plugins.mcpDiscovered': '从插件发现',
|
|
6692
7390
|
'plugins.mcpStored': '用户 MCP 服务器',
|
|
7391
|
+
'plugins.mcpConfiguredCount': '已配置 {count} 项',
|
|
7392
|
+
'plugins.mcpSearch': '搜索 MCP 服务器...',
|
|
7393
|
+
'plugins.mcpNoMatch': '没有符合搜索条件的 MCP 服务器。',
|
|
7394
|
+
'plugins.mcpRefresh': '刷新',
|
|
7395
|
+
'plugins.mcpRefreshing': '正在刷新 MCP 服务器...',
|
|
7396
|
+
'plugins.mcpLoadError': '无法加载 MCP 服务器。',
|
|
7397
|
+
'plugins.mcpUnavailable': '当前界面不支持 MCP 管理。',
|
|
7398
|
+
'plugins.mcpAddTitle': '添加 MCP 服务器',
|
|
7399
|
+
'plugins.mcpEditTitle': '编辑 MCP 服务器',
|
|
7400
|
+
'plugins.mcpReviewTitle': '审核 MCP 候选项',
|
|
7401
|
+
'plugins.mcpFormHelp': '保存前请审核所有字段。从候选项导入时始终默认禁用。',
|
|
7402
|
+
'plugins.mcpEnabled': '保存后启用此服务器',
|
|
7403
|
+
'plugins.mcpEndpointStdio': '命令',
|
|
7404
|
+
'plugins.mcpEndpointHttp': '服务器 URL',
|
|
7405
|
+
'plugins.mcpCwd': '工作目录(可选)',
|
|
7406
|
+
'plugins.mcpSecretsHelp': '编辑时留空可保留已保存的值;输入 {} 可清空。界面绝不显示密钥值。',
|
|
7407
|
+
'plugins.mcpSavedEnvKeys': '已保存环境变量键:{keys}',
|
|
7408
|
+
'plugins.mcpSavedHeaderKeys': '已保存请求头键:{keys}',
|
|
7409
|
+
'plugins.mcpNoSavedKeys': '没有已保存的键。',
|
|
7410
|
+
'plugins.mcpInvalidArgs': '参数必须是 JSON 数组。',
|
|
7411
|
+
'plugins.mcpInvalidObject': '{field} 必须是 JSON 对象。',
|
|
7412
|
+
'plugins.mcpRequiredName': '请输入服务器名称。',
|
|
7413
|
+
'plugins.mcpRequiredCommand': '请输入 stdio 服务器命令。',
|
|
7414
|
+
'plugins.mcpRequiredUrl': '请输入 http(s) 服务器 URL。',
|
|
7415
|
+
'plugins.mcpSaving': '正在保存...',
|
|
7416
|
+
'plugins.mcpSaved': 'MCP 服务器已保存。',
|
|
7417
|
+
'plugins.mcpEnabledStatus': '已启用',
|
|
7418
|
+
'plugins.mcpDisabledStatus': '已禁用',
|
|
7419
|
+
'plugins.mcpMutationFailed': 'MCP 操作失败。',
|
|
7420
|
+
'plugins.mcpRemoveConfirm': '移除 MCP 服务器“{name}”?',
|
|
7421
|
+
'plugins.mcpReadonly': '只读元数据',
|
|
7422
|
+
'plugins.mcpDiscoveredEmpty': '未从已安装插件中发现 MCP 元数据。',
|
|
7423
|
+
'plugins.mcpStoredEmpty': '暂无用户 MCP 服务器。可以添加服务器,或审核兼容的 DSH 候选项。',
|
|
7424
|
+
'plugins.mcpReviewImport': '审核并导入',
|
|
7425
|
+
'plugins.mcpCandidateHelp': '此操作只会预填 MCP 表单,不会安装、执行或自动启用任何内容。',
|
|
7426
|
+
'plugins.retry': '重试',
|
|
7427
|
+
'plugins.dshTitle': 'DSH Plugin 兼容',
|
|
7428
|
+
'plugins.dshHelp': '开发者预览:检查本地官方 DSH CLI 与包配置。发现过程严格只读,绝不会安装、执行、更新或改写 DSH。',
|
|
7429
|
+
'plugins.dshPreview': '开发者预览',
|
|
7430
|
+
'plugins.dshRescan': '重新扫描',
|
|
7431
|
+
'plugins.dshScanning': '正在扫描 DSH 兼容信息...',
|
|
7432
|
+
'plugins.dshLoadError': '无法加载 DSH 兼容信息。',
|
|
7433
|
+
'plugins.dshUnavailable': '当前界面不支持 DSH 发现。',
|
|
7434
|
+
'plugins.dshCli': 'CLI 与软件包',
|
|
7435
|
+
'plugins.dshCliPath': 'CLI 路径',
|
|
7436
|
+
'plugins.dshCliVersion': 'CLI 版本',
|
|
7437
|
+
'plugins.dshPackageVersion': '软件包版本',
|
|
7438
|
+
'plugins.dshHome': 'DSH_HOME',
|
|
7439
|
+
'plugins.dshHomeSource': '目录来源',
|
|
7440
|
+
'plugins.dshConfigFiles': '配置文件',
|
|
7441
|
+
'plugins.dshLayers': '配置层顺序',
|
|
7442
|
+
'plugins.dshLayerOrder': '后面的层覆盖前面的条目;未知键会被展示但不会改写。',
|
|
7443
|
+
'plugins.dshHomePatches': 'Home 级 patch',
|
|
7444
|
+
'plugins.dshUpdateability': '可更新性:请使用官方 DSH 工具或编辑下方 patch 文件;Newmark 不会重写这些文件。',
|
|
7445
|
+
'plugins.dshUpdateChannel': '更新通道',
|
|
7446
|
+
'plugins.dshLatestChannel': 'latest(未锁定)',
|
|
7447
|
+
'plugins.dshProfiles': 'Profiles',
|
|
7448
|
+
'plugins.dshBundles': 'Bundles',
|
|
7449
|
+
'plugins.dshWarnings': '警告',
|
|
7450
|
+
'plugins.dshUnknownKeys': '未知配置键',
|
|
7451
|
+
'plugins.dshMcpCandidates': 'MCP 候选项',
|
|
7452
|
+
'plugins.dshNone': '未发现',
|
|
7453
|
+
'plugins.dshNotAvailable': '不可用',
|
|
7454
|
+
'plugins.dshOfficialRepo': '官方仓库',
|
|
7455
|
+
'plugins.dshOfficialDocs': '官方文档',
|
|
7456
|
+
'plugins.dshOfficialNpm': 'npm 软件包',
|
|
7457
|
+
'plugins.dshReadonly': '只读兼容策略',
|
|
7458
|
+
'plugins.dshReadonlyDetail': 'Newmark 只读取本地兼容元数据。安装、执行、更新或更改 DSH 配置请使用官方 DSH 工具。',
|
|
6693
7459
|
'workspace.new': '新建工作区',
|
|
6694
7460
|
'workspace.type': '类型',
|
|
6695
7461
|
'workspace.internal': '内部工作区',
|
|
@@ -6789,6 +7555,21 @@ var NEWMARK_I18N = {
|
|
|
6789
7555
|
'status.contextModeModel': '模型',
|
|
6790
7556
|
'status.messages': '条消息',
|
|
6791
7557
|
'status.noCompression': '当前对话暂无压缩事件',
|
|
7558
|
+
'status.contextInspector': '上下文管理',
|
|
7559
|
+
'status.contextInspectorHint': '借鉴 DSH 的动态预算;可见对话历史不会被改写。',
|
|
7560
|
+
'status.activeBuild': '当前 Build',
|
|
7561
|
+
'status.longHistory': '长期历史',
|
|
7562
|
+
'status.trigger': '触发线',
|
|
7563
|
+
'status.retention': '保留量',
|
|
7564
|
+
'status.hotCache': '热缓存',
|
|
7565
|
+
'status.coldArchive': '冷归档',
|
|
7566
|
+
'status.lastCompression': '最近一次压缩',
|
|
7567
|
+
'status.noCompressionShort': '尚未压缩',
|
|
7568
|
+
'status.compressNow': '立即压缩',
|
|
7569
|
+
'status.compressing': '正在压缩...',
|
|
7570
|
+
'status.compressedNow': '上下文已压缩。',
|
|
7571
|
+
'status.compressionFailed': '上下文压缩失败。',
|
|
7572
|
+
'status.compressionBusy': '对话运行中,暂时无法压缩上下文。',
|
|
6792
7573
|
'status.recentFiles': '最近文件变更',
|
|
6793
7574
|
'status.noFileChanges': '最近一轮没有记录文件变更。',
|
|
6794
7575
|
'status.pendingOptions': '待处理选项',
|
|
@@ -6809,6 +7590,8 @@ var NEWMARK_I18N = {
|
|
|
6809
7590
|
'conversation.reorderFailed': '无法保存对话顺序。',
|
|
6810
7591
|
'conversation.pin': '置顶对话',
|
|
6811
7592
|
'conversation.unpin': '取消置顶对话',
|
|
7593
|
+
'conversation.branchCommunication': '允许分支交流',
|
|
7594
|
+
'conversation.branchCommunicationBadge': '分支交流',
|
|
6812
7595
|
'conversation.loadingIsolated': '正在加载隔离对话...',
|
|
6813
7596
|
'conversation.locked': 'Agent 工作中,当前对话已锁定。',
|
|
6814
7597
|
'queue.next': '下一轮',
|
|
@@ -6933,6 +7716,10 @@ function applyLanguageToUi() {
|
|
|
6933
7716
|
}
|
|
6934
7717
|
var wsHead = document.getElementById('left-ws-header');
|
|
6935
7718
|
if (wsHead) wsHead.textContent = t('left.workspaces');
|
|
7719
|
+
var wsList = document.getElementById('left-ws-list');
|
|
7720
|
+
if (wsList) wsList.setAttribute('aria-label', t('left.workspaces'));
|
|
7721
|
+
var conversationList = document.getElementById('conversation-list');
|
|
7722
|
+
if (conversationList) conversationList.setAttribute('aria-label', t('left.conversations'));
|
|
6936
7723
|
var wsAdd = document.querySelector('#left-ws-add span:last-child');
|
|
6937
7724
|
if (wsAdd) wsAdd.textContent = t('left.new');
|
|
6938
7725
|
setTitleAndLabel('.secondary-top button[onclick="window.openWsSettings()"]', t('workspace.settingsTitle'));
|
|
@@ -6958,6 +7745,10 @@ function applyLanguageToUi() {
|
|
|
6958
7745
|
if (browserUrl) browserUrl.setAttribute('placeholder', t('browser.url'));
|
|
6959
7746
|
var terminalInputs = document.querySelectorAll('.terminal-input');
|
|
6960
7747
|
for (var ti = 0; ti < terminalInputs.length; ti++) terminalInputs[ti].setAttribute('placeholder', t('terminal.enterCommand'));
|
|
7748
|
+
var terminalTabs = document.getElementById('terminal-tabs');
|
|
7749
|
+
if (terminalTabs) terminalTabs.setAttribute('aria-label', t('shortcuts.category.terminal'));
|
|
7750
|
+
var fileTree = document.getElementById('file-tree-container');
|
|
7751
|
+
if (fileTree) fileTree.setAttribute('aria-label', t('right.fileTree'));
|
|
6961
7752
|
var terminalReady = document.querySelector('#terminal-pane-0 .terminal-output span');
|
|
6962
7753
|
if (terminalReady && terminalReady.textContent === 'Terminal ready') terminalReady.textContent = t('terminal.ready');
|
|
6963
7754
|
var terminalStatusSpans = document.querySelectorAll('.terminal-output span');
|
|
@@ -8220,6 +9011,8 @@ window.toggleWorkReview = function(head) {
|
|
|
8220
9011
|
var review = head && head.closest ? head.closest('.work-review') : null;
|
|
8221
9012
|
if (!review) return;
|
|
8222
9013
|
review.classList.toggle('collapsed');
|
|
9014
|
+
var toggle = review.querySelector('.work-review-toggle');
|
|
9015
|
+
if (toggle) toggle.setAttribute('aria-expanded', review.classList.contains('collapsed') ? 'false' : 'true');
|
|
8223
9016
|
};
|
|
8224
9017
|
|
|
8225
9018
|
window.toggleWorkReviewFiles = function(button) {
|
|
@@ -8324,7 +9117,7 @@ function addWorkReview(diffs) {
|
|
|
8324
9117
|
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
9118
|
'<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
9119
|
'<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>' +
|
|
9120
|
+
'<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
9121
|
'<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
9122
|
els['chat-area'].appendChild(review);
|
|
8330
9123
|
autoScrollIfAtBottom();
|
|
@@ -8859,7 +9652,7 @@ function publicWorkEvent(event) {
|
|
|
8859
9652
|
var content = String(event && event.content || '');
|
|
8860
9653
|
var toolArgs = String(event && event.toolArgs || '');
|
|
8861
9654
|
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;
|
|
9655
|
+
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
9656
|
}
|
|
8864
9657
|
|
|
8865
9658
|
function publicToolNameForUi(value) {
|
|
@@ -9118,7 +9911,12 @@ function syncWorkRunsSnapshot(runs, target, branchId) {
|
|
|
9118
9911
|
return item;
|
|
9119
9912
|
});
|
|
9120
9913
|
state.workRunsByBranch[workRunBranchKey(target, selectedBranchId)] = normalized;
|
|
9121
|
-
|
|
9914
|
+
// 串分支修复:全局显示列表(workRunsByTarget)只在 sync 的分支就是「浏览分支」时
|
|
9915
|
+
// 才更新。当运行分支(runtime)的 streaming 结果到达、而用户正在浏览另一个分支时,
|
|
9916
|
+
// 只按分支存储(workRunsByBranch),不污染当前浏览分支的显示。
|
|
9917
|
+
if (selectedBranchId === branchIds.viewed) {
|
|
9918
|
+
state.workRunsByTarget[key] = normalized;
|
|
9919
|
+
}
|
|
9122
9920
|
return normalized;
|
|
9123
9921
|
}
|
|
9124
9922
|
|
|
@@ -9410,6 +10208,23 @@ function renderWorkToolGroup(event, eventIndex) {
|
|
|
9410
10208
|
activityRows + '</div></details>';
|
|
9411
10209
|
}
|
|
9412
10210
|
|
|
10211
|
+
function renderWorkThought(event, eventIndex) {
|
|
10212
|
+
var zh = currentLang() === 'zh';
|
|
10213
|
+
var content = String(event.content || '').trim();
|
|
10214
|
+
var completed = !!event.completed;
|
|
10215
|
+
var activityDomKey = String(event.id || ('thought-' + eventIndex));
|
|
10216
|
+
var label = completed ? (zh ? '进行了思考' : 'Thought') : (zh ? '思考中' : 'Thinking');
|
|
10217
|
+
var detailRows = '';
|
|
10218
|
+
if (content) {
|
|
10219
|
+
detailRows = '<div class="conversation-work-thought-text">' + esc(content) + '</div>';
|
|
10220
|
+
} else if (!completed) {
|
|
10221
|
+
detailRows = '<div class="conversation-work-thought-text conversation-work-thought-pending">' + esc(zh ? '正在思考…' : 'Thinking…') + '</div>';
|
|
10222
|
+
}
|
|
10223
|
+
return '<details class="conversation-work-activity conversation-work-thought" data-activity-key="' + escAttr(activityDomKey) + '"><summary>' +
|
|
10224
|
+
iconSvg('brain', 'thought', 'tiny') + '<span>' + esc(label) + '</span>' +
|
|
10225
|
+
'<span class="conversation-work-activity-chevron" aria-hidden="true"></span></summary>' + detailRows + '</details>';
|
|
10226
|
+
}
|
|
10227
|
+
|
|
9413
10228
|
function workEventLabel(event) {
|
|
9414
10229
|
var type = String(event && event.type || 'status').toLowerCase();
|
|
9415
10230
|
var content = String(event && event.content || '').trim();
|
|
@@ -9514,6 +10329,16 @@ function renderWorkRunEvents(run, includeGuides) {
|
|
|
9514
10329
|
}
|
|
9515
10330
|
if (!rawEvent) continue;
|
|
9516
10331
|
}
|
|
10332
|
+
if (rawType === 'thought_result') {
|
|
10333
|
+
for (var thoughtPriorIndex = events.length - 1; thoughtPriorIndex >= 0; thoughtPriorIndex--) {
|
|
10334
|
+
var thoughtPrior = events[thoughtPriorIndex];
|
|
10335
|
+
if (String(thoughtPrior && thoughtPrior.type || '').toLowerCase() !== 'thought' || thoughtPrior.completed) continue;
|
|
10336
|
+
events[thoughtPriorIndex] = Object.assign({}, thoughtPrior, { completed: true, content: rawEvent.content || thoughtPrior.content });
|
|
10337
|
+
rawEvent = null;
|
|
10338
|
+
break;
|
|
10339
|
+
}
|
|
10340
|
+
if (!rawEvent) continue;
|
|
10341
|
+
}
|
|
9517
10342
|
events.push(rawEvent);
|
|
9518
10343
|
}
|
|
9519
10344
|
flushPublicText();
|
|
@@ -9554,6 +10379,7 @@ function renderWorkRunEvents(run, includeGuides) {
|
|
|
9554
10379
|
}
|
|
9555
10380
|
if (type.indexOf('guide') === 0 || event.guide) return renderWorkRunGuideMessage(event);
|
|
9556
10381
|
if (type === 'tool_group') return renderWorkToolGroup(event, eventIndex);
|
|
10382
|
+
if (type === 'thought') return renderWorkThought(event, eventIndex);
|
|
9557
10383
|
var activitySummary = type.indexOf('tool_') === 0 && type !== 'tool_call' && type !== 'tool_result';
|
|
9558
10384
|
var cls = type.indexOf('guide') === 0 ? ' guide' : (type === 'error' ? ' error' : (activitySummary ? ' activity-summary' : ''));
|
|
9559
10385
|
var label = activitySummary ? workToolActivityLabel(event.activity, Number(event.count || 1), !!event.completed) : workEventLabel(event) + (event.completed ? (currentLang() === 'zh' ? ' · 已完成' : ' · completed') : '');
|
|
@@ -10576,7 +11402,12 @@ function applyConversationSnapshot(s, requestedConversationId) {
|
|
|
10576
11402
|
if (s && s.runtimeKey) registerRuntimeKey(snapshotTarget, s.runtimeKey);
|
|
10577
11403
|
hydrateConversationBranchState(s);
|
|
10578
11404
|
rebindQueueToRuntimeBranch(snapshotTarget);
|
|
10579
|
-
if (s && Array.isArray(s.workRuns))
|
|
11405
|
+
if (s && Array.isArray(s.workRuns)) {
|
|
11406
|
+
var viewedBranchIdForSync = Array.isArray(s.viewedBranchNodePath) && s.viewedBranchNodePath.length
|
|
11407
|
+
? String(s.viewedBranchNodePath[s.viewedBranchNodePath.length - 1])
|
|
11408
|
+
: '';
|
|
11409
|
+
syncWorkRunsSnapshot(s.workRuns, snapshotTarget, viewedBranchIdForSync || undefined);
|
|
11410
|
+
}
|
|
10580
11411
|
applyAutoRouteRatingState(s);
|
|
10581
11412
|
if (s && s.chatMessages) {
|
|
10582
11413
|
renderChatMessages(s.chatMessages);
|
|
@@ -10639,9 +11470,9 @@ function addShellBlock(title, content) {
|
|
|
10639
11470
|
var div = document.createElement('div');
|
|
10640
11471
|
div.className = 'chat-msg assistant';
|
|
10641
11472
|
div.innerHTML = '<div class="shell-block collapsed">' +
|
|
10642
|
-
'<
|
|
11473
|
+
'<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
11474
|
'<span class="arrow">></span> ' + esc(title) +
|
|
10644
|
-
'</
|
|
11475
|
+
'</button><div class="shell-block-body">' + esc(content) + '</div></div>';
|
|
10645
11476
|
els['chat-area'].appendChild(div);
|
|
10646
11477
|
autoScrollIfAtBottom();
|
|
10647
11478
|
}
|
|
@@ -10650,10 +11481,10 @@ function addDiffBlock(title, adds, dels, linesHTML) {
|
|
|
10650
11481
|
var div = document.createElement('div');
|
|
10651
11482
|
div.className = 'chat-msg assistant';
|
|
10652
11483
|
div.innerHTML = '<div class="diff-block collapsed">' +
|
|
10653
|
-
'<
|
|
11484
|
+
'<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
11485
|
'<span class="arrow">></span> ' + esc(title) +
|
|
10655
11486
|
'<span class="diff-stat"><span class="diff-add">+' + adds + '</span><span class="diff-del">-' + dels + '</span></span>' +
|
|
10656
|
-
'</
|
|
11487
|
+
'</button><div class="diff-block-body">' + linesHTML + '</div></div>';
|
|
10657
11488
|
els['chat-area'].appendChild(div);
|
|
10658
11489
|
autoScrollIfAtBottom();
|
|
10659
11490
|
}
|
|
@@ -11135,7 +11966,7 @@ window.stopCurrentConversation = async function() {
|
|
|
11135
11966
|
return true;
|
|
11136
11967
|
};
|
|
11137
11968
|
|
|
11138
|
-
window.submitCurrentAction = function() {
|
|
11969
|
+
window.submitCurrentAction = function(source) {
|
|
11139
11970
|
if (currentFlowRunning() && flowTakeoverMatchesCurrent()) {
|
|
11140
11971
|
if (!promptHasText()) {
|
|
11141
11972
|
window.stopFlowRun();
|
|
@@ -11170,6 +12001,8 @@ window.submitCurrentAction = function() {
|
|
|
11170
12001
|
return;
|
|
11171
12002
|
}
|
|
11172
12003
|
if (isCurrentConversationRunning() && !promptHasText()) {
|
|
12004
|
+
// 回车:运行中空输入不操作(打断仅通过 Esc 或点击打断按钮)。
|
|
12005
|
+
if (source === 'enter') return;
|
|
11173
12006
|
window.stopCurrentConversation();
|
|
11174
12007
|
return;
|
|
11175
12008
|
}
|
|
@@ -11211,6 +12044,98 @@ window.renderContextWindow = function() {
|
|
|
11211
12044
|
ring.style.mask = 'radial-gradient(farthest-side, transparent 58%, #000 60%)';
|
|
11212
12045
|
var status = c.warning === 'over_limit' ? t('status.contextOverLimit') : (c.warning === 'near_limit' ? t('status.contextNearLimit') : t('status.contextTokens'));
|
|
11213
12046
|
ring.title = status + ': ' + used + ' / ' + max;
|
|
12047
|
+
if (window.renderContextInspector) window.renderContextInspector();
|
|
12048
|
+
};
|
|
12049
|
+
|
|
12050
|
+
function contextInspectorValue(value) {
|
|
12051
|
+
var number = Number(value);
|
|
12052
|
+
return Number.isFinite(number) ? Math.max(0, Math.round(number)) : 0;
|
|
12053
|
+
}
|
|
12054
|
+
|
|
12055
|
+
function contextInspectorCell(label, value) {
|
|
12056
|
+
return '<div class="context-inspector-cell"><span class="context-inspector-label">' + esc(label) + '</span><span class="context-inspector-value">' + esc(value) + '</span></div>';
|
|
12057
|
+
}
|
|
12058
|
+
|
|
12059
|
+
window.renderContextInspector = function() {
|
|
12060
|
+
var panel = document.getElementById('context-inspector');
|
|
12061
|
+
var ring = els['context-token-ring'] || document.getElementById('context-token-ring');
|
|
12062
|
+
if (!panel || !ring) return;
|
|
12063
|
+
ring.setAttribute('aria-expanded', state.contextInspectorOpen ? 'true' : 'false');
|
|
12064
|
+
panel.classList.toggle('open', state.contextInspectorOpen);
|
|
12065
|
+
if (!state.contextInspectorOpen) {
|
|
12066
|
+
panel.innerHTML = '';
|
|
12067
|
+
return;
|
|
12068
|
+
}
|
|
12069
|
+
var c = state.contextWindow || {};
|
|
12070
|
+
var max = Math.max(1, contextInspectorValue(c.maxTokens) || 1);
|
|
12071
|
+
var used = contextInspectorValue(c.estimatedTokens);
|
|
12072
|
+
var active = contextInspectorValue(c.buildBlockTokens);
|
|
12073
|
+
var history = contextInspectorValue(c.longHistoryTokens);
|
|
12074
|
+
var activeTrigger = contextInspectorValue(c.buildBlockTriggerTokens);
|
|
12075
|
+
var historyTrigger = contextInspectorValue(c.longHistoryTriggerTokens);
|
|
12076
|
+
var activeRetention = contextInspectorValue(c.buildBlockRetentionTokens);
|
|
12077
|
+
var historyRetention = contextInspectorValue(c.longHistoryRetentionTokens);
|
|
12078
|
+
var percent = Math.min(100, Math.round((used / max) * 100));
|
|
12079
|
+
var fillColor = c.warning === 'over_limit' ? 'var(--nm-state-danger)' : (c.warning === 'near_limit' ? 'var(--nm-state-warning)' : 'var(--accent)');
|
|
12080
|
+
var compression = state.contextCompression || null;
|
|
12081
|
+
var last = compression
|
|
12082
|
+
? ((compression.fallback ? t('status.contextModeFallback') : t('status.contextModeModel')) + ' · ' + String(compression.originalMessages || 0) + ' → ' + String(compression.compressedMessages || 0) + ' ' + t('status.messages'))
|
|
12083
|
+
: t('status.noCompressionShort');
|
|
12084
|
+
var busy = !!state.contextMutationPending;
|
|
12085
|
+
var running = typeof isCurrentConversationRunning === 'function' && isCurrentConversationRunning();
|
|
12086
|
+
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>' +
|
|
12087
|
+
'<button type="button" class="context-inspector-close" onclick="window.closeContextInspector()" aria-label="' + esc(t('common.close') || 'Close') + '">×</button></div>' +
|
|
12088
|
+
'<div class="context-inspector-meter"><div class="context-inspector-meter-fill" style="width:' + percent + '%;background:' + fillColor + '"></div></div>' +
|
|
12089
|
+
'<div class="context-inspector-grid">' +
|
|
12090
|
+
contextInspectorCell(t('status.contextTokens'), used + ' / ' + max) +
|
|
12091
|
+
contextInspectorCell(t('status.activeBuild'), active + ' / ' + activeTrigger) +
|
|
12092
|
+
contextInspectorCell(t('status.longHistory'), history + ' / ' + historyTrigger) +
|
|
12093
|
+
contextInspectorCell(t('status.retention'), activeRetention + ' + ' + historyRetention) +
|
|
12094
|
+
contextInspectorCell(t('status.hotCache'), contextInspectorValue(c.cacheEntries) + ' entries') +
|
|
12095
|
+
contextInspectorCell(t('status.coldArchive'), contextInspectorValue(c.archiveEntries) + ' entries') +
|
|
12096
|
+
'</div>' +
|
|
12097
|
+
'<div class="context-inspector-section"><div class="context-inspector-section-title">' + esc(t('status.lastCompression')) + '</div><div class="context-inspector-meta">' + esc(last) + '</div>' +
|
|
12098
|
+
(compression && compression.model ? '<div class="context-inspector-meta">' + esc(compression.model) + '</div>' : '') + '</div>' +
|
|
12099
|
+
'<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>';
|
|
12100
|
+
};
|
|
12101
|
+
|
|
12102
|
+
window.closeContextInspector = function() {
|
|
12103
|
+
state.contextInspectorOpen = false;
|
|
12104
|
+
window.renderContextInspector();
|
|
12105
|
+
};
|
|
12106
|
+
|
|
12107
|
+
window.toggleContextInspector = function() {
|
|
12108
|
+
state.contextInspectorOpen = !state.contextInspectorOpen;
|
|
12109
|
+
window.hideContextWindowTooltip();
|
|
12110
|
+
window.renderContextInspector();
|
|
12111
|
+
};
|
|
12112
|
+
|
|
12113
|
+
window.compressContextNow = function() {
|
|
12114
|
+
if (state.contextMutationPending) return;
|
|
12115
|
+
if (typeof isCurrentConversationRunning === 'function' && isCurrentConversationRunning()) {
|
|
12116
|
+
showUiNotice(t('status.compressionBusy'), 'error', 'context-compress-busy');
|
|
12117
|
+
return;
|
|
12118
|
+
}
|
|
12119
|
+
if (!api.compressContext) {
|
|
12120
|
+
showUiNotice(t('status.compressionFailed'), 'error', 'context-compress-unavailable');
|
|
12121
|
+
return;
|
|
12122
|
+
}
|
|
12123
|
+
state.contextMutationPending = true;
|
|
12124
|
+
window.renderContextInspector();
|
|
12125
|
+
Promise.resolve(api.compressContext({ target: currentConversationTarget(), force: true })).then(function(result) {
|
|
12126
|
+
if (!result || result.ok === false) throw new Error((result && result.error) || t('status.compressionFailed'));
|
|
12127
|
+
if (result.contextWindow) state.contextWindow = result.contextWindow;
|
|
12128
|
+
if (result.contextCompression !== undefined) state.contextCompression = result.contextCompression;
|
|
12129
|
+
window.renderContextWindow();
|
|
12130
|
+
window.renderRightStatusPanel();
|
|
12131
|
+
showUiNotice(t('status.compressedNow'), 'success', 'context-compress-success');
|
|
12132
|
+
return result;
|
|
12133
|
+
}).catch(function(error) {
|
|
12134
|
+
showUiNotice(error && error.message ? error.message : t('status.compressionFailed'), 'error', 'context-compress-error');
|
|
12135
|
+
}).finally(function() {
|
|
12136
|
+
state.contextMutationPending = false;
|
|
12137
|
+
window.renderContextInspector();
|
|
12138
|
+
});
|
|
11214
12139
|
};
|
|
11215
12140
|
|
|
11216
12141
|
window.contextWindowTooltipHtml = function() {
|
|
@@ -11831,6 +12756,7 @@ window.renderQueuePanel = function() {
|
|
|
11831
12756
|
}
|
|
11832
12757
|
var toggle = panel.querySelector('#queue-expand-btn');
|
|
11833
12758
|
if (toggle) {
|
|
12759
|
+
toggle.setAttribute('aria-expanded', state.queueCollapsed ? 'false' : 'true');
|
|
11834
12760
|
toggle.title = state.queueCollapsed ? t('queue.expand') : t('queue.collapse');
|
|
11835
12761
|
toggle.innerHTML = iconSvg(state.queueCollapsed ? 'chevron-up' : 'chevron-down', toggle.title, 'tiny');
|
|
11836
12762
|
}
|
|
@@ -12120,7 +13046,14 @@ window.sendMessage = async function(modeOverride, queuedText, opts) {
|
|
|
12120
13046
|
var displayText = optimisticAttachments.length
|
|
12121
13047
|
? rawText + (rawText ? '\n\n' : '') + '[' + optimisticAttachments.length + ' image attachment' + (optimisticAttachments.length === 1 ? '' : 's') + ']'
|
|
12122
13048
|
: text;
|
|
12123
|
-
if (!text && !optimisticAttachments.length)
|
|
13049
|
+
if (!text && !optimisticAttachments.length) {
|
|
13050
|
+
// 空输入时发送默认句段「继续 / Continue」,按界面语言切换。
|
|
13051
|
+
var continuePhrase = t('input.continue');
|
|
13052
|
+
rawText = continuePhrase;
|
|
13053
|
+
text = continuePhrase;
|
|
13054
|
+
requestMessage = continuePhrase;
|
|
13055
|
+
displayText = continuePhrase;
|
|
13056
|
+
}
|
|
12124
13057
|
|
|
12125
13058
|
var lockedConversationId = activeConversationId();
|
|
12126
13059
|
var lockedTarget = currentConversationTarget(lockedConversationId);
|
|
@@ -12868,19 +13801,25 @@ window.toggleBottom = function() {
|
|
|
12868
13801
|
};
|
|
12869
13802
|
|
|
12870
13803
|
// === Right Sidebar Tabs ===
|
|
13804
|
+
function rightTabButtonHtml(tab, icon, label, active) {
|
|
13805
|
+
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>';
|
|
13806
|
+
}
|
|
13807
|
+
|
|
12871
13808
|
window.upgradeRightSidebar = function() {
|
|
12872
13809
|
var rightTabs = els['right-tabs'] || document.getElementById('right-tabs');
|
|
12873
13810
|
var rightContent = els['right-content'] || document.getElementById('right-content');
|
|
12874
13811
|
if (!rightTabs || !rightContent || rightTabs.getAttribute('data-upgraded') === 'true') return;
|
|
12875
13812
|
rightTabs.setAttribute('data-upgraded', 'true');
|
|
13813
|
+
rightTabs.setAttribute('role', 'tablist');
|
|
13814
|
+
rightTabs.setAttribute('aria-label', t('right.files'));
|
|
12876
13815
|
rightTabs.innerHTML =
|
|
12877
|
-
'
|
|
12878
|
-
|
|
12879
|
-
|
|
12880
|
-
'
|
|
12881
|
-
|
|
12882
|
-
|
|
12883
|
-
|
|
13816
|
+
rightTabButtonHtml('file-tree', 'folder', t('right.files'), state.rightTab === 'file-tree') +
|
|
13817
|
+
rightTabButtonHtml('editor', 'square-pen', t('right.editor'), state.rightTab === 'editor') +
|
|
13818
|
+
rightTabButtonHtml('plan', 'list-checks', t('right.plan'), state.rightTab === 'plan') +
|
|
13819
|
+
rightTabButtonHtml('subagent', 'bot', t('right.subagents'), state.rightTab === 'subagent') +
|
|
13820
|
+
rightTabButtonHtml('browser', 'globe', t('right.browser'), state.rightTab === 'browser') +
|
|
13821
|
+
rightTabButtonHtml('status', 'activity', t('right.status'), state.rightTab === 'status') +
|
|
13822
|
+
rightTabButtonHtml('archives', 'archive', t('right.archives'), state.rightTab === 'archives') +
|
|
12884
13823
|
'<div class="tab-divider"></div>' +
|
|
12885
13824
|
'<button class="tab-btn" onclick="window.toggleRight()" title="' + escAttr(t('right.close')) + '">' + iconOnly('x', t('right.close')) + '</button>';
|
|
12886
13825
|
|
|
@@ -12888,7 +13827,7 @@ window.upgradeRightSidebar = function() {
|
|
|
12888
13827
|
if (filePanel && !filePanel.getAttribute('data-upgraded')) {
|
|
12889
13828
|
filePanel.setAttribute('data-upgraded', 'true');
|
|
12890
13829
|
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>';
|
|
13830
|
+
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
13831
|
if (tree) document.getElementById('file-tree-container').innerHTML = tree.innerHTML;
|
|
12893
13832
|
}
|
|
12894
13833
|
var subPanel = document.getElementById('panel-subagent');
|
|
@@ -12919,6 +13858,14 @@ window.upgradeRightSidebar = function() {
|
|
|
12919
13858
|
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
13859
|
rightContent.appendChild(archivesPanel);
|
|
12921
13860
|
}
|
|
13861
|
+
var upgradedPanels = rightContent.querySelectorAll('.tab-panel');
|
|
13862
|
+
for (var upgradedIndex = 0; upgradedIndex < upgradedPanels.length; upgradedIndex++) {
|
|
13863
|
+
var upgradedPanel = upgradedPanels[upgradedIndex];
|
|
13864
|
+
var upgradedTab = upgradedPanel.id.replace(/^panel-/, '');
|
|
13865
|
+
upgradedPanel.setAttribute('role', 'tabpanel');
|
|
13866
|
+
upgradedPanel.setAttribute('aria-labelledby', 'right-tab-' + upgradedTab);
|
|
13867
|
+
upgradedPanel.hidden = upgradedTab !== state.rightTab;
|
|
13868
|
+
}
|
|
12922
13869
|
};
|
|
12923
13870
|
|
|
12924
13871
|
window.switchRightTab = function(tab) {
|
|
@@ -12932,11 +13879,16 @@ window.switchRightTab = function(tab) {
|
|
|
12932
13879
|
if (!rightTabs || !rightContent) return;
|
|
12933
13880
|
var btns = rightTabs.querySelectorAll('.tab-btn[data-tab]');
|
|
12934
13881
|
for (var i = 0; i < btns.length; i++) {
|
|
12935
|
-
|
|
13882
|
+
var selected = btns[i].getAttribute('data-tab') === tab;
|
|
13883
|
+
btns[i].classList.toggle('active', selected);
|
|
13884
|
+
btns[i].setAttribute('aria-selected', selected ? 'true' : 'false');
|
|
13885
|
+
btns[i].tabIndex = selected ? 0 : -1;
|
|
12936
13886
|
}
|
|
12937
13887
|
var panels = rightContent.querySelectorAll('.tab-panel');
|
|
12938
13888
|
for (var j = 0; j < panels.length; j++) {
|
|
12939
|
-
|
|
13889
|
+
var panelActive = panels[j].id === 'panel-' + tab;
|
|
13890
|
+
panels[j].classList.toggle('active', panelActive);
|
|
13891
|
+
panels[j].hidden = !panelActive;
|
|
12940
13892
|
}
|
|
12941
13893
|
// Load content on first access
|
|
12942
13894
|
if (tab === 'file-tree') window.loadFileTree();
|
|
@@ -13028,7 +13980,7 @@ window.renderConversationPlan = function() {
|
|
|
13028
13980
|
var plan = normalizeConversationPlan(state.conversationPlan);
|
|
13029
13981
|
var items = plan.items || [];
|
|
13030
13982
|
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()">' +
|
|
13983
|
+
'<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
13984
|
'<button class="sec-btn primary" onclick="window.addConversationPlanItem()">' + esc(t('plan.add')) + '</button>' +
|
|
13033
13985
|
'</div>';
|
|
13034
13986
|
if (!items.length) {
|
|
@@ -13096,7 +14048,7 @@ window.editConversationPlanItem = function(idx) {
|
|
|
13096
14048
|
var rows = target.querySelectorAll('.plan-row');
|
|
13097
14049
|
var row = rows[idx];
|
|
13098
14050
|
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 + ')">';
|
|
14051
|
+
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
14052
|
var actions = row.querySelector('.plan-actions');
|
|
13101
14053
|
if (actions) {
|
|
13102
14054
|
actions.innerHTML = '<button class="archive-action-btn" onclick="window.saveConversationPlanEdit(' + idx + ')">' + esc(t('common.save')) + '</button>' +
|
|
@@ -13247,6 +14199,8 @@ window.renderRightStatusPanel = function() {
|
|
|
13247
14199
|
if (contextWindow) {
|
|
13248
14200
|
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
14201
|
esc(String(contextWindow.estimatedTokens || 0) + ' / ' + String(contextWindow.maxTokens || 0) + ' | ' + String(contextWindow.warning || 'ok')) +
|
|
14202
|
+
(contextWindow.buildBlockTokens !== undefined ? '<br>' + esc(t('status.activeBuild')) + ': ' + esc(String(contextWindow.buildBlockTokens || 0) + ' / ' + String(contextWindow.buildBlockTriggerTokens || 0)) +
|
|
14203
|
+
' · ' + esc(t('status.longHistory')) + ': ' + esc(String(contextWindow.longHistoryTokens || 0) + ' / ' + String(contextWindow.longHistoryTriggerTokens || 0)) : '') +
|
|
13250
14204
|
'</span></div></div>';
|
|
13251
14205
|
}
|
|
13252
14206
|
if (compression) {
|
|
@@ -13470,6 +14424,35 @@ window.spawnTerminal = function(shellId, options) {
|
|
|
13470
14424
|
return window.addTerminalTab(shellId, options);
|
|
13471
14425
|
};
|
|
13472
14426
|
|
|
14427
|
+
window.handleTerminalTabKey = function(event) {
|
|
14428
|
+
if (!event || event.defaultPrevented || event.isComposing || event.key === 'Process' || event.keyCode === 229 || event.target !== event.currentTarget) return false;
|
|
14429
|
+
var tabs = Array.prototype.slice.call(document.querySelectorAll('#terminal-tabs .terminal-tab'));
|
|
14430
|
+
var index = tabs.indexOf(event.currentTarget);
|
|
14431
|
+
if (index < 0 || !tabs.length) return false;
|
|
14432
|
+
var next = index;
|
|
14433
|
+
if (event.key === 'ArrowRight') next = (index + 1) % tabs.length;
|
|
14434
|
+
else if (event.key === 'ArrowLeft') next = (index - 1 + tabs.length) % tabs.length;
|
|
14435
|
+
else if (event.key === 'Home') next = 0;
|
|
14436
|
+
else if (event.key === 'End') next = tabs.length - 1;
|
|
14437
|
+
else if (event.key === 'Enter' || event.key === ' ') next = index;
|
|
14438
|
+
else if (event.key === 'Delete') {
|
|
14439
|
+
event.preventDefault();
|
|
14440
|
+
var closingId = parseInt(tabs[index].getAttribute('data-tab-id'), 10);
|
|
14441
|
+
window.closeTerminalTab(closingId);
|
|
14442
|
+
requestAnimationFrame(function() {
|
|
14443
|
+
var activeTab = document.querySelector('#terminal-tabs .terminal-tab.active') || document.querySelector('#terminal-tabs .terminal-tab');
|
|
14444
|
+
if (activeTab) activeTab.focus({ preventScroll:true });
|
|
14445
|
+
});
|
|
14446
|
+
return true;
|
|
14447
|
+
}
|
|
14448
|
+
else return false;
|
|
14449
|
+
event.preventDefault();
|
|
14450
|
+
var tabId = parseInt(tabs[next].getAttribute('data-tab-id'), 10);
|
|
14451
|
+
window.switchTerminalTab(tabId);
|
|
14452
|
+
tabs[next].focus({ preventScroll:true });
|
|
14453
|
+
return true;
|
|
14454
|
+
};
|
|
14455
|
+
|
|
13473
14456
|
window.addTerminalTab = function(shellId, options) {
|
|
13474
14457
|
options = options || {};
|
|
13475
14458
|
shellId = normalizeTerminalShell(shellId || state._terminalShell);
|
|
@@ -13487,13 +14470,23 @@ window.addTerminalTab = function(shellId, options) {
|
|
|
13487
14470
|
// Create tab button
|
|
13488
14471
|
var tab = document.createElement('div');
|
|
13489
14472
|
tab.className = 'terminal-tab active';
|
|
14473
|
+
tab.id = 'terminal-tab-' + tabId;
|
|
14474
|
+
tab.setAttribute('role', 'tab');
|
|
14475
|
+
tab.setAttribute('aria-selected', 'true');
|
|
14476
|
+
tab.setAttribute('aria-controls', 'terminal-pane-' + tabId);
|
|
14477
|
+
tab.tabIndex = 0;
|
|
13490
14478
|
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>';
|
|
14479
|
+
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
14480
|
tab.onclick = function() { window.switchTerminalTab(tabId); };
|
|
14481
|
+
tab.addEventListener('keydown', window.handleTerminalTabKey);
|
|
13493
14482
|
|
|
13494
14483
|
// Deactivate all other tabs
|
|
13495
14484
|
var allTabs = tabsContainer.querySelectorAll('.terminal-tab');
|
|
13496
|
-
for (var i = 0; i < allTabs.length; i++)
|
|
14485
|
+
for (var i = 0; i < allTabs.length; i++) {
|
|
14486
|
+
allTabs[i].classList.remove('active');
|
|
14487
|
+
allTabs[i].setAttribute('aria-selected', 'false');
|
|
14488
|
+
allTabs[i].tabIndex = -1;
|
|
14489
|
+
}
|
|
13497
14490
|
|
|
13498
14491
|
tabsContainer.appendChild(tab);
|
|
13499
14492
|
|
|
@@ -13501,18 +14494,20 @@ window.addTerminalTab = function(shellId, options) {
|
|
|
13501
14494
|
var pane = document.createElement('div');
|
|
13502
14495
|
pane.className = 'terminal-pane active';
|
|
13503
14496
|
pane.id = 'terminal-pane-' + tabId;
|
|
14497
|
+
pane.setAttribute('role', 'tabpanel');
|
|
14498
|
+
pane.setAttribute('aria-labelledby', tab.id);
|
|
13504
14499
|
pane.setAttribute('data-tab-id', tabId);
|
|
13505
14500
|
pane.setAttribute('data-session', '');
|
|
13506
14501
|
pane.innerHTML =
|
|
13507
14502
|
'<div class="terminal-output"><span style="color:var(--accent2);">Connecting ' + shellId + '...</span>\r\n</div>' +
|
|
13508
14503
|
'<div class="terminal-input-row">' +
|
|
13509
14504
|
'<span class="terminal-prompt">' + shellLabel + '></span>' +
|
|
13510
|
-
'<input class="terminal-input" type="text" placeholder="Enter command..." onkeydown="if(event.key===\'Enter\')window.terminalSend()">' +
|
|
14505
|
+
'<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
14506
|
'</div>';
|
|
13512
14507
|
|
|
13513
14508
|
// Deactivate all other panes
|
|
13514
14509
|
var allPanes = body.querySelectorAll('.terminal-pane');
|
|
13515
|
-
for (var j = 0; j < allPanes.length; j++) allPanes[j].classList.remove('active');
|
|
14510
|
+
for (var j = 0; j < allPanes.length; j++) { allPanes[j].classList.remove('active'); allPanes[j].hidden = true; }
|
|
13516
14511
|
|
|
13517
14512
|
body.appendChild(pane);
|
|
13518
14513
|
|
|
@@ -13563,21 +14558,33 @@ window.ensureTerminalTakeoverPane = function(session) {
|
|
|
13563
14558
|
|
|
13564
14559
|
var tab = document.createElement('div');
|
|
13565
14560
|
tab.className = 'terminal-tab agent-takeover marquee-border';
|
|
14561
|
+
tab.id = 'terminal-tab-' + tabId;
|
|
14562
|
+
tab.setAttribute('role', 'tab');
|
|
14563
|
+
tab.setAttribute('aria-selected', 'true');
|
|
14564
|
+
tab.setAttribute('aria-controls', 'terminal-pane-' + tabId);
|
|
14565
|
+
tab.tabIndex = 0;
|
|
13566
14566
|
tab.setAttribute('data-tab-id', tabId);
|
|
13567
14567
|
tab.setAttribute('data-takeover-session', key);
|
|
13568
14568
|
tab.setAttribute('data-takeover-workspace-id', session.workspaceId || '');
|
|
13569
14569
|
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>';
|
|
14570
|
+
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
14571
|
tab.onclick = function() { window.switchTerminalTab(tabId); };
|
|
14572
|
+
tab.addEventListener('keydown', window.handleTerminalTabKey);
|
|
13572
14573
|
|
|
13573
14574
|
var allTabs = tabsContainer.querySelectorAll('.terminal-tab');
|
|
13574
|
-
for (var i = 0; i < allTabs.length; i++)
|
|
14575
|
+
for (var i = 0; i < allTabs.length; i++) {
|
|
14576
|
+
allTabs[i].classList.remove('active');
|
|
14577
|
+
allTabs[i].setAttribute('aria-selected', 'false');
|
|
14578
|
+
allTabs[i].tabIndex = -1;
|
|
14579
|
+
}
|
|
13575
14580
|
tab.classList.add('active');
|
|
13576
14581
|
tabsContainer.appendChild(tab);
|
|
13577
14582
|
|
|
13578
14583
|
var pane = document.createElement('div');
|
|
13579
14584
|
pane.className = 'terminal-pane active agent-takeover marquee-border';
|
|
13580
14585
|
pane.id = 'terminal-pane-' + tabId;
|
|
14586
|
+
pane.setAttribute('role', 'tabpanel');
|
|
14587
|
+
pane.setAttribute('aria-labelledby', tab.id);
|
|
13581
14588
|
pane.setAttribute('data-tab-id', tabId);
|
|
13582
14589
|
pane.setAttribute('data-session', '');
|
|
13583
14590
|
pane.setAttribute('data-takeover-session', key);
|
|
@@ -13589,11 +14596,11 @@ window.ensureTerminalTakeoverPane = function(session) {
|
|
|
13589
14596
|
'<div class="terminal-output"></div>' +
|
|
13590
14597
|
'<div class="terminal-input-row">' +
|
|
13591
14598
|
'<span class="terminal-prompt">Agent></span>' +
|
|
13592
|
-
'<input class="terminal-input" type="text" placeholder="Enter command..." onkeydown="if(event.key===\'Enter\')window.terminalSend()">' +
|
|
14599
|
+
'<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
14600
|
'</div>';
|
|
13594
14601
|
|
|
13595
14602
|
var allPanes = body.querySelectorAll('.terminal-pane');
|
|
13596
|
-
for (var j = 0; j < allPanes.length; j++) allPanes[j].classList.remove('active');
|
|
14603
|
+
for (var j = 0; j < allPanes.length; j++) { allPanes[j].classList.remove('active'); allPanes[j].hidden = true; }
|
|
13597
14604
|
body.appendChild(pane);
|
|
13598
14605
|
tabsContainer.scrollLeft = tabsContainer.scrollWidth;
|
|
13599
14606
|
window.switchTerminalTab(tabId);
|
|
@@ -13688,12 +14695,17 @@ window.switchTerminalTab = function(tabId) {
|
|
|
13688
14695
|
// Update tabs
|
|
13689
14696
|
var allTabs = document.querySelectorAll('.terminal-tab');
|
|
13690
14697
|
for (var i = 0; i < allTabs.length; i++) {
|
|
13691
|
-
|
|
14698
|
+
var selected = parseInt(allTabs[i].getAttribute('data-tab-id')) === tabId;
|
|
14699
|
+
allTabs[i].classList.toggle('active', selected);
|
|
14700
|
+
allTabs[i].setAttribute('aria-selected', selected ? 'true' : 'false');
|
|
14701
|
+
allTabs[i].tabIndex = selected ? 0 : -1;
|
|
13692
14702
|
}
|
|
13693
14703
|
// Update panes
|
|
13694
14704
|
var allPanes = document.querySelectorAll('.terminal-pane');
|
|
13695
14705
|
for (var j = 0; j < allPanes.length; j++) {
|
|
13696
|
-
|
|
14706
|
+
var active = parseInt(allPanes[j].getAttribute('data-tab-id')) === tabId;
|
|
14707
|
+
allPanes[j].classList.toggle('active', active);
|
|
14708
|
+
allPanes[j].hidden = !active;
|
|
13697
14709
|
}
|
|
13698
14710
|
// Update active session
|
|
13699
14711
|
var activePane = document.querySelector('.terminal-pane.active');
|
|
@@ -13879,6 +14891,7 @@ function renderTodo() {
|
|
|
13879
14891
|
label.textContent = t('goal.list') + (items.length ? ' ' + items.length : '');
|
|
13880
14892
|
var toggle = wrap.querySelector('#todo-header .stack-icon-btn');
|
|
13881
14893
|
if (toggle) {
|
|
14894
|
+
toggle.setAttribute('aria-expanded', state.todoCollapsed ? 'false' : 'true');
|
|
13882
14895
|
var title = state.todoCollapsed ? t('queue.expand') : t('queue.collapse');
|
|
13883
14896
|
toggle.title = title;
|
|
13884
14897
|
toggle.innerHTML = iconSvg(state.todoCollapsed ? 'chevron-up' : 'chevron-down', title, 'tiny');
|
|
@@ -13891,10 +14904,10 @@ function renderTodo() {
|
|
|
13891
14904
|
for (var i = 0; i < items.length; i++) {
|
|
13892
14905
|
var item = items[i];
|
|
13893
14906
|
var done = item.status === 'done';
|
|
13894
|
-
html += '<
|
|
14907
|
+
html += '<button type="button" class="todo-item ' + (done ? 'done' : '') + '" onclick="window.checkTodo(' + i + ')" title="' + escAttr(item.text) + '" aria-pressed="' + (done ? 'true' : 'false') + '">' +
|
|
13895
14908
|
'<span class="todo-check">' + (done ? iconSvg('check', 'done', 'tiny') : '') + '</span>' +
|
|
13896
14909
|
'<span class="todo-text">' + esc(item.text) + '</span>' +
|
|
13897
|
-
'</
|
|
14910
|
+
'</button>';
|
|
13898
14911
|
}
|
|
13899
14912
|
list.innerHTML = html;
|
|
13900
14913
|
}
|
|
@@ -13995,8 +15008,61 @@ window.setInputMode = function(mode, persist) {
|
|
|
13995
15008
|
};
|
|
13996
15009
|
|
|
13997
15010
|
// === Sub-Window System ===
|
|
15011
|
+
var subWindowOriginFocus = null;
|
|
15012
|
+
function newmarkFocusableElements(container) {
|
|
15013
|
+
if (!container || !container.querySelectorAll) return [];
|
|
15014
|
+
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) {
|
|
15015
|
+
return !element.hidden && element.getAttribute('aria-hidden') !== 'true' && element.getClientRects().length > 0;
|
|
15016
|
+
});
|
|
15017
|
+
}
|
|
15018
|
+
|
|
15019
|
+
function focusSubWindowInitial() {
|
|
15020
|
+
var dialog = els['sub-win'];
|
|
15021
|
+
if (!dialog || !els['sub-win-overlay'].classList.contains('open')) return;
|
|
15022
|
+
var body = els['sub-win-body'];
|
|
15023
|
+
var target = body && (body.querySelector('[autofocus]') || newmarkFocusableElements(body)[0]);
|
|
15024
|
+
if (!target) target = dialog.querySelector('.sub-win-close') || dialog;
|
|
15025
|
+
if (target && typeof target.focus === 'function') target.focus({ preventScroll: true });
|
|
15026
|
+
}
|
|
15027
|
+
|
|
15028
|
+
function updateApplicationInertState() {
|
|
15029
|
+
var commandOpen = !!(document.getElementById('command-surface-overlay') && document.getElementById('command-surface-overlay').classList.contains('open'));
|
|
15030
|
+
var subWindowOpen = !!(els['sub-win-overlay'] && els['sub-win-overlay'].classList.contains('open'));
|
|
15031
|
+
var topbar = document.getElementById('topbar');
|
|
15032
|
+
var main = document.getElementById('main');
|
|
15033
|
+
if (topbar) topbar.inert = commandOpen || subWindowOpen;
|
|
15034
|
+
if (main) main.inert = commandOpen || subWindowOpen;
|
|
15035
|
+
if (els['sub-win-overlay']) els['sub-win-overlay'].inert = commandOpen;
|
|
15036
|
+
}
|
|
15037
|
+
window.updateApplicationInertState = updateApplicationInertState;
|
|
15038
|
+
|
|
15039
|
+
function trapNewmarkDialogFocus(event, container) {
|
|
15040
|
+
if (!event || event.key !== 'Tab' || !container) return false;
|
|
15041
|
+
var items = newmarkFocusableElements(container);
|
|
15042
|
+
if (!items.length) {
|
|
15043
|
+
event.preventDefault();
|
|
15044
|
+
if (typeof container.focus === 'function') container.focus();
|
|
15045
|
+
return true;
|
|
15046
|
+
}
|
|
15047
|
+
var first = items[0];
|
|
15048
|
+
var last = items[items.length - 1];
|
|
15049
|
+
var active = document.activeElement;
|
|
15050
|
+
if (event.shiftKey && (active === first || !container.contains(active))) {
|
|
15051
|
+
event.preventDefault();
|
|
15052
|
+
last.focus();
|
|
15053
|
+
return true;
|
|
15054
|
+
}
|
|
15055
|
+
if (!event.shiftKey && (active === last || !container.contains(active))) {
|
|
15056
|
+
event.preventDefault();
|
|
15057
|
+
first.focus();
|
|
15058
|
+
return true;
|
|
15059
|
+
}
|
|
15060
|
+
return false;
|
|
15061
|
+
}
|
|
15062
|
+
|
|
13998
15063
|
window.openSubWin = function(title, html) {
|
|
13999
15064
|
var overlayOpen = els['sub-win-overlay'].classList.contains('open');
|
|
15065
|
+
if (!overlayOpen && document.activeElement && typeof document.activeElement.focus === 'function') subWindowOriginFocus = document.activeElement;
|
|
14000
15066
|
if (overlayOpen && !state.restoringSubWindow && state.activeSubWindowView) {
|
|
14001
15067
|
if (!state.subWindowStack) state.subWindowStack = [];
|
|
14002
15068
|
state.subWindowStack.push({
|
|
@@ -14010,6 +15076,25 @@ window.openSubWin = function(title, html) {
|
|
|
14010
15076
|
els['sub-win-body'].innerHTML = html;
|
|
14011
15077
|
els['sub-win'].classList.toggle('memory-lab-window', !!(state.activeSubWindowView && state.activeSubWindowView.name === 'memoryLab'));
|
|
14012
15078
|
els['sub-win-overlay'].classList.add('open');
|
|
15079
|
+
updateApplicationInertState();
|
|
15080
|
+
requestAnimationFrame(focusSubWindowInitial);
|
|
15081
|
+
};
|
|
15082
|
+
|
|
15083
|
+
window.handleRightTabKey = function(event) {
|
|
15084
|
+
if (!event) return;
|
|
15085
|
+
var tabs = Array.prototype.slice.call((els['right-tabs'] || document).querySelectorAll('.tab-btn[data-tab]'));
|
|
15086
|
+
var index = tabs.indexOf(event.currentTarget);
|
|
15087
|
+
if (index < 0) return;
|
|
15088
|
+
var next = index;
|
|
15089
|
+
if (event.key === 'ArrowRight') next = (index + 1) % tabs.length;
|
|
15090
|
+
else if (event.key === 'ArrowLeft') next = (index - 1 + tabs.length) % tabs.length;
|
|
15091
|
+
else if (event.key === 'Home') next = 0;
|
|
15092
|
+
else if (event.key === 'End') next = tabs.length - 1;
|
|
15093
|
+
else return;
|
|
15094
|
+
event.preventDefault();
|
|
15095
|
+
var tab = tabs[next].getAttribute('data-tab');
|
|
15096
|
+
window.switchRightTab(tab);
|
|
15097
|
+
tabs[next].focus();
|
|
14013
15098
|
};
|
|
14014
15099
|
|
|
14015
15100
|
window.closeSubWin = function() {
|
|
@@ -14023,6 +15108,7 @@ window.closeSubWin = function() {
|
|
|
14023
15108
|
requestAnimationFrame(function() {
|
|
14024
15109
|
els['sub-win-body'].scrollTop = previous.scrollTop || 0;
|
|
14025
15110
|
state.restoringSubWindow = false;
|
|
15111
|
+
focusSubWindowInitial();
|
|
14026
15112
|
});
|
|
14027
15113
|
return;
|
|
14028
15114
|
}
|
|
@@ -14030,6 +15116,12 @@ window.closeSubWin = function() {
|
|
|
14030
15116
|
state.activeSubWindowView = null;
|
|
14031
15117
|
var win = els['sub-win'];
|
|
14032
15118
|
if (win) { win.classList.remove('memory-lab-window'); win.style.left = ''; win.style.top = ''; win.style.margin = ''; }
|
|
15119
|
+
var restoreFocus = subWindowOriginFocus;
|
|
15120
|
+
subWindowOriginFocus = null;
|
|
15121
|
+
updateApplicationInertState();
|
|
15122
|
+
requestAnimationFrame(function() {
|
|
15123
|
+
if (restoreFocus && restoreFocus.isConnected && typeof restoreFocus.focus === 'function') restoreFocus.focus({ preventScroll: true });
|
|
15124
|
+
});
|
|
14033
15125
|
};
|
|
14034
15126
|
|
|
14035
15127
|
function rerenderActiveSubWindowForLanguage() {
|
|
@@ -14078,19 +15170,19 @@ window.openSettings = function(tab) {
|
|
|
14078
15170
|
var activeTab = tab || state.settingsActiveTab || 'general';
|
|
14079
15171
|
var refreshingSettings = els['sub-win-overlay'].classList.contains('open') && state.activeSubWindowView && state.activeSubWindowView.name === 'settings';
|
|
14080
15172
|
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>' +
|
|
15173
|
+
var html = '<div class="settings-tabs" role="tablist" aria-label="' + escAttr(t('settings.title')) + '">' +
|
|
15174
|
+
'<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>' +
|
|
15175
|
+
'<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>' +
|
|
15176
|
+
'<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>' +
|
|
15177
|
+
'<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>' +
|
|
15178
|
+
'<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
15179
|
'</div>' +
|
|
14088
|
-
'<div class="stab-panel" id="stab-general" data-lazy="1"></div>' +
|
|
15180
|
+
'<div class="stab-panel" id="stab-general" role="tabpanel" aria-labelledby="settings-tab-general" data-lazy="1"></div>' +
|
|
14089
15181
|
// 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>');
|
|
15182
|
+
(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>') +
|
|
15183
|
+
(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>') +
|
|
15184
|
+
(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>') +
|
|
15185
|
+
(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
15186
|
state.activeSubWindowView = { name: 'settings', tab: activeTab };
|
|
14095
15187
|
if (refreshingSettings) state.restoringSubWindow = true;
|
|
14096
15188
|
window.openSubWin(t('settings.title'), html);
|
|
@@ -14457,7 +15549,12 @@ window.settingsTab = function(name) {
|
|
|
14457
15549
|
state.settingsActiveTab = name || 'general';
|
|
14458
15550
|
var btns = document.querySelectorAll('.stab-btn');
|
|
14459
15551
|
for (var i = 0; i < btns.length; i++) {
|
|
14460
|
-
|
|
15552
|
+
var selected = btns[i].getAttribute('data-stab') === name;
|
|
15553
|
+
btns[i].classList.toggle('active', selected);
|
|
15554
|
+
if (btns[i].closest('.settings-tabs:not(.plugin-tabs)')) {
|
|
15555
|
+
btns[i].setAttribute('aria-selected', selected ? 'true' : 'false');
|
|
15556
|
+
btns[i].tabIndex = selected ? 0 : -1;
|
|
15557
|
+
}
|
|
14461
15558
|
}
|
|
14462
15559
|
// Render lazy panels on first access for faster initial open
|
|
14463
15560
|
var panelId = 'stab-' + name;
|
|
@@ -14483,6 +15580,7 @@ window.settingsTab = function(name) {
|
|
|
14483
15580
|
var panels = document.querySelectorAll('.stab-panel');
|
|
14484
15581
|
for (var j = 0; j < panels.length; j++) {
|
|
14485
15582
|
panels[j].classList.toggle('active', panels[j].id === panelId);
|
|
15583
|
+
panels[j].hidden = panels[j].id !== panelId;
|
|
14486
15584
|
}
|
|
14487
15585
|
if (name === 'models' && panel && panel.getAttribute('data-lazy') !== '1') window.loadGlobalAgentPrompt();
|
|
14488
15586
|
};
|
|
@@ -14501,8 +15599,8 @@ window.refreshGlobalConfigFile = function() {
|
|
|
14501
15599
|
if (!api.reloadGlobalConfig) return;
|
|
14502
15600
|
api.reloadGlobalConfig().then(function(result) {
|
|
14503
15601
|
if (result && result.error) throw new Error(result.error);
|
|
14504
|
-
|
|
14505
|
-
|
|
15602
|
+
try { sessionStorage.setItem('newmark-config-reloading', '1'); } catch (_) {}
|
|
15603
|
+
window.location.reload();
|
|
14506
15604
|
}).catch(function(error) {
|
|
14507
15605
|
showUiNotice(error && error.message ? error.message : String(error), 'error', 'global-config-refresh');
|
|
14508
15606
|
});
|
|
@@ -15179,7 +16277,13 @@ window.validateAllModels = function() {
|
|
|
15179
16277
|
return state.modelValidationResults;
|
|
15180
16278
|
}).catch(function(err) {
|
|
15181
16279
|
document.body.classList.remove('model-evaluating');
|
|
15182
|
-
|
|
16280
|
+
var failedHtml = '<div style="color:#ff7777;font-size:12px;">' + esc(t('model.validationFailed')) + ': ' + esc(err.message) + '</div>';
|
|
16281
|
+
var body = document.getElementById('sub-win-body');
|
|
16282
|
+
if (body && document.getElementById('model-validation-progress') && els['sub-win-overlay'].classList.contains('open')) {
|
|
16283
|
+
body.innerHTML = failedHtml;
|
|
16284
|
+
} else {
|
|
16285
|
+
addMsg('assistant', redactSensitiveText('[Error] ' + t('model.validationFailed') + ': ' + err.message), 'error', '');
|
|
16286
|
+
}
|
|
15183
16287
|
return [];
|
|
15184
16288
|
}).finally(function() {
|
|
15185
16289
|
window.stopModelValidationProgressPolling();
|
|
@@ -15195,16 +16299,45 @@ window.renderModelValidationProgress = function(progress) {
|
|
|
15195
16299
|
var completedModels = Math.max(0, Number(progress.completedModels || 0));
|
|
15196
16300
|
var totalModels = Math.max(0, Number(progress.totalModels || 0));
|
|
15197
16301
|
var current = [String(progress.currentModel || ''), String(progress.currentCheck || '')].filter(Boolean).join(' · ');
|
|
15198
|
-
return '<div class="provider-card marquee-border">' +
|
|
15199
|
-
'<div style="display:flex;justify-content:space-between;gap:10px;"><span>' + esc(t('model.validating')) + '</span><strong>' + esc(String(percent)) + '%</strong></div>' +
|
|
15200
|
-
'<div role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="' + esc(String(percent)) + '" style="height:7px;margin-top:10px;border-radius:999px;background:var(--surface-strong);overflow:hidden;"><div style="height:100%;width:' + esc(String(percent)) + '%;background:var(--accent);transition:width .18s ease;"></div></div>' +
|
|
15201
|
-
'<div style="margin-top:8px;color:var(--text-dim);font-size:11px;display:flex;justify-content:space-between;gap:8px;"><span>' + esc(String(completedChecks)) + '/' + esc(String(totalChecks)) + ' ' + esc(t('model.validationChecks')) + '</span><span>' + esc(String(completedModels)) + '/' + esc(String(totalModels)) + ' ' + esc(t('model.validationModels')) + '</span></div>' +
|
|
15202
|
-
|
|
16302
|
+
return '<div class="provider-card marquee-border" id="model-validation-progress">' +
|
|
16303
|
+
'<div style="display:flex;justify-content:space-between;gap:10px;"><span>' + esc(t('model.validating')) + '</span><strong id="mv-percent">' + esc(String(percent)) + '%</strong></div>' +
|
|
16304
|
+
'<div id="mv-progressbar" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="' + esc(String(percent)) + '" style="height:7px;margin-top:10px;border-radius:999px;background:var(--surface-strong);overflow:hidden;"><div id="mv-bar" style="height:100%;width:' + esc(String(percent)) + '%;background:var(--accent);transition:width .18s ease;"></div></div>' +
|
|
16305
|
+
'<div style="margin-top:8px;color:var(--text-dim);font-size:11px;display:flex;justify-content:space-between;gap:8px;"><span id="mv-checks">' + esc(String(completedChecks)) + '/' + esc(String(totalChecks)) + ' ' + esc(t('model.validationChecks')) + '</span><span id="mv-models">' + esc(String(completedModels)) + '/' + esc(String(totalModels)) + ' ' + esc(t('model.validationModels')) + '</span></div>' +
|
|
16306
|
+
'<div id="mv-current" style="margin-top:6px;color:var(--text-dim);font-size:11px;overflow-wrap:anywhere;' + (current ? '' : 'display:none;') + '">' + esc(t('model.validationCurrent')) + ': ' + esc(current) + '</div>' +
|
|
15203
16307
|
'</div><div style="margin-top:6px;color:var(--text-dim);font-size:11px;">' + esc(t('model.validationBackgroundNote')) + '</div>';
|
|
15204
16308
|
};
|
|
15205
16309
|
|
|
16310
|
+
window.updateModelValidationProgress = function(progress) {
|
|
16311
|
+
progress = progress || {};
|
|
16312
|
+
var body = document.getElementById('sub-win-body');
|
|
16313
|
+
if (!body) return;
|
|
16314
|
+
var percent = Math.max(0, Math.min(100, Number(progress.percent || 0)));
|
|
16315
|
+
var completedChecks = Math.max(0, Number(progress.completedChecks || 0));
|
|
16316
|
+
var totalChecks = Math.max(0, Number(progress.totalChecks || 0));
|
|
16317
|
+
var completedModels = Math.max(0, Number(progress.completedModels || 0));
|
|
16318
|
+
var totalModels = Math.max(0, Number(progress.totalModels || 0));
|
|
16319
|
+
var current = [String(progress.currentModel || ''), String(progress.currentCheck || '')].filter(Boolean).join(' · ');
|
|
16320
|
+
var percentEl = document.getElementById('mv-percent');
|
|
16321
|
+
if (!percentEl) return;
|
|
16322
|
+
percentEl.textContent = String(percent) + '%';
|
|
16323
|
+
var barEl = document.getElementById('mv-bar');
|
|
16324
|
+
if (barEl) barEl.style.width = String(percent) + '%';
|
|
16325
|
+
var progressbarEl = document.getElementById('mv-progressbar');
|
|
16326
|
+
if (progressbarEl) progressbarEl.setAttribute('aria-valuenow', String(percent));
|
|
16327
|
+
var checksEl = document.getElementById('mv-checks');
|
|
16328
|
+
if (checksEl) checksEl.textContent = String(completedChecks) + '/' + String(totalChecks) + ' ' + t('model.validationChecks');
|
|
16329
|
+
var modelsEl = document.getElementById('mv-models');
|
|
16330
|
+
if (modelsEl) modelsEl.textContent = String(completedModels) + '/' + String(totalModels) + ' ' + t('model.validationModels');
|
|
16331
|
+
var currentEl = document.getElementById('mv-current');
|
|
16332
|
+
if (currentEl) {
|
|
16333
|
+
currentEl.textContent = t('model.validationCurrent') + ': ' + current;
|
|
16334
|
+
currentEl.style.display = current ? '' : 'none';
|
|
16335
|
+
}
|
|
16336
|
+
};
|
|
16337
|
+
|
|
15206
16338
|
window.showModelValidationProgress = function(progress) {
|
|
15207
16339
|
document.body.classList.add('model-evaluating');
|
|
16340
|
+
if (document.getElementById('model-validation-progress')) return;
|
|
15208
16341
|
window.openSubWin(t('model.validationTitle'), window.renderModelValidationProgress(progress));
|
|
15209
16342
|
};
|
|
15210
16343
|
|
|
@@ -15220,7 +16353,7 @@ window.startModelValidationProgressPolling = function() {
|
|
|
15220
16353
|
Promise.resolve(api.modelValidationStatus()).then(function(progress) {
|
|
15221
16354
|
if (!state.modelValidationPromise) return;
|
|
15222
16355
|
var body = document.getElementById('sub-win-body');
|
|
15223
|
-
if (body && els['sub-win-overlay'].classList.contains('open'))
|
|
16356
|
+
if (body && els['sub-win-overlay'].classList.contains('open')) window.updateModelValidationProgress(progress);
|
|
15224
16357
|
state.modelValidationProgressTimer = setTimeout(poll, 150);
|
|
15225
16358
|
}).catch(function() {
|
|
15226
16359
|
if (state.modelValidationPromise) state.modelValidationProgressTimer = setTimeout(poll, 300);
|
|
@@ -15247,7 +16380,21 @@ window.showModelEvaluationResults = function(results) {
|
|
|
15247
16380
|
}
|
|
15248
16381
|
}
|
|
15249
16382
|
html += '</div>';
|
|
15250
|
-
|
|
16383
|
+
var body = document.getElementById('sub-win-body');
|
|
16384
|
+
if (body && document.getElementById('model-validation-progress') && els['sub-win-overlay'].classList.contains('open')) {
|
|
16385
|
+
// The progress window is still visible: replace it in place so closing
|
|
16386
|
+
// the results restores whatever window was open before validation.
|
|
16387
|
+
body.innerHTML = html;
|
|
16388
|
+
return;
|
|
16389
|
+
}
|
|
16390
|
+
// The user closed the progress window or opened another window while
|
|
16391
|
+
// validation was running. Do not hijack the current window; summarize in chat.
|
|
16392
|
+
var okCount = 0;
|
|
16393
|
+
for (var j = 0; j < (results || []).length; j++) {
|
|
16394
|
+
var status = String((results[j] && results[j].status) || '');
|
|
16395
|
+
if (status === 'verified' || status === 'degraded' || status === 'available') okCount++;
|
|
16396
|
+
}
|
|
16397
|
+
addMsg('assistant', '[System] ' + t('model.validationTitle') + ': ' + okCount + '/' + (results || []).length + ' ' + t('model.validationModels'), okCount === (results || []).length ? 'success' : 'warning', '');
|
|
15251
16398
|
};
|
|
15252
16399
|
renderArchiveSettings = function() {
|
|
15253
16400
|
if (api.listArchives && !state._allArchiveSettingsLoading) {
|
|
@@ -15290,6 +16437,23 @@ window.archiveCurrent = function() {
|
|
|
15290
16437
|
return window.archiveConv(currentId);
|
|
15291
16438
|
};
|
|
15292
16439
|
|
|
16440
|
+
window.handleSettingsTabKey = function(event) {
|
|
16441
|
+
if (!event) return;
|
|
16442
|
+
var tabs = Array.prototype.slice.call(document.querySelectorAll('.settings-tabs:not(.plugin-tabs) [role="tab"]'));
|
|
16443
|
+
var index = tabs.indexOf(event.currentTarget);
|
|
16444
|
+
if (index < 0) return;
|
|
16445
|
+
var next = index;
|
|
16446
|
+
if (event.key === 'ArrowRight') next = (index + 1) % tabs.length;
|
|
16447
|
+
else if (event.key === 'ArrowLeft') next = (index - 1 + tabs.length) % tabs.length;
|
|
16448
|
+
else if (event.key === 'Home') next = 0;
|
|
16449
|
+
else if (event.key === 'End') next = tabs.length - 1;
|
|
16450
|
+
else return;
|
|
16451
|
+
event.preventDefault();
|
|
16452
|
+
var name = tabs[next].getAttribute('data-stab');
|
|
16453
|
+
window.settingsTab(name);
|
|
16454
|
+
tabs[next].focus();
|
|
16455
|
+
};
|
|
16456
|
+
|
|
15293
16457
|
window.loadArchive = function(idx, scope) {
|
|
15294
16458
|
var item = (scope === 'all' ? state.allArchives : state.workspaceArchives)[idx];
|
|
15295
16459
|
if (!item || !api.readArchive) return;
|
|
@@ -15624,10 +16788,10 @@ function renderFlowItem(work, idx, expanded) {
|
|
|
15624
16788
|
componentsHtml += '</div>';
|
|
15625
16789
|
}
|
|
15626
16790
|
return '<div class="flow-item">' +
|
|
15627
|
-
'<
|
|
16791
|
+
'<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
16792
|
'<span class="arrow">></span><span class="flow-item-name">' + esc(work.name || t('flow.untitled')) + '</span>' +
|
|
15629
16793
|
'<span class="flow-item-type">' + (work.components ? work.components.length : 0) + ' ' + esc(t('flow.components')) + '</span>' +
|
|
15630
|
-
'</
|
|
16794
|
+
'</button>' +
|
|
15631
16795
|
'<div class="flow-item-children" style="margin-bottom:4px;">' +
|
|
15632
16796
|
'<div style="display:flex;gap:4px;padding:4px 0;">' +
|
|
15633
16797
|
'<button class="sec-btn" style="flex:1;font-size:10px;" onclick="window.addFlowComp(' + idx + ',\'dialog\')">+ ' + esc(t('flow.dialog')) + '</button>' +
|
|
@@ -15642,7 +16806,7 @@ function renderFlowItem(work, idx, expanded) {
|
|
|
15642
16806
|
window.newFlowWork = function() {
|
|
15643
16807
|
var html = '<div style="padding:10px;">' +
|
|
15644
16808
|
'<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()">' +
|
|
16809
|
+
'<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
16810
|
'<div style="margin-top:12px;display:flex;gap:8px;">' +
|
|
15647
16811
|
'<button class="sec-btn primary" style="flex:1;" onclick="window.doNewFlowWork()">' + esc(t('common.create')) + '</button>' +
|
|
15648
16812
|
'<button class="sec-btn" onclick="window.showFlowEditor()">' + esc(t('common.cancel')) + '</button>' +
|
|
@@ -16351,14 +17515,25 @@ function renderTreeNodes(nodes, parent, depth) {
|
|
|
16351
17515
|
var n = nodes[i];
|
|
16352
17516
|
var div = document.createElement('div');
|
|
16353
17517
|
div.className = 'ft-item';
|
|
17518
|
+
div.setAttribute('role', 'treeitem');
|
|
17519
|
+
var treeRoot = parent.closest ? (parent.closest('[role="tree"]') || parent) : parent;
|
|
17520
|
+
div.tabIndex = treeRoot.querySelector && treeRoot.querySelector('[role="treeitem"][tabindex="0"]') ? -1 : 0;
|
|
17521
|
+
div.addEventListener('keydown', window.handleFileTreeKey);
|
|
17522
|
+
div.addEventListener('focus', function() {
|
|
17523
|
+
var root = this.closest('[role="tree"]');
|
|
17524
|
+
if (!root) return;
|
|
17525
|
+
Array.prototype.forEach.call(root.querySelectorAll('[role="treeitem"]'), function(item) { item.tabIndex = item === document.activeElement ? 0 : -1; });
|
|
17526
|
+
});
|
|
16354
17527
|
div.style.paddingLeft = (8 + depth * 14) + 'px';
|
|
16355
17528
|
var icon = n.type === 'directory' ? iconSvg('folder', 'Folder', 'small') : iconSvg('file', 'File', 'small');
|
|
16356
17529
|
if (n.type === 'directory') {
|
|
17530
|
+
div.setAttribute('aria-expanded', 'false');
|
|
16357
17531
|
div.innerHTML = '<span class="ft-toggle collapsed">' + iconSvg('chevron-right', t('fileTree.toggleFolder'), 'tiny') + '</span>' +
|
|
16358
17532
|
'<span class="ft-icon">' + icon + '</span><span class="ft-name">' + esc(n.name) + '</span>';
|
|
16359
17533
|
parent.appendChild(div);
|
|
16360
17534
|
var childContainer = document.createElement('div');
|
|
16361
17535
|
childContainer.className = 'ft-children';
|
|
17536
|
+
childContainer.setAttribute('role', 'group');
|
|
16362
17537
|
childContainer.style.display = 'none';
|
|
16363
17538
|
parent.appendChild(childContainer);
|
|
16364
17539
|
div.onclick = function(node, toggle, children, childDepth) {
|
|
@@ -16367,6 +17542,7 @@ function renderTreeNodes(nodes, parent, depth) {
|
|
|
16367
17542
|
var opening = children.style.display === 'none';
|
|
16368
17543
|
children.style.display = opening ? 'block' : 'none';
|
|
16369
17544
|
toggle.classList.toggle('collapsed', !opening);
|
|
17545
|
+
this.setAttribute('aria-expanded', opening ? 'true' : 'false');
|
|
16370
17546
|
if (!opening || children.getAttribute('data-loaded') === 'true') return;
|
|
16371
17547
|
children.setAttribute('data-loading', 'true');
|
|
16372
17548
|
try {
|
|
@@ -16474,8 +17650,7 @@ window.renderNativeEditor = function() {
|
|
|
16474
17650
|
}
|
|
16475
17651
|
window.renderEditorGutter(code);
|
|
16476
17652
|
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);
|
|
17653
|
+
window.renderEditorCaretStatus();
|
|
16479
17654
|
if (els['editor-dirty']) els['editor-dirty'].textContent = code !== state.editorOriginal ? 'modified' : '';
|
|
16480
17655
|
if (els['editor-vim-mode']) els['editor-vim-mode'].textContent = state.editorVimEnabled ? state.editorVimMode.toUpperCase() : 'INSERT';
|
|
16481
17656
|
if (state.editorPreview && els['editor-md-preview']) els['editor-md-preview'].innerHTML = renderMessageContent(code);
|
|
@@ -16517,6 +17692,7 @@ window.editorSetValue = function(value, preserveUndo) {
|
|
|
16517
17692
|
if (!ta) return;
|
|
16518
17693
|
if (!preserveUndo && ta.value !== value) { state.editorUndo.push(ta.value); if (state.editorUndo.length > 100) state.editorUndo.shift(); state.editorRedo = []; }
|
|
16519
17694
|
ta.value = value;
|
|
17695
|
+
state.editorCompletionCache = [];
|
|
16520
17696
|
window.renderNativeEditor();
|
|
16521
17697
|
};
|
|
16522
17698
|
|
|
@@ -16545,23 +17721,100 @@ window.editorReplaceSelection = function(text) {
|
|
|
16545
17721
|
window.renderNativeEditor();
|
|
16546
17722
|
};
|
|
16547
17723
|
|
|
16548
|
-
window.
|
|
17724
|
+
window.applyEditorCompletionDelta = function(payload) {
|
|
17725
|
+
payload = payload || {};
|
|
17726
|
+
if (String(payload.requestId || '') !== String(state.editorCompletionRequest || '')) return;
|
|
17727
|
+
var delta = String(payload.text || '');
|
|
17728
|
+
if (!delta || !state.editorCompletionAnchor) return;
|
|
17729
|
+
state.editorCompletionStreamText = (state.editorCompletionStreamText || '') + delta;
|
|
17730
|
+
state.editorCompletionText = state.editorCompletionStreamText.slice(0, 1200);
|
|
17731
|
+
window.renderEditorGhostText();
|
|
17732
|
+
if (els['editor-completion']) { els['editor-completion'].textContent = ''; els['editor-completion'].classList.remove('open'); }
|
|
17733
|
+
};
|
|
17734
|
+
|
|
17735
|
+
function editorCompletionValueKey(value) {
|
|
17736
|
+
var text = String(value || '');
|
|
17737
|
+
var hash = 2166136261;
|
|
17738
|
+
for (var i = 0; i < text.length; i++) hash = Math.imul(hash ^ text.charCodeAt(i), 16777619);
|
|
17739
|
+
return text.length + ':' + (hash >>> 0);
|
|
17740
|
+
}
|
|
17741
|
+
|
|
17742
|
+
function editorCompletionAnchorKey(anchor) {
|
|
17743
|
+
return [anchor.path, anchor.start, anchor.end, editorCompletionValueKey(anchor.value)].join('\u0000');
|
|
17744
|
+
}
|
|
17745
|
+
|
|
17746
|
+
function editorCompletionCacheFind(anchor) {
|
|
17747
|
+
var cache = Array.isArray(state.editorCompletionCache) ? state.editorCompletionCache : [];
|
|
17748
|
+
state.editorCompletionCache = cache;
|
|
17749
|
+
var now = Date.now();
|
|
17750
|
+
var key = editorCompletionAnchorKey(anchor);
|
|
17751
|
+
for (var i = cache.length - 1; i >= 0; i--) {
|
|
17752
|
+
var item = cache[i];
|
|
17753
|
+
if (!item || item.expiresAt <= now) { cache.splice(i, 1); continue; }
|
|
17754
|
+
if (item.key === key) {
|
|
17755
|
+
cache.splice(i, 1);
|
|
17756
|
+
cache.unshift(item);
|
|
17757
|
+
return item;
|
|
17758
|
+
}
|
|
17759
|
+
}
|
|
17760
|
+
return null;
|
|
17761
|
+
}
|
|
17762
|
+
|
|
17763
|
+
function editorCompletionCachePut(anchor, text, ttl) {
|
|
17764
|
+
var cache = Array.isArray(state.editorCompletionCache) ? state.editorCompletionCache : [];
|
|
17765
|
+
var key = editorCompletionAnchorKey(anchor);
|
|
17766
|
+
state.editorCompletionCache = cache.filter(function(item) { return !item || item.key !== key; });
|
|
17767
|
+
state.editorCompletionCache.unshift({ key: key, text: text, expiresAt: Date.now() + ttl });
|
|
17768
|
+
if (state.editorCompletionCache.length > 16) state.editorCompletionCache.length = 16;
|
|
17769
|
+
}
|
|
17770
|
+
|
|
17771
|
+
window.requestEditorCompletion = async function(options) {
|
|
17772
|
+
options = options || {};
|
|
17773
|
+
var force = options.force === true;
|
|
16549
17774
|
var ta = els['editor-textarea']; if (!ta || !state.editorPath || !api.editorComplete) return;
|
|
16550
17775
|
var requestId = ++state.editorCompletionRequest;
|
|
16551
17776
|
var pos = ta.selectionStart;
|
|
16552
17777
|
var anchor = { path: state.editorPath, value: ta.value, start: pos, end: ta.selectionEnd };
|
|
16553
17778
|
state.editorCompletionAnchor = anchor;
|
|
17779
|
+
var cached = force ? null : editorCompletionCacheFind(anchor);
|
|
17780
|
+
if (cached) {
|
|
17781
|
+
state.editorCompletionInFlight = false;
|
|
17782
|
+
state.editorCompletionStreamText = '';
|
|
17783
|
+
state.editorCompletionText = cached.text || '';
|
|
17784
|
+
state.editorCompletionAnchor = state.editorCompletionText ? anchor : null;
|
|
17785
|
+
window.renderEditorGhostText();
|
|
17786
|
+
if (els['editor-completion']) { els['editor-completion'].textContent = ''; els['editor-completion'].classList.remove('open'); }
|
|
17787
|
+
return;
|
|
17788
|
+
}
|
|
16554
17789
|
if (els['editor-completion']) { els['editor-completion'].textContent = 'Predicting...'; els['editor-completion'].classList.add('open'); }
|
|
16555
|
-
|
|
16556
|
-
|
|
16557
|
-
var
|
|
17790
|
+
state.editorCompletionInFlight = true;
|
|
17791
|
+
state.editorCompletionStreamText = '';
|
|
17792
|
+
var beforeStart = Math.max(0, pos - 3200);
|
|
17793
|
+
var afterEnd = Math.min(ta.value.length, pos + 800);
|
|
17794
|
+
var result;
|
|
17795
|
+
try {
|
|
17796
|
+
result = await api.editorComplete({ requestId: String(requestId), path: state.editorPath, before: ta.value.slice(beforeStart, pos), after: ta.value.slice(pos, afterEnd) });
|
|
17797
|
+
} catch (error) {
|
|
17798
|
+
result = { ok: false, text: '', error: error && error.message ? error.message : String(error) };
|
|
17799
|
+
} finally {
|
|
17800
|
+
if (requestId === state.editorCompletionRequest) state.editorCompletionInFlight = false;
|
|
17801
|
+
}
|
|
16558
17802
|
if (requestId !== state.editorCompletionRequest) return;
|
|
16559
|
-
|
|
16560
|
-
|
|
17803
|
+
// Input/caret handlers already schedule the replacement request. Do not
|
|
17804
|
+
// recursively schedule here: that doubled provider traffic on fast edits.
|
|
17805
|
+
if (!window.editorAnchorMatches(anchor)) return;
|
|
17806
|
+
var suggestion = result && result.ok ? String(result.text || '').slice(0, 1200) : '';
|
|
17807
|
+
if (!suggestion.trim()) suggestion = '';
|
|
17808
|
+
state.editorCompletionText = suggestion;
|
|
17809
|
+
state.editorCompletionStreamText = '';
|
|
17810
|
+
state.editorCompletionAnchor = suggestion ? anchor : null;
|
|
17811
|
+
editorCompletionCachePut(anchor, suggestion, suggestion ? 15000 : 2000);
|
|
16561
17812
|
window.renderEditorGhostText();
|
|
16562
17813
|
if (els['editor-completion']) {
|
|
16563
|
-
|
|
16564
|
-
|
|
17814
|
+
// Empty/aborted/timeout responses are normal for an inline predictor. The
|
|
17815
|
+
// editor should stay quiet instead of flashing an error on every keystroke.
|
|
17816
|
+
els['editor-completion'].textContent = '';
|
|
17817
|
+
els['editor-completion'].classList.remove('open');
|
|
16565
17818
|
}
|
|
16566
17819
|
};
|
|
16567
17820
|
|
|
@@ -16590,7 +17843,7 @@ window.scheduleEditorCompletion = function() {
|
|
|
16590
17843
|
state.editorCompletionTimer = setTimeout(function() {
|
|
16591
17844
|
state.editorCompletionTimer = null;
|
|
16592
17845
|
window.requestEditorCompletion();
|
|
16593
|
-
},
|
|
17846
|
+
}, 300);
|
|
16594
17847
|
};
|
|
16595
17848
|
|
|
16596
17849
|
window.editorCaretSignature = function() {
|
|
@@ -16609,7 +17862,8 @@ window.handleEditorCaretChange = function() {
|
|
|
16609
17862
|
var signature = window.editorCaretSignature();
|
|
16610
17863
|
if (signature === state.editorCaretSignature) return;
|
|
16611
17864
|
state.editorCaretSignature = signature;
|
|
16612
|
-
window.
|
|
17865
|
+
window.renderEditorCaretStatus();
|
|
17866
|
+
window.renderEditorGhostText();
|
|
16613
17867
|
window.scheduleEditorCompletion();
|
|
16614
17868
|
};
|
|
16615
17869
|
|
|
@@ -16617,7 +17871,24 @@ window.acceptEditorCompletion = function() {
|
|
|
16617
17871
|
if (state.editorCompletionText && window.editorCompletionAnchorIsCurrent()) window.editorReplaceSelection(state.editorCompletionText);
|
|
16618
17872
|
window.dismissEditorCompletion();
|
|
16619
17873
|
};
|
|
16620
|
-
window.dismissEditorCompletion = function() {
|
|
17874
|
+
window.dismissEditorCompletion = function() {
|
|
17875
|
+
state.editorCompletionText = '';
|
|
17876
|
+
state.editorCompletionStreamText = '';
|
|
17877
|
+
state.editorCompletionAnchor = null;
|
|
17878
|
+
state.editorCompletionRequest++;
|
|
17879
|
+
if (state.editorCompletionInFlight && api.editorCompleteCancel) {
|
|
17880
|
+
try { Promise.resolve(api.editorCompleteCancel()).catch(function() {}); } catch (_) {}
|
|
17881
|
+
}
|
|
17882
|
+
if (els['editor-completion']) { els['editor-completion'].textContent = ''; els['editor-completion'].classList.remove('open'); }
|
|
17883
|
+
window.renderEditorGhostText();
|
|
17884
|
+
};
|
|
17885
|
+
|
|
17886
|
+
window.renderEditorCaretStatus = function() {
|
|
17887
|
+
var ta = els['editor-textarea'];
|
|
17888
|
+
if (!ta) return;
|
|
17889
|
+
var before = String(ta.value || '').slice(0, ta.selectionStart || 0).split('\n');
|
|
17890
|
+
if (els['editor-position']) els['editor-position'].textContent = before.length + ':' + (before[before.length - 1].length + 1);
|
|
17891
|
+
};
|
|
16621
17892
|
|
|
16622
17893
|
window.requestEditorAssist = async function() {
|
|
16623
17894
|
var ta = els['editor-textarea']; if (!ta || !state.editorPath || !api.editorAssist) return;
|
|
@@ -17223,6 +18494,42 @@ function rememberBrowserUrl(url, force, target) {
|
|
|
17223
18494
|
}
|
|
17224
18495
|
}
|
|
17225
18496
|
|
|
18497
|
+
window.handleFileTreeKey = function(event) {
|
|
18498
|
+
if (!event || event.defaultPrevented || event.isComposing || event.key === 'Process' || event.keyCode === 229 || event.target !== event.currentTarget) return false;
|
|
18499
|
+
var item = event.currentTarget;
|
|
18500
|
+
var root = item.closest('[role="tree"]');
|
|
18501
|
+
if (!root) return false;
|
|
18502
|
+
if (event.key === 'Enter' || event.key === ' ') return window.activateButtonLike(event);
|
|
18503
|
+
if (event.key === 'ArrowRight') {
|
|
18504
|
+
if (item.hasAttribute('aria-expanded') && item.getAttribute('aria-expanded') !== 'true') {
|
|
18505
|
+
event.preventDefault(); item.click(); return true;
|
|
18506
|
+
}
|
|
18507
|
+
var group = item.nextElementSibling;
|
|
18508
|
+
var child = group && group.matches('[role="group"]') ? group.querySelector('[role="treeitem"]') : null;
|
|
18509
|
+
if (child) { event.preventDefault(); child.focus({ preventScroll:true }); return true; }
|
|
18510
|
+
return false;
|
|
18511
|
+
}
|
|
18512
|
+
if (event.key === 'ArrowLeft') {
|
|
18513
|
+
if (item.getAttribute('aria-expanded') === 'true') { event.preventDefault(); item.click(); return true; }
|
|
18514
|
+
var ownerGroup = item.parentElement && item.parentElement.matches('[role="group"]') ? item.parentElement : null;
|
|
18515
|
+
var parentItem = ownerGroup && ownerGroup.previousElementSibling && ownerGroup.previousElementSibling.matches('[role="treeitem"]') ? ownerGroup.previousElementSibling : null;
|
|
18516
|
+
if (parentItem) { event.preventDefault(); parentItem.focus({ preventScroll:true }); return true; }
|
|
18517
|
+
return false;
|
|
18518
|
+
}
|
|
18519
|
+
var visible = Array.prototype.slice.call(root.querySelectorAll('[role="treeitem"]')).filter(function(node) { return node.getClientRects().length > 0; });
|
|
18520
|
+
var index = visible.indexOf(item);
|
|
18521
|
+
var next = index;
|
|
18522
|
+
if (event.key === 'ArrowDown') next = Math.min(visible.length - 1, index + 1);
|
|
18523
|
+
else if (event.key === 'ArrowUp') next = Math.max(0, index - 1);
|
|
18524
|
+
else if (event.key === 'Home') next = 0;
|
|
18525
|
+
else if (event.key === 'End') next = visible.length - 1;
|
|
18526
|
+
else return false;
|
|
18527
|
+
if (next < 0 || !visible[next]) return false;
|
|
18528
|
+
event.preventDefault();
|
|
18529
|
+
visible[next].focus({ preventScroll:true });
|
|
18530
|
+
return true;
|
|
18531
|
+
};
|
|
18532
|
+
|
|
17226
18533
|
function waitForBrowserCreationFloor() {
|
|
17227
18534
|
var remaining = NEWMARK_BROWSER_MIN_CREATE_DELAY_MS - (Date.now() - newmarkRendererStartedAt);
|
|
17228
18535
|
if (remaining <= 0) return Promise.resolve();
|
|
@@ -17555,7 +18862,8 @@ function applyBackendConversations(items, activeId, workspaceId) {
|
|
|
17555
18862
|
updatedAt: item.updatedAt || '',
|
|
17556
18863
|
pinned: !!item.pinned,
|
|
17557
18864
|
pinnedAt: item.pinnedAt || '',
|
|
17558
|
-
order: Number(item.order || 0)
|
|
18865
|
+
order: Number(item.order || 0),
|
|
18866
|
+
branchCommunication: !!item.branchCommunication
|
|
17559
18867
|
});
|
|
17560
18868
|
}
|
|
17561
18869
|
// A stale list response can arrive between creating a conversation locally
|
|
@@ -17682,16 +18990,26 @@ function renderConversations() {
|
|
|
17682
18990
|
}
|
|
17683
18991
|
var div = document.createElement('div');
|
|
17684
18992
|
div.className = 'conv-item' + (conv.active ? ' active' : '');
|
|
18993
|
+
div.setAttribute('role', 'listitem');
|
|
18994
|
+
div.setAttribute('tabindex', conv.active ? '0' : '-1');
|
|
18995
|
+
div.setAttribute('aria-current', conv.active ? 'true' : 'false');
|
|
17685
18996
|
div.setAttribute('draggable', 'true');
|
|
17686
18997
|
div.setAttribute('data-conversation-id', String(conv.id || ''));
|
|
17687
18998
|
if (runtimeState && ['running', 'stopping', 'force_restarting'].indexOf(String(runtimeState.status || '')) >= 0) div.classList.add('marquee-border');
|
|
17688
18999
|
var runtimeBadge = runtimeState && runtimeState.status && runtimeState.status !== 'idle'
|
|
17689
19000
|
? '<span class="conv-runtime-badge ' + escAttr(String(runtimeState.status)) + '">' + esc(String(runtimeState.status)) + '</span>' : '';
|
|
17690
|
-
|
|
19001
|
+
var branchCommIcon = conv.branchCommunication
|
|
19002
|
+
? '<span class="conv-branch-comm-icon" title="' + escAttr(t('conversation.branchCommunicationBadge')) + '" aria-label="' + escAttr(t('conversation.branchCommunicationBadge')) + '">' + iconSvg('git-branch', t('conversation.branchCommunicationBadge')) + '</span>' : '';
|
|
19003
|
+
var archivePendingKey = currentWorkspaceKey() + '::' + String(conv.id);
|
|
19004
|
+
var archiveBtn = state.conversationArchivePending[archivePendingKey]
|
|
19005
|
+
? '<button class="conv-archive-btn archiving" title="' + escAttr(t('archive.archiving')) + '" disabled><span class="conv-archive-spinner"></span></button>'
|
|
19006
|
+
: '<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>';
|
|
19007
|
+
div.innerHTML = '<span class="conv-summary" title="' + escAttr(String(conv.id || '')) + '">' + esc(displaySummary) + (conv.messageCount ? ' (' + esc(String(conv.messageCount)) + ')' : '') + '</span>' + branchCommIcon + runtimeBadge +
|
|
17691
19008
|
'<button class="conv-rename-btn" onclick="event.stopPropagation();window.editConversationName(' + i + ')" title="' + escAttr(t('conversation.rename')) + '">' + iconOnly('pencil', t('conversation.rename')) + '</button>' +
|
|
17692
|
-
|
|
19009
|
+
archiveBtn +
|
|
17693
19010
|
'<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
19011
|
div.onclick = function(idx) { return function() { window.switchConversation(idx); }; }(i);
|
|
19012
|
+
div.addEventListener('keydown', window.handleConversationKey);
|
|
17695
19013
|
div.addEventListener('dragstart', function(event) {
|
|
17696
19014
|
this.classList.add('dragging');
|
|
17697
19015
|
if (event.dataTransfer) { event.dataTransfer.effectAllowed = 'move'; event.dataTransfer.setData('text/plain', this.getAttribute('data-conversation-id') || ''); }
|
|
@@ -17721,6 +19039,30 @@ function renderConversations() {
|
|
|
17721
19039
|
updateWorkspaceGate();
|
|
17722
19040
|
}
|
|
17723
19041
|
|
|
19042
|
+
window.handleConversationKey = function(event) {
|
|
19043
|
+
if (!event || event.defaultPrevented || event.isComposing || event.key === 'Process' || event.keyCode === 229 || event.target !== event.currentTarget) return false;
|
|
19044
|
+
if (event.key === 'Enter' || event.key === ' ') return window.activateButtonLike(event);
|
|
19045
|
+
var items = Array.prototype.slice.call(document.querySelectorAll('#conversation-list .conv-item'));
|
|
19046
|
+
var index = items.indexOf(event.currentTarget);
|
|
19047
|
+
if (index < 0 || !items.length) return false;
|
|
19048
|
+
var next = index;
|
|
19049
|
+
if (event.key === 'ArrowDown') next = (index + 1) % items.length;
|
|
19050
|
+
else if (event.key === 'ArrowUp') next = (index - 1 + items.length) % items.length;
|
|
19051
|
+
else if (event.key === 'Home') next = 0;
|
|
19052
|
+
else if (event.key === 'End') next = items.length - 1;
|
|
19053
|
+
else return false;
|
|
19054
|
+
event.preventDefault();
|
|
19055
|
+
var nextId = items[next].getAttribute('data-conversation-id');
|
|
19056
|
+
items[next].click();
|
|
19057
|
+
requestAnimationFrame(function() {
|
|
19058
|
+
var replacement = Array.prototype.slice.call(document.querySelectorAll('#conversation-list .conv-item')).find(function(item) {
|
|
19059
|
+
return item.getAttribute('data-conversation-id') === nextId;
|
|
19060
|
+
});
|
|
19061
|
+
if (replacement) replacement.focus({ preventScroll:true });
|
|
19062
|
+
});
|
|
19063
|
+
return true;
|
|
19064
|
+
};
|
|
19065
|
+
|
|
17724
19066
|
window.newConversationOld = function() {
|
|
17725
19067
|
var id = 'conv-' + Date.now();
|
|
17726
19068
|
var summary = t('left.newChat') + ' ' + (state.conversations.length + 1);
|
|
@@ -17754,7 +19096,7 @@ window.archiveConvOld = function(idx) {
|
|
|
17754
19096
|
}
|
|
17755
19097
|
};
|
|
17756
19098
|
|
|
17757
|
-
window.newConversation = function(workspaceReference) {
|
|
19099
|
+
window.newConversation = function(workspaceReference, branchCommunication) {
|
|
17758
19100
|
if (workspaceReference && workspaceReference !== state.currentWorkspaceId) {
|
|
17759
19101
|
window.selectWorkspace(workspaceReference);
|
|
17760
19102
|
}
|
|
@@ -17784,6 +19126,13 @@ window.newConversation = function(workspaceReference) {
|
|
|
17784
19126
|
if (createdWorkspaceKey !== currentWorkspaceKey() || id !== String(activeConversationId() || 'default')) return;
|
|
17785
19127
|
state.activeBackendConversationId = String((s && s.conversationId) || id);
|
|
17786
19128
|
if (s) applyConversationSnapshot(s, id);
|
|
19129
|
+
if (branchCommunication && api.setConversationBranchCommunication) {
|
|
19130
|
+
api.setConversationBranchCommunication(target, true).then(function() {
|
|
19131
|
+
var convsNow = currentWorkspaceConversations();
|
|
19132
|
+
var created = convsNow.find(function(item){ return String(item && item.id) === id; });
|
|
19133
|
+
if (created) { created.branchCommunication = true; renderConversations(); }
|
|
19134
|
+
}).catch(function(){});
|
|
19135
|
+
}
|
|
17787
19136
|
}).then(function() {
|
|
17788
19137
|
if (createdWorkspaceKey !== currentWorkspaceKey() || id !== String(activeConversationId() || 'default')) return;
|
|
17789
19138
|
state.foregroundConversationHoldId = '';
|
|
@@ -17810,6 +19159,7 @@ window.showNewConversationPage = function() {
|
|
|
17810
19159
|
var html = '<div style="display:flex;flex-direction:column;gap:12px;padding:4px 2px;">' +
|
|
17811
19160
|
'<div style="font-size:12px;color:var(--text-dim);line-height:1.5;">' + esc(t('workspace.newConversationDesc')) + '</div>' +
|
|
17812
19161
|
'<div class="auto-input-group"><label>' + esc(t('status.workspace')) + '</label><select id="new-conv-ws">' + options + '</select></div>' +
|
|
19162
|
+
'<div class="auto-input-group checkbox-row"><label><input type="checkbox" id="new-conv-branch-comm"><span>' + esc(t('conversation.branchCommunication')) + '</span></label></div>' +
|
|
17813
19163
|
'<div style="display:flex;gap:8px;">' +
|
|
17814
19164
|
'<button class="sec-btn primary" style="flex:1;" onclick="window.doNewConversationFromPage()">' + esc(t('workspace.createConversation')) + '</button>' +
|
|
17815
19165
|
'<button class="sec-btn" style="flex:1;" onclick="window.showNewWorkspaceDialog()">' + esc(t('workspace.createAction')) + '</button>' +
|
|
@@ -17826,11 +19176,13 @@ window.doNewConversationFromPage = function() {
|
|
|
17826
19176
|
window.showNewWorkspaceDialog();
|
|
17827
19177
|
return;
|
|
17828
19178
|
}
|
|
19179
|
+
var branchComm = document.getElementById('new-conv-branch-comm');
|
|
19180
|
+
var branchCommunication = !!(branchComm && branchComm.checked);
|
|
17829
19181
|
window.switchToWorkspace(identity).then(function(ws) {
|
|
17830
19182
|
state.currentWorkspace = (ws && ws.name) || state.currentWorkspace;
|
|
17831
19183
|
state.currentWorkspaceId = workspaceIdentity(ws) || state.currentWorkspaceId || identity;
|
|
17832
19184
|
window.closeSubWin();
|
|
17833
|
-
window.newConversation(state.currentWorkspaceId);
|
|
19185
|
+
window.newConversation(state.currentWorkspaceId, branchCommunication);
|
|
17834
19186
|
}).catch(function(err) {
|
|
17835
19187
|
showUiNotice(t('workspace.selectAction') + ': ' + err.message, 'error', 'workspace-new-conversation-' + identity);
|
|
17836
19188
|
});
|
|
@@ -17951,26 +19303,45 @@ window.archiveConv = function(conversationId) {
|
|
|
17951
19303
|
orderIds: rollbackOrder,
|
|
17952
19304
|
chatHtml: priorActiveId === targetId && els['chat-area'] ? els['chat-area'].innerHTML : ''
|
|
17953
19305
|
};
|
|
17954
|
-
|
|
17955
|
-
if (!convs.length) convs.push({ id: 'default', summary: t('workspace.defaultConversation'), archived: false, active: true });
|
|
17956
|
-
var nextActiveId = priorActiveId && priorActiveId !== targetId ? priorActiveId : String(convs[Math.min(idx, convs.length - 1)].id || 'default');
|
|
17957
|
-
var nextActiveIndex = Math.max(0, convs.findIndex(function(item) { return String(item && item.id || '') === nextActiveId; }));
|
|
17958
|
-
for (var i = 0; i < convs.length; i++) convs[i].active = i === nextActiveIndex;
|
|
17959
|
-
state.workspaceActiveConversation[workspaceKey] = nextActiveIndex;
|
|
17960
|
-
state.activeConversation = nextActiveIndex;
|
|
17961
|
-
state.conversations = convs;
|
|
17962
|
-
if (priorActiveId === targetId) {
|
|
17963
|
-
state.activeBackendConversationId = nextActiveId;
|
|
17964
|
-
if (els['chat-area']) els['chat-area'].innerHTML = '';
|
|
17965
|
-
}
|
|
17966
|
-
setConversationRuntimeState(targetRuntime, 'idle', '');
|
|
17967
|
-
setWorking(!!runningConversationRecord(activeConversationId()));
|
|
19306
|
+
// 归档中:不立即剔除行,按钮转圈等待;后端完成归档后再剔除前端。
|
|
17968
19307
|
renderConversations();
|
|
17969
|
-
if (priorActiveId === targetId) scheduleConversationArchiveActiveSync(workspaceKey);
|
|
17970
19308
|
var archivePromise = api.archive ? api.archive(targetRuntime) : Promise.reject(new Error('Archive API unavailable'));
|
|
17971
19309
|
archivePromise.then(function(receipt) {
|
|
17972
19310
|
if (!receipt || receipt.ok !== true) throw new Error((receipt && receipt.error) || 'Archive failed');
|
|
17973
19311
|
delete state.conversationArchivePending[pendingKey];
|
|
19312
|
+
// 后端完成归档:现在才剔除前端行 + 切换 active + 清理 Flow takeover。
|
|
19313
|
+
var currentConvs = currentWorkspaceConversations();
|
|
19314
|
+
var currentIdx = currentConvs.findIndex(function(item) { return String(item && item.id || 'default') === targetId; });
|
|
19315
|
+
if (currentIdx >= 0) currentConvs.splice(currentIdx, 1);
|
|
19316
|
+
if (!currentConvs.length) currentConvs.push({ id: 'default', summary: t('workspace.defaultConversation'), archived: false, active: true });
|
|
19317
|
+
var nextActiveId = priorActiveId && priorActiveId !== targetId ? priorActiveId : String(currentConvs[Math.min(Math.max(currentIdx, 0), currentConvs.length - 1)].id || 'default');
|
|
19318
|
+
var nextActiveIndex = Math.max(0, currentConvs.findIndex(function(item) { return String(item && item.id || '') === nextActiveId; }));
|
|
19319
|
+
for (var i = 0; i < currentConvs.length; i++) currentConvs[i].active = i === nextActiveIndex;
|
|
19320
|
+
state.workspaceActiveConversation[workspaceKey] = nextActiveIndex;
|
|
19321
|
+
state.activeConversation = nextActiveIndex;
|
|
19322
|
+
state.conversations = currentConvs;
|
|
19323
|
+
if (priorActiveId === targetId) {
|
|
19324
|
+
state.activeBackendConversationId = nextActiveId;
|
|
19325
|
+
if (els['chat-area']) els['chat-area'].innerHTML = '';
|
|
19326
|
+
}
|
|
19327
|
+
if (state.flowTakeovers) {
|
|
19328
|
+
var archivedFlowKey = runtimeKeyFor(targetRuntime.workspaceId, targetRuntime.conversationId);
|
|
19329
|
+
var archivedFlowRecord = state.flowTakeovers[archivedFlowKey];
|
|
19330
|
+
if (archivedFlowRecord) {
|
|
19331
|
+
archivedFlowRecord.running = false;
|
|
19332
|
+
archivedFlowRecord.paused = false;
|
|
19333
|
+
archivedFlowRecord.runtimeLease = null;
|
|
19334
|
+
archivedFlowRecord.queueLease = null;
|
|
19335
|
+
delete state.flowTakeovers[archivedFlowKey];
|
|
19336
|
+
}
|
|
19337
|
+
if (priorActiveId === targetId && window.renderFlowTakeover) {
|
|
19338
|
+
window.renderFlowTakeover(false, '', { target: targetRuntime });
|
|
19339
|
+
}
|
|
19340
|
+
}
|
|
19341
|
+
setConversationRuntimeState(targetRuntime, 'idle', '');
|
|
19342
|
+
setWorking(!!runningConversationRecord(activeConversationId()));
|
|
19343
|
+
renderConversations();
|
|
19344
|
+
if (priorActiveId === targetId) scheduleConversationArchiveActiveSync(workspaceKey);
|
|
17974
19345
|
var optimisticArchive = {
|
|
17975
19346
|
id: receipt.fileName,
|
|
17976
19347
|
name: receipt.fileName,
|
|
@@ -17998,10 +19369,8 @@ window.archiveConv = function(conversationId) {
|
|
|
17998
19369
|
scheduleConversationArchiveRefresh(workspaceKey);
|
|
17999
19370
|
}).catch(function(err) {
|
|
18000
19371
|
delete state.conversationArchivePending[pendingKey];
|
|
18001
|
-
//
|
|
18002
|
-
|
|
18003
|
-
// the user's pointer; the next explicit workspace refresh is the only
|
|
18004
|
-
// path allowed to reconcile a failed destructive operation.
|
|
19372
|
+
// 归档失败:恢复按钮,保留行(不再乐观剔除)。
|
|
19373
|
+
renderConversations();
|
|
18005
19374
|
showUiNotice('[Archive] ' + t('workspace.saveFailed') + ': ' + (err.message || String(err)), 'error', 'archive-failed-' + targetId);
|
|
18006
19375
|
});
|
|
18007
19376
|
}
|
|
@@ -18809,37 +20178,117 @@ window.reindexMemoryLab = function() {
|
|
|
18809
20178
|
});
|
|
18810
20179
|
};
|
|
18811
20180
|
|
|
18812
|
-
// === Plugin
|
|
18813
|
-
|
|
18814
|
-
|
|
20181
|
+
// === Plugin / Skills Market ===
|
|
20182
|
+
var PLUGIN_TABS = ['mcp', 'dsh', 'installed', 'market', 'github'];
|
|
20183
|
+
|
|
20184
|
+
function pluginText(key, values) {
|
|
20185
|
+
var output = t(key);
|
|
20186
|
+
Object.keys(values || {}).forEach(function(name) {
|
|
20187
|
+
output = output.replace(new RegExp('\\{' + name + '\\}', 'g'), function() { return String(values[name]); });
|
|
20188
|
+
});
|
|
20189
|
+
return output;
|
|
20190
|
+
}
|
|
20191
|
+
|
|
20192
|
+
function pluginRequestActive(tab, generation) {
|
|
20193
|
+
return generation === state.pluginPanelGeneration
|
|
20194
|
+
&& state.pluginActiveTab === tab
|
|
20195
|
+
&& !!(state.activeSubWindowView && state.activeSubWindowView.name === 'plugins')
|
|
20196
|
+
&& !!(els['sub-win-overlay'] && els['sub-win-overlay'].classList.contains('open'))
|
|
20197
|
+
&& !!document.getElementById('plugin-panel');
|
|
20198
|
+
}
|
|
20199
|
+
|
|
20200
|
+
function pluginPanelState(message, kind, retryCall) {
|
|
20201
|
+
return '<div class="plugin-panel-state' + (kind === 'error' ? ' error' : '') + '" role="' + (kind === 'error' ? 'alert' : 'status') + '"' + (kind === 'loading' ? ' aria-live="polite" aria-busy="true"' : '') + '>' +
|
|
20202
|
+
'<span>' + esc(message) + '</span>' +
|
|
20203
|
+
(retryCall ? '<button type="button" class="sec-btn" onclick="' + retryCall + '">' + esc(t('plugins.retry')) + '</button>' : '') +
|
|
20204
|
+
'</div>';
|
|
20205
|
+
}
|
|
20206
|
+
|
|
20207
|
+
function pluginTabMarkup(tab, label) {
|
|
20208
|
+
var selected = state.pluginActiveTab === tab;
|
|
20209
|
+
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>';
|
|
20210
|
+
}
|
|
20211
|
+
|
|
20212
|
+
window.syncPluginTabs = function(focusTab) {
|
|
20213
|
+
var labels = { mcp: t('plugins.tabMcp'), dsh: t('plugins.tabDsh'), installed: t('plugins.tabSkills'), market: t('plugins.tabMarket'), github: t('plugins.tabGithub') };
|
|
20214
|
+
PLUGIN_TABS.forEach(function(tab) {
|
|
20215
|
+
var button = document.getElementById('plugin-tab-' + tab);
|
|
20216
|
+
if (!button) return;
|
|
20217
|
+
var selected = tab === state.pluginActiveTab;
|
|
20218
|
+
button.classList.toggle('active', selected);
|
|
20219
|
+
button.setAttribute('aria-selected', selected ? 'true' : 'false');
|
|
20220
|
+
button.tabIndex = selected ? 0 : -1;
|
|
20221
|
+
button.textContent = labels[tab];
|
|
20222
|
+
});
|
|
20223
|
+
var tablist = document.querySelector('.plugin-tabs[role="tablist"]');
|
|
20224
|
+
if (tablist) tablist.setAttribute('aria-label', t('plugins.title'));
|
|
20225
|
+
if (els['sub-win-title']) els['sub-win-title'].textContent = t('plugins.title');
|
|
20226
|
+
var panel = document.getElementById('plugin-panel');
|
|
20227
|
+
if (panel) panel.setAttribute('aria-labelledby', 'plugin-tab-' + state.pluginActiveTab);
|
|
20228
|
+
if (focusTab) {
|
|
20229
|
+
var activeButton = document.getElementById('plugin-tab-' + state.pluginActiveTab);
|
|
20230
|
+
if (activeButton) activeButton.focus({ preventScroll: true });
|
|
20231
|
+
}
|
|
18815
20232
|
};
|
|
18816
20233
|
|
|
18817
|
-
|
|
18818
|
-
|
|
18819
|
-
var
|
|
18820
|
-
|
|
18821
|
-
|
|
18822
|
-
|
|
18823
|
-
|
|
18824
|
-
|
|
18825
|
-
|
|
18826
|
-
|
|
18827
|
-
|
|
18828
|
-
|
|
18829
|
-
|
|
18830
|
-
window.
|
|
18831
|
-
|
|
18832
|
-
|
|
18833
|
-
|
|
18834
|
-
|
|
20234
|
+
window.handlePluginTabKey = function(event) {
|
|
20235
|
+
if (!event || PLUGIN_TABS.indexOf(state.pluginActiveTab) < 0) return;
|
|
20236
|
+
var index = PLUGIN_TABS.indexOf(state.pluginActiveTab);
|
|
20237
|
+
if (event.key === 'ArrowRight') index = (index + 1) % PLUGIN_TABS.length;
|
|
20238
|
+
else if (event.key === 'ArrowLeft') index = (index - 1 + PLUGIN_TABS.length) % PLUGIN_TABS.length;
|
|
20239
|
+
else if (event.key === 'Home') index = 0;
|
|
20240
|
+
else if (event.key === 'End') index = PLUGIN_TABS.length - 1;
|
|
20241
|
+
else return;
|
|
20242
|
+
event.preventDefault();
|
|
20243
|
+
window.showPluginList(PLUGIN_TABS[index], { focusTab: true });
|
|
20244
|
+
};
|
|
20245
|
+
|
|
20246
|
+
window.selectPluginTab = function(tab) {
|
|
20247
|
+
window.showPluginList(tab, { focusTab: false });
|
|
20248
|
+
};
|
|
20249
|
+
|
|
20250
|
+
window.showPluginList = function(tab, options) {
|
|
20251
|
+
var requested = PLUGIN_TABS.indexOf(tab) >= 0 ? tab : (PLUGIN_TABS.indexOf(state.pluginActiveTab) >= 0 ? state.pluginActiveTab : 'mcp');
|
|
20252
|
+
var overlayOpen = !!(els['sub-win-overlay'] && els['sub-win-overlay'].classList.contains('open'));
|
|
20253
|
+
var pluginOpen = overlayOpen && state.activeSubWindowView && state.activeSubWindowView.name === 'plugins' && !!document.getElementById('plugin-panel');
|
|
20254
|
+
state.pluginActiveTab = requested;
|
|
20255
|
+
state.pluginPanelGeneration++;
|
|
20256
|
+
if (!pluginOpen) {
|
|
20257
|
+
var html = '<div class="settings-tabs plugin-tabs" role="tablist" aria-label="' + escAttr(t('plugins.title')) + '">' +
|
|
20258
|
+
pluginTabMarkup('mcp', t('plugins.tabMcp')) +
|
|
20259
|
+
pluginTabMarkup('dsh', t('plugins.tabDsh')) +
|
|
20260
|
+
pluginTabMarkup('installed', t('plugins.tabSkills')) +
|
|
20261
|
+
pluginTabMarkup('market', t('plugins.tabMarket')) +
|
|
20262
|
+
pluginTabMarkup('github', t('plugins.tabGithub')) +
|
|
20263
|
+
'</div><div id="plugin-panel" class="plugin-panel" role="tabpanel" tabindex="0" aria-labelledby="plugin-tab-' + requested + '"></div>';
|
|
20264
|
+
if (overlayOpen && state.activeSubWindowView) {
|
|
20265
|
+
window.openSubWin(t('plugins.title'), html);
|
|
20266
|
+
state.activeSubWindowView = { name: 'plugins', tab: requested };
|
|
20267
|
+
} else {
|
|
20268
|
+
state.activeSubWindowView = { name: 'plugins', tab: requested };
|
|
20269
|
+
window.openSubWin(t('plugins.title'), html);
|
|
20270
|
+
}
|
|
20271
|
+
if (els['sub-win']) els['sub-win'].classList.remove('memory-lab-window');
|
|
20272
|
+
} else {
|
|
20273
|
+
state.activeSubWindowView = { name: 'plugins', tab: requested };
|
|
20274
|
+
}
|
|
20275
|
+
window.syncPluginTabs(!pluginOpen || !!(options && options.focusTab));
|
|
20276
|
+
var panel = document.getElementById('plugin-panel');
|
|
20277
|
+
if (panel) panel.replaceChildren();
|
|
20278
|
+
if (requested === 'mcp') window.renderMcpManager();
|
|
20279
|
+
else if (requested === 'dsh') window.renderDshPlugin();
|
|
20280
|
+
else if (requested === 'market') window.renderSkillsMarket();
|
|
20281
|
+
else if (requested === 'github') window.renderGithubCliPanel();
|
|
18835
20282
|
else window.renderInstalledSkills();
|
|
18836
20283
|
};
|
|
18837
20284
|
|
|
18838
20285
|
window.renderInstalledSkills = function() {
|
|
18839
20286
|
var panel = document.getElementById('plugin-panel');
|
|
18840
|
-
if (!panel) return;
|
|
20287
|
+
if (!panel || state.pluginActiveTab !== 'installed') return;
|
|
20288
|
+
var generation = ++state.pluginPanelGeneration;
|
|
18841
20289
|
var render = function(items) {
|
|
18842
20290
|
state.skills = items || [];
|
|
20291
|
+
if (!pluginRequestActive('installed', generation)) return;
|
|
18843
20292
|
if (!items || !items.length) {
|
|
18844
20293
|
panel.innerHTML = '<div style="font-size:12px;color:var(--text-dim);padding:18px;text-align:center;">' + esc(t('plugins.noInstalled')) + '</div>';
|
|
18845
20294
|
return;
|
|
@@ -18880,14 +20329,15 @@ window.refreshSkillsRuntime = function(next) {
|
|
|
18880
20329
|
|
|
18881
20330
|
window.renderSkillsMarket = function() {
|
|
18882
20331
|
var panel = document.getElementById('plugin-panel');
|
|
18883
|
-
if (!panel) return;
|
|
20332
|
+
if (!panel || state.pluginActiveTab !== 'market') return;
|
|
20333
|
+
var generation = ++state.pluginPanelGeneration;
|
|
18884
20334
|
panel.innerHTML = '<div class="provider-card marquee-border">' + esc(t('plugins.discovering')) + '</div>';
|
|
18885
20335
|
state._skillMarketAll = [];
|
|
18886
20336
|
state._skillMarketSources = [];
|
|
18887
20337
|
var done = 0;
|
|
18888
20338
|
var finish = function() {
|
|
18889
20339
|
done++;
|
|
18890
|
-
if (done >= 2) window.renderSkillsMarketList();
|
|
20340
|
+
if (done >= 2 && pluginRequestActive('market', generation)) window.renderSkillsMarketList();
|
|
18891
20341
|
};
|
|
18892
20342
|
if (api.marketSkillSources) api.marketSkillSources().then(function(sources) {
|
|
18893
20343
|
state._skillMarketSources = sources || [];
|
|
@@ -18901,88 +20351,466 @@ window.renderSkillsMarket = function() {
|
|
|
18901
20351
|
else finish();
|
|
18902
20352
|
};
|
|
18903
20353
|
|
|
20354
|
+
var DSH_OFFICIAL_URLS = {
|
|
20355
|
+
repo: 'https://github.com/deepseek-ai/deepseek-harness',
|
|
20356
|
+
docs: 'https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/user/develop/basic/publish.md',
|
|
20357
|
+
npm: 'https://www.npmjs.com/package/@deepseek-ai/dsh'
|
|
20358
|
+
};
|
|
20359
|
+
|
|
20360
|
+
function dshCollection(value) {
|
|
20361
|
+
if (Array.isArray(value)) return value;
|
|
20362
|
+
if (value && typeof value === 'object') return Object.keys(value).map(function(key) {
|
|
20363
|
+
var item = value[key];
|
|
20364
|
+
if (item && typeof item === 'object' && !Array.isArray(item)) return Object.assign({ name: key }, item);
|
|
20365
|
+
return { name: key, value: item };
|
|
20366
|
+
});
|
|
20367
|
+
return [];
|
|
20368
|
+
}
|
|
20369
|
+
|
|
20370
|
+
function dshDisplayValue(value) {
|
|
20371
|
+
if (value === undefined || value === null || value === '') return t('plugins.dshNotAvailable');
|
|
20372
|
+
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') return String(value);
|
|
20373
|
+
try { return JSON.stringify(value); } catch (_) { return String(value); }
|
|
20374
|
+
}
|
|
20375
|
+
|
|
20376
|
+
function dshUniqueStrings(values) {
|
|
20377
|
+
var seen = Object.create(null);
|
|
20378
|
+
return dshCollection(values).map(function(value) {
|
|
20379
|
+
return typeof value === 'string' ? value : dshDisplayValue(value);
|
|
20380
|
+
}).filter(function(value) {
|
|
20381
|
+
var key = String(value || '');
|
|
20382
|
+
if (!key || seen[key]) return false;
|
|
20383
|
+
seen[key] = true;
|
|
20384
|
+
return true;
|
|
20385
|
+
});
|
|
20386
|
+
}
|
|
20387
|
+
|
|
20388
|
+
function dshListMarkup(items, emptyText, warning) {
|
|
20389
|
+
var values = dshCollection(items);
|
|
20390
|
+
if (!values.length) return '<div class="plugin-empty">' + esc(emptyText || t('plugins.dshNone')) + '</div>';
|
|
20391
|
+
return '<div class="dsh-list">' + values.map(function(item) {
|
|
20392
|
+
var label = item && typeof item === 'object'
|
|
20393
|
+
? (item.name || item.id || item.path || item.file || item.key || dshDisplayValue(item))
|
|
20394
|
+
: item;
|
|
20395
|
+
var detail = item && typeof item === 'object' ? (item.version || item.source || item.value || item.reason || '') : '';
|
|
20396
|
+
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>';
|
|
20397
|
+
}).join('') + '</div>';
|
|
20398
|
+
}
|
|
20399
|
+
|
|
20400
|
+
function dshLayerMarkup(profile) {
|
|
20401
|
+
var layers = dshCollection(profile && profile.layers);
|
|
20402
|
+
if (!layers.length) return '<div class="plugin-empty">' + esc(t('plugins.dshNone')) + '</div>';
|
|
20403
|
+
return '<div class="dsh-list">' + layers.map(function(layer, index) {
|
|
20404
|
+
var kind = layer && layer.kind ? String(layer.kind) : 'layer';
|
|
20405
|
+
var order = Number.isFinite(Number(layer && layer.order)) ? Number(layer.order) + 1 : index + 1;
|
|
20406
|
+
var file = layer && (layer.path || layer.file) || '';
|
|
20407
|
+
return '<div class="dsh-list-item"><strong>' + esc(order + '. ' + kind + (layer && layer.name ? ' · ' + layer.name : '')) + '</strong>' +
|
|
20408
|
+
(file ? '<div class="provider-meta">' + esc(redactSensitiveText(file)) + '</div>' : '') + '</div>';
|
|
20409
|
+
}).join('') + '</div>';
|
|
20410
|
+
}
|
|
20411
|
+
|
|
20412
|
+
window.openDshOfficial = function(kind) {
|
|
20413
|
+
var url = DSH_OFFICIAL_URLS[kind];
|
|
20414
|
+
if (!url || !api.openWebUrl) {
|
|
20415
|
+
showUiNotice(t('plugins.dshUnavailable'), 'error', 'dsh-web-url');
|
|
20416
|
+
return;
|
|
20417
|
+
}
|
|
20418
|
+
var generation = state.pluginPanelGeneration;
|
|
20419
|
+
Promise.resolve(api.openWebUrl(url)).then(function(result) {
|
|
20420
|
+
if (result && (result.ok === false || result.success === false || result.error)) throw new Error(result.error || t('plugins.dshUnavailable'));
|
|
20421
|
+
}).catch(function(error) {
|
|
20422
|
+
if (pluginRequestActive('dsh', generation)) showUiNotice(error && error.message ? error.message : String(error), 'error', 'dsh-web-url');
|
|
20423
|
+
});
|
|
20424
|
+
};
|
|
20425
|
+
|
|
20426
|
+
window.renderDshPlugin = function() {
|
|
20427
|
+
var panel = document.getElementById('plugin-panel');
|
|
20428
|
+
if (!panel || state.pluginActiveTab !== 'dsh') return;
|
|
20429
|
+
var generation = ++state.pluginPanelGeneration;
|
|
20430
|
+
panel.innerHTML = pluginPanelState(t('plugins.dshScanning'), 'loading');
|
|
20431
|
+
if (!api.discoverDshCompatibility) {
|
|
20432
|
+
panel.innerHTML = pluginPanelState(t('plugins.dshUnavailable'), 'error');
|
|
20433
|
+
return;
|
|
20434
|
+
}
|
|
20435
|
+
Promise.resolve(api.discoverDshCompatibility()).then(function(snapshot) {
|
|
20436
|
+
if (!pluginRequestActive('dsh', generation)) return;
|
|
20437
|
+
state.dshCompatibility = snapshot && typeof snapshot === 'object' ? snapshot : {};
|
|
20438
|
+
window.renderDshPluginContent();
|
|
20439
|
+
}).catch(function(error) {
|
|
20440
|
+
if (!pluginRequestActive('dsh', generation)) return;
|
|
20441
|
+
var message = t('plugins.dshLoadError') + (error && error.message ? ' ' + error.message : '');
|
|
20442
|
+
panel.innerHTML = pluginPanelState(message, 'error', 'window.renderDshPlugin()');
|
|
20443
|
+
});
|
|
20444
|
+
};
|
|
20445
|
+
|
|
20446
|
+
window.renderDshPluginContent = function() {
|
|
20447
|
+
var panel = document.getElementById('plugin-panel');
|
|
20448
|
+
if (!panel || state.pluginActiveTab !== 'dsh') return;
|
|
20449
|
+
var dsh = state.dshCompatibility || {};
|
|
20450
|
+
var cli = dsh.cli && typeof dsh.cli === 'object' ? dsh.cli : {};
|
|
20451
|
+
var pkg = dsh.package && typeof dsh.package === 'object' ? dsh.package : {};
|
|
20452
|
+
var update = dsh.update && typeof dsh.update === 'object' ? dsh.update : {};
|
|
20453
|
+
var cliPath = cli.path || cli.executable || cli.commandPath || dsh.cliPath || '';
|
|
20454
|
+
var cliVersion = cli.version || dsh.cliVersion || '';
|
|
20455
|
+
var packageVersion = pkg.version || (cli.package && cli.package.version) || cli.packageVersion || dsh.packageVersion || '';
|
|
20456
|
+
var updateChannel = update.channel || update.tag || dsh.updateChannel || '';
|
|
20457
|
+
var updateLocked = update.locked === true || update.versionLocked === true || update.isLocked === true;
|
|
20458
|
+
if (String(updateChannel).toLowerCase() === 'latest' && !updateLocked) updateChannel = t('plugins.dshLatestChannel');
|
|
20459
|
+
var candidates = dshCollection(dsh.mcpCandidates);
|
|
20460
|
+
var configFiles = dshCollection(dsh.configFiles);
|
|
20461
|
+
dshCollection(dsh.profiles).forEach(function(profile) {
|
|
20462
|
+
if (profile && typeof profile === 'object') configFiles = configFiles.concat(dshCollection(profile.configFiles));
|
|
20463
|
+
});
|
|
20464
|
+
configFiles = dshUniqueStrings(configFiles);
|
|
20465
|
+
var html = '<section class="dsh-hero" id="dsh-hero" aria-labelledby="dsh-title">' +
|
|
20466
|
+
'<div class="dsh-hero-head"><div class="dsh-hero-copy"><div class="dsh-title" id="dsh-title">' + esc(t('plugins.dshTitle')) + '</div>' +
|
|
20467
|
+
'<div class="dsh-description">' + esc(t('plugins.dshHelp')) + '</div></div><span class="plugin-status-badge preview">' + esc(t('plugins.dshPreview')) + '</span></div>' +
|
|
20468
|
+
'<div class="dsh-actions"><button type="button" class="sec-btn primary" id="dsh-rescan" onclick="window.renderDshPlugin()">' + esc(t('plugins.dshRescan')) + '</button>' +
|
|
20469
|
+
'<button type="button" class="sec-btn" id="dsh-official-repo" onclick="window.openDshOfficial(\'repo\')">' + esc(t('plugins.dshOfficialRepo')) + '</button>' +
|
|
20470
|
+
'<button type="button" class="sec-btn" id="dsh-official-docs" onclick="window.openDshOfficial(\'docs\')">' + esc(t('plugins.dshOfficialDocs')) + '</button>' +
|
|
20471
|
+
'<button type="button" class="sec-btn" id="dsh-official-npm" onclick="window.openDshOfficial(\'npm\')">' + esc(t('plugins.dshOfficialNpm')) + '</button></div></section>';
|
|
20472
|
+
html += '<div class="dsh-grid">' +
|
|
20473
|
+
'<section class="dsh-card" id="dsh-cli-card"><div class="dsh-card-title">' + esc(t('plugins.dshCli')) + '</div><dl class="dsh-kv">' +
|
|
20474
|
+
'<dt>' + esc(t('plugins.dshCliPath')) + '</dt><dd id="dsh-cli-path">' + esc(redactSensitiveText(dshDisplayValue(cliPath))) + '</dd>' +
|
|
20475
|
+
'<dt>' + esc(t('plugins.dshCliVersion')) + '</dt><dd id="dsh-cli-version">' + esc(dshDisplayValue(cliVersion)) + '</dd>' +
|
|
20476
|
+
'<dt>' + esc(t('plugins.dshPackageVersion')) + '</dt><dd id="dsh-package-version">' + esc(dshDisplayValue(packageVersion)) + '</dd></dl></section>' +
|
|
20477
|
+
'<section class="dsh-card" id="dsh-runtime-card"><div class="dsh-card-title">' + esc(t('plugins.dshReadonly')) + '</div><dl class="dsh-kv">' +
|
|
20478
|
+
'<dt>' + esc(t('plugins.dshHome')) + '</dt><dd id="dsh-home">' + esc(redactSensitiveText(dshDisplayValue(dsh.dshHome || dsh.home))) + '</dd>' +
|
|
20479
|
+
'<dt>' + esc(t('plugins.dshHomeSource')) + '</dt><dd id="dsh-home-source">' + esc(redactSensitiveText(dshDisplayValue(dsh.dshHomeSource || dsh.homeSource || (dsh.home && dsh.home.source)))) + '</dd>' +
|
|
20480
|
+
'<dt>' + esc(t('plugins.dshUpdateChannel')) + '</dt><dd id="dsh-update-channel">' + esc(dshDisplayValue(updateChannel)) + '</dd></dl>' +
|
|
20481
|
+
'<div class="dsh-description">' + esc(t('plugins.dshReadonlyDetail')) + '</div></section>' +
|
|
20482
|
+
'<section class="dsh-card" id="dsh-profiles-card"><div class="dsh-card-title">' + esc(t('plugins.dshProfiles')) + '</div>' + dshListMarkup(dsh.profiles) + '</section>' +
|
|
20483
|
+
'<section class="dsh-card" id="dsh-bundles-card"><div class="dsh-card-title">' + esc(t('plugins.dshBundles')) + '</div>' + dshListMarkup(dsh.bundles) + '</section>' +
|
|
20484
|
+
'<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>' +
|
|
20485
|
+
'<section class="dsh-card" id="dsh-unknown-keys-card"><div class="dsh-card-title">' + esc(t('plugins.dshUnknownKeys')) + '</div>' + dshListMarkup(dsh.unknownKeys) + '</section></div>';
|
|
20486
|
+
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>';
|
|
20487
|
+
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>';
|
|
20488
|
+
dshCollection(dsh.profiles).forEach(function(profile) {
|
|
20489
|
+
html += '<div class="dsh-layer-profile"><div class="plugin-section-title">' + esc(profile && (profile.name || profile.source) || t('plugins.dshNotAvailable')) + '</div>' + dshLayerMarkup(profile) + '</div>';
|
|
20490
|
+
});
|
|
20491
|
+
var homeFiles = dshCollection(dsh.homeConfigFiles);
|
|
20492
|
+
if (homeFiles.length) html += '<div class="dsh-layer-profile"><div class="plugin-section-title">' + esc(t('plugins.dshHomePatches')) + '</div>' + dshListMarkup(homeFiles) + '</div>';
|
|
20493
|
+
html += '<div class="mcp-field-help">' + esc(t('plugins.dshUpdateability')) + '</div></section>';
|
|
20494
|
+
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>' +
|
|
20495
|
+
'<div class="mcp-field-help">' + esc(t('plugins.mcpCandidateHelp')) + '</div>';
|
|
20496
|
+
if (!candidates.length) html += '<div class="plugin-empty">' + esc(t('plugins.dshNone')) + '</div>';
|
|
20497
|
+
candidates.forEach(function(candidate, index) {
|
|
20498
|
+
var name = candidate && (candidate.name || candidate.id) || ('MCP ' + (index + 1));
|
|
20499
|
+
var source = candidate && (candidate.source || candidate.path) || '';
|
|
20500
|
+
var reason = candidate && candidate.reason || '';
|
|
20501
|
+
var importable = !!(candidate && candidate.importable && candidate.template);
|
|
20502
|
+
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) +
|
|
20503
|
+
'<span class="plugin-status-badge">' + esc(importable ? t('plugins.mcpReviewImport') : t('plugins.mcpReadonly')) + '</span></div>' +
|
|
20504
|
+
'<div class="mcp-server-meta">' + esc(redactSensitiveText(dshDisplayValue(source))) + '</div>' +
|
|
20505
|
+
(reason ? '<div class="mcp-server-meta">' + esc(redactSensitiveText(dshDisplayValue(reason))) + '</div>' : '') + '</div>' +
|
|
20506
|
+
(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>';
|
|
20507
|
+
});
|
|
20508
|
+
html += '</section>';
|
|
20509
|
+
panel.innerHTML = html;
|
|
20510
|
+
};
|
|
20511
|
+
|
|
20512
|
+
function newMcpDraft(input, source) {
|
|
20513
|
+
input = input && typeof input === 'object' ? input : {};
|
|
20514
|
+
var transport = input.transport === 'http' ? 'http' : 'stdio';
|
|
20515
|
+
return {
|
|
20516
|
+
id: input.id || '',
|
|
20517
|
+
source: source || 'add',
|
|
20518
|
+
name: String(input.name || ''),
|
|
20519
|
+
transport: transport,
|
|
20520
|
+
command: String(input.command || ''),
|
|
20521
|
+
url: String(input.url || ''),
|
|
20522
|
+
argsText: JSON.stringify(Array.isArray(input.args) ? input.args : [], null, 2),
|
|
20523
|
+
cwd: String(input.cwd || ''),
|
|
20524
|
+
envText: input.env && typeof input.env === 'object' ? JSON.stringify(input.env, null, 2) : '',
|
|
20525
|
+
headersText: input.headers && typeof input.headers === 'object' ? JSON.stringify(input.headers, null, 2) : '',
|
|
20526
|
+
enabled: source === 'candidate' ? false : input.enabled !== false,
|
|
20527
|
+
envKeys: Array.isArray(input.envKeys) ? input.envKeys.slice() : [],
|
|
20528
|
+
headerKeys: Array.isArray(input.headerKeys) ? input.headerKeys.slice() : []
|
|
20529
|
+
};
|
|
20530
|
+
}
|
|
20531
|
+
|
|
20532
|
+
window.reviewDshMcpCandidate = function(index) {
|
|
20533
|
+
var candidates = dshCollection(state.dshCompatibility && state.dshCompatibility.mcpCandidates);
|
|
20534
|
+
var candidate = candidates[index];
|
|
20535
|
+
if (!candidate || !candidate.importable || !candidate.template) return;
|
|
20536
|
+
state.mcpEditingId = '';
|
|
20537
|
+
state.mcpDraft = newMcpDraft(Object.assign({}, candidate.template, {
|
|
20538
|
+
enabled: false,
|
|
20539
|
+
envKeys: Array.isArray(candidate.envKeys) ? candidate.envKeys : [],
|
|
20540
|
+
headerKeys: Array.isArray(candidate.headerKeys) ? candidate.headerKeys : []
|
|
20541
|
+
}), 'candidate');
|
|
20542
|
+
state.mcpFormFocusRequested = true;
|
|
20543
|
+
window.showPluginList('mcp');
|
|
20544
|
+
};
|
|
20545
|
+
|
|
18904
20546
|
window.renderMcpManager = function() {
|
|
18905
20547
|
var panel = document.getElementById('plugin-panel');
|
|
18906
|
-
if (!panel) return;
|
|
18907
|
-
|
|
20548
|
+
if (!panel || state.pluginActiveTab !== 'mcp') return;
|
|
20549
|
+
var generation = ++state.pluginPanelGeneration;
|
|
20550
|
+
panel.innerHTML = pluginPanelState(t('plugins.mcpRefreshing'), 'loading');
|
|
18908
20551
|
if (!api.listMcpServers) {
|
|
18909
|
-
panel.innerHTML =
|
|
20552
|
+
panel.innerHTML = pluginPanelState(t('plugins.mcpUnavailable'), 'error');
|
|
18910
20553
|
return;
|
|
18911
20554
|
}
|
|
18912
|
-
api.listMcpServers().then(function(result) {
|
|
20555
|
+
Promise.resolve(api.listMcpServers()).then(function(result) {
|
|
20556
|
+
if (!pluginRequestActive('mcp', generation)) return;
|
|
18913
20557
|
state.mcpServers = Array.isArray(result && result.servers) ? result.servers : [];
|
|
18914
20558
|
state.mcpDiscovered = Array.isArray(result && result.discovered) ? result.discovered : [];
|
|
18915
20559
|
window.renderMcpManagerContent();
|
|
18916
20560
|
}).catch(function(error) {
|
|
18917
|
-
|
|
20561
|
+
if (!pluginRequestActive('mcp', generation)) return;
|
|
20562
|
+
var message = t('plugins.mcpLoadError') + (error && error.message ? ' ' + error.message : '');
|
|
20563
|
+
panel.innerHTML = pluginPanelState(message, 'error', 'window.renderMcpManager()');
|
|
18918
20564
|
});
|
|
18919
20565
|
};
|
|
18920
20566
|
|
|
20567
|
+
function mcpSearchMatch(server, query) {
|
|
20568
|
+
server = server || {};
|
|
20569
|
+
if (!query) return true;
|
|
20570
|
+
var text = [server.name, server.transport, server.command, server.url, server.plugin, server.ecosystem, server.root]
|
|
20571
|
+
.concat(server.args || []).join(' ').toLowerCase();
|
|
20572
|
+
return text.indexOf(query) >= 0;
|
|
20573
|
+
}
|
|
20574
|
+
|
|
20575
|
+
function mcpSecretHelp(keys, keyName) {
|
|
20576
|
+
return keys && keys.length
|
|
20577
|
+
? pluginText(keyName, { keys: keys.join(', ') })
|
|
20578
|
+
: t('plugins.mcpNoSavedKeys');
|
|
20579
|
+
}
|
|
20580
|
+
|
|
20581
|
+
function renderMcpForm() {
|
|
20582
|
+
var draft = state.mcpDraft;
|
|
20583
|
+
if (!draft) return '';
|
|
20584
|
+
var pending = !!state.mcpMutationPending;
|
|
20585
|
+
var titleKey = draft.source === 'candidate' ? 'plugins.mcpReviewTitle' : (draft.id ? 'plugins.mcpEditTitle' : 'plugins.mcpAddTitle');
|
|
20586
|
+
var stdio = draft.transport !== 'http';
|
|
20587
|
+
return '<section class="mcp-form-card" id="mcp-form" aria-labelledby="mcp-form-title" aria-busy="' + (pending ? 'true' : 'false') + '">' +
|
|
20588
|
+
'<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>' +
|
|
20589
|
+
'<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>' +
|
|
20590
|
+
'<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>' +
|
|
20591
|
+
'<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>' +
|
|
20592
|
+
'<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>' +
|
|
20593
|
+
'<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>' +
|
|
20594
|
+
'<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>' +
|
|
20595
|
+
'<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>' +
|
|
20596
|
+
'<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>' +
|
|
20597
|
+
'<label class="mcp-enabled-check" for="mcp-enabled"><input id="mcp-enabled" type="checkbox"' + (draft.enabled ? ' checked' : '') + (pending ? ' disabled' : '') + '> ' + esc(t('plugins.mcpEnabled')) + '</label>' +
|
|
20598
|
+
'<div class="mcp-form-actions"><button type="button" class="sec-btn" id="mcp-cancel" onclick="window.cancelMcpForm()"' + (pending ? ' disabled' : '') + '>' + esc(t('common.cancel')) + '</button>' +
|
|
20599
|
+
'<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>';
|
|
20600
|
+
}
|
|
20601
|
+
|
|
18921
20602
|
window.renderMcpManagerContent = function() {
|
|
18922
20603
|
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>';
|
|
20604
|
+
if (!panel || state.pluginActiveTab !== 'mcp') return;
|
|
20605
|
+
var allServers = state.mcpServers || [];
|
|
20606
|
+
var allDiscovered = state.mcpDiscovered || [];
|
|
20607
|
+
var query = String(state.mcpSearchQuery || '').trim().toLowerCase();
|
|
20608
|
+
var servers = allServers.filter(function(server) { return mcpSearchMatch(server, query); });
|
|
20609
|
+
var discovered = allDiscovered.filter(function(server) { return mcpSearchMatch(server, query); });
|
|
20610
|
+
var pending = !!state.mcpMutationPending;
|
|
20611
|
+
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>' +
|
|
20612
|
+
'<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)">' +
|
|
20613
|
+
'<button type="button" class="sec-btn" id="mcp-refresh" onclick="window.renderMcpManager()"' + (pending ? ' disabled' : '') + '>' + esc(t('plugins.mcpRefresh')) + '</button>' +
|
|
20614
|
+
'<button type="button" class="sec-btn primary" id="mcp-add" onclick="window.openMcpAddForm()"' + (pending ? ' disabled' : '') + '>' + esc(t('plugins.mcpAdd')) + '</button></div>';
|
|
20615
|
+
html += renderMcpForm();
|
|
20616
|
+
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>';
|
|
20617
|
+
if (!allServers.length) html += '<div class="plugin-empty">' + esc(t('plugins.mcpStoredEmpty')) + '</div>';
|
|
20618
|
+
else if (!servers.length) html += '<div class="plugin-empty">' + esc(t('plugins.mcpNoMatch')) + '</div>';
|
|
18939
20619
|
servers.forEach(function(server) {
|
|
18940
|
-
var
|
|
18941
|
-
|
|
18942
|
-
|
|
18943
|
-
'<
|
|
18944
|
-
'<
|
|
20620
|
+
var index = allServers.indexOf(server);
|
|
20621
|
+
var endpoint = server.transport === 'http' ? server.url : [server.command].concat(server.args || []).filter(Boolean).join(' ');
|
|
20622
|
+
html += '<div class="mcp-server-row" data-mcp-index="' + index + '"><div class="mcp-server-copy"><div class="mcp-server-title">' + esc(server.name || '') +
|
|
20623
|
+
'<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>' +
|
|
20624
|
+
'<div class="mcp-server-meta">' + esc(endpoint || '') + '</div></div><div class="mcp-row-actions">' +
|
|
20625
|
+
'<button type="button" class="sec-btn" onclick="window.editMcpServerAt(' + index + ')"' + (pending ? ' disabled' : '') + '>' + esc(t('common.edit')) + '</button>' +
|
|
20626
|
+
'<button type="button" class="sec-btn" onclick="window.toggleMcpServerAt(' + index + ',' + (!server.enabled) + ')"' + (pending ? ' disabled' : '') + '>' + esc(server.enabled ? t('common.disable') : t('common.enable')) + '</button>' +
|
|
20627
|
+
'<button type="button" class="sec-btn" onclick="window.removeMcpServerAt(' + index + ')"' + (pending ? ' disabled' : '') + '>' + esc(t('common.remove')) + '</button></div></div>';
|
|
18945
20628
|
});
|
|
18946
|
-
html += '
|
|
18947
|
-
if (!
|
|
20629
|
+
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>';
|
|
20630
|
+
if (!allDiscovered.length) html += '<div class="plugin-empty">' + esc(t('plugins.mcpDiscoveredEmpty')) + '</div>';
|
|
20631
|
+
else if (!discovered.length) html += '<div class="plugin-empty">' + esc(t('plugins.mcpNoMatch')) + '</div>';
|
|
18948
20632
|
discovered.forEach(function(server) {
|
|
18949
|
-
html += '<div class="
|
|
20633
|
+
html += '<div class="mcp-server-row"><div class="mcp-server-copy"><div class="mcp-server-title">' + esc(server.name || '') +
|
|
20634
|
+
'<span class="plugin-status-badge">' + esc(server.ecosystem || t('plugins.mcpReadonly')) + '</span>' +
|
|
20635
|
+
'<span class="plugin-status-badge' + (server.enabled ? ' enabled' : '') + '">' + esc(server.enabled ? t('plugins.mcpEnabledStatus') : t('plugins.mcpDisabledStatus')) + '</span></div><div class="mcp-server-meta">' +
|
|
20636
|
+
esc([server.plugin, server.root].filter(Boolean).join(' · ')) + '</div></div><span class="plugin-status-badge">' + esc(t('plugins.mcpReadonly')) + '</span></div>';
|
|
18950
20637
|
});
|
|
20638
|
+
html += '</section>';
|
|
18951
20639
|
panel.innerHTML = html;
|
|
20640
|
+
window.updateMcpTransportForm(false);
|
|
20641
|
+
if (state.mcpFormFocusRequested) {
|
|
20642
|
+
state.mcpFormFocusRequested = false;
|
|
20643
|
+
requestAnimationFrame(function() {
|
|
20644
|
+
var form = document.getElementById('mcp-form');
|
|
20645
|
+
var input = document.getElementById('mcp-name');
|
|
20646
|
+
if (form) form.scrollIntoView({ block: 'nearest' });
|
|
20647
|
+
if (input) input.focus({ preventScroll: true });
|
|
20648
|
+
});
|
|
20649
|
+
}
|
|
18952
20650
|
};
|
|
18953
20651
|
|
|
18954
|
-
window.
|
|
18955
|
-
|
|
18956
|
-
var
|
|
18957
|
-
|
|
18958
|
-
|
|
18959
|
-
|
|
20652
|
+
window.captureMcpDraftFromForm = function() {
|
|
20653
|
+
if (!state.mcpDraft || !document.getElementById('mcp-form')) return state.mcpDraft;
|
|
20654
|
+
var value = function(id) { var element = document.getElementById(id); return element ? element.value : ''; };
|
|
20655
|
+
state.mcpDraft.name = value('mcp-name');
|
|
20656
|
+
state.mcpDraft.transport = value('mcp-transport') === 'http' ? 'http' : 'stdio';
|
|
20657
|
+
state.mcpDraft.command = value('mcp-command');
|
|
20658
|
+
state.mcpDraft.url = value('mcp-url');
|
|
20659
|
+
state.mcpDraft.argsText = value('mcp-args');
|
|
20660
|
+
state.mcpDraft.cwd = value('mcp-cwd');
|
|
20661
|
+
state.mcpDraft.envText = value('mcp-env');
|
|
20662
|
+
state.mcpDraft.headersText = value('mcp-headers');
|
|
20663
|
+
var enabled = document.getElementById('mcp-enabled');
|
|
20664
|
+
state.mcpDraft.enabled = !!(enabled && enabled.checked);
|
|
20665
|
+
return state.mcpDraft;
|
|
20666
|
+
};
|
|
20667
|
+
|
|
20668
|
+
window.updateMcpTransportForm = function(capture) {
|
|
20669
|
+
if (capture !== false) window.captureMcpDraftFromForm();
|
|
20670
|
+
var transport = document.getElementById('mcp-transport');
|
|
20671
|
+
var stdio = document.getElementById('mcp-stdio-fields');
|
|
20672
|
+
var http = document.getElementById('mcp-http-fields');
|
|
20673
|
+
var isHttp = !!(transport && transport.value === 'http');
|
|
20674
|
+
if (state.mcpDraft) state.mcpDraft.transport = isHttp ? 'http' : 'stdio';
|
|
20675
|
+
if (stdio) stdio.hidden = isHttp;
|
|
20676
|
+
if (http) http.hidden = !isHttp;
|
|
20677
|
+
};
|
|
20678
|
+
|
|
20679
|
+
window.openMcpAddForm = function() {
|
|
20680
|
+
if (state.mcpMutationPending) return;
|
|
20681
|
+
state.mcpEditingId = '';
|
|
20682
|
+
state.mcpDraft = newMcpDraft({ enabled: false, transport: 'stdio', args: [] }, 'add');
|
|
20683
|
+
state.mcpFormFocusRequested = true;
|
|
20684
|
+
window.renderMcpManagerContent();
|
|
20685
|
+
};
|
|
20686
|
+
|
|
20687
|
+
window.editMcpServerAt = function(index) {
|
|
20688
|
+
if (state.mcpMutationPending) return;
|
|
20689
|
+
var server = (state.mcpServers || [])[index];
|
|
20690
|
+
if (!server) return;
|
|
20691
|
+
state.mcpEditingId = server.id || '';
|
|
20692
|
+
state.mcpDraft = newMcpDraft(server, 'edit');
|
|
20693
|
+
state.mcpFormFocusRequested = true;
|
|
20694
|
+
window.renderMcpManagerContent();
|
|
20695
|
+
};
|
|
20696
|
+
|
|
20697
|
+
window.cancelMcpForm = function() {
|
|
20698
|
+
if (state.mcpMutationPending) return;
|
|
20699
|
+
state.mcpEditingId = '';
|
|
20700
|
+
state.mcpDraft = null;
|
|
20701
|
+
window.renderMcpManagerContent();
|
|
20702
|
+
var addButton = document.getElementById('mcp-add');
|
|
20703
|
+
if (addButton) addButton.focus({ preventScroll: true });
|
|
20704
|
+
};
|
|
20705
|
+
|
|
20706
|
+
window.updateMcpSearch = function(value) {
|
|
20707
|
+
window.captureMcpDraftFromForm();
|
|
20708
|
+
state.mcpSearchQuery = String(value || '');
|
|
20709
|
+
window.renderMcpManagerContent();
|
|
20710
|
+
var search = document.getElementById('mcp-search');
|
|
20711
|
+
if (search) {
|
|
20712
|
+
search.focus({ preventScroll: true });
|
|
20713
|
+
search.setSelectionRange(search.value.length, search.value.length);
|
|
20714
|
+
}
|
|
18960
20715
|
};
|
|
18961
|
-
|
|
18962
|
-
|
|
20716
|
+
|
|
20717
|
+
function parseMcpObject(text, fieldLabel) {
|
|
20718
|
+
if (!String(text || '').trim()) return undefined;
|
|
20719
|
+
var parsed = JSON.parse(text);
|
|
20720
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error(pluginText('plugins.mcpInvalidObject', { field: fieldLabel }));
|
|
20721
|
+
return parsed;
|
|
20722
|
+
}
|
|
20723
|
+
|
|
20724
|
+
function mcpMutationUiActive(generation) {
|
|
20725
|
+
return generation === state.mcpMutationGeneration
|
|
20726
|
+
&& state.pluginActiveTab === 'mcp'
|
|
20727
|
+
&& !!(state.activeSubWindowView && state.activeSubWindowView.name === 'plugins')
|
|
20728
|
+
&& !!document.getElementById('plugin-panel');
|
|
20729
|
+
}
|
|
20730
|
+
|
|
18963
20731
|
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 };
|
|
20732
|
+
if (!api.upsertMcpServer || state.mcpMutationPending) return;
|
|
20733
|
+
var draft = window.captureMcpDraftFromForm();
|
|
20734
|
+
if (!draft) return;
|
|
20735
|
+
var name = String(draft.name || '').trim();
|
|
20736
|
+
var transport = draft.transport === 'http' ? 'http' : 'stdio';
|
|
20737
|
+
if (!name) { showUiNotice(t('plugins.mcpRequiredName'), 'error', 'mcp-save'); return; }
|
|
20738
|
+
var input = { id: draft.id || state.mcpEditingId || undefined, name: name, transport: transport, enabled: !!draft.enabled };
|
|
18971
20739
|
try {
|
|
18972
|
-
if (transport === 'http') {
|
|
18973
|
-
|
|
20740
|
+
if (transport === 'http') {
|
|
20741
|
+
var url = String(draft.url || '').trim();
|
|
20742
|
+
if (!/^https?:\/\//i.test(url)) throw new Error(t('plugins.mcpRequiredUrl'));
|
|
20743
|
+
input.url = url;
|
|
20744
|
+
var headers = parseMcpObject(draft.headersText, t('plugins.mcpHeaders'));
|
|
20745
|
+
if (headers !== undefined) input.headers = headers;
|
|
20746
|
+
} else {
|
|
20747
|
+
var command = String(draft.command || '').trim();
|
|
20748
|
+
if (!command) throw new Error(t('plugins.mcpRequiredCommand'));
|
|
20749
|
+
var args = String(draft.argsText || '').trim() ? JSON.parse(draft.argsText) : [];
|
|
20750
|
+
if (!Array.isArray(args)) throw new Error(t('plugins.mcpInvalidArgs'));
|
|
20751
|
+
input.command = command;
|
|
20752
|
+
input.args = args;
|
|
20753
|
+
input.cwd = String(draft.cwd || '').trim() || undefined;
|
|
20754
|
+
var env = parseMcpObject(draft.envText, t('plugins.mcpEnv'));
|
|
20755
|
+
if (env !== undefined) input.env = env;
|
|
20756
|
+
}
|
|
18974
20757
|
} catch (error) {
|
|
18975
|
-
showUiNotice(error.message
|
|
20758
|
+
showUiNotice(error && error.message ? error.message : String(error), 'error', 'mcp-save');
|
|
18976
20759
|
return;
|
|
18977
20760
|
}
|
|
18978
|
-
|
|
18979
|
-
|
|
20761
|
+
var generation = ++state.mcpMutationGeneration;
|
|
20762
|
+
state.mcpMutationPending = true;
|
|
20763
|
+
window.renderMcpManagerContent();
|
|
20764
|
+
Promise.resolve(api.upsertMcpServer(input)).then(function(result) {
|
|
20765
|
+
if (!result || result.ok !== true) throw new Error(result && result.error || t('plugins.mcpMutationFailed'));
|
|
20766
|
+
if (Array.isArray(result.servers)) state.mcpServers = result.servers;
|
|
18980
20767
|
state.mcpEditingId = '';
|
|
18981
|
-
|
|
18982
|
-
|
|
20768
|
+
state.mcpDraft = null;
|
|
20769
|
+
if (mcpMutationUiActive(generation)) showUiNotice(t('plugins.mcpSaved'), 'success', 'mcp-save');
|
|
20770
|
+
}).catch(function(error) {
|
|
20771
|
+
if (mcpMutationUiActive(generation)) showUiNotice(error && error.message ? error.message : String(error), 'error', 'mcp-save');
|
|
20772
|
+
}).finally(function() {
|
|
20773
|
+
state.mcpMutationPending = false;
|
|
20774
|
+
if (mcpMutationUiActive(generation)) window.renderMcpManager();
|
|
20775
|
+
});
|
|
20776
|
+
};
|
|
20777
|
+
|
|
20778
|
+
window.toggleMcpServerAt = function(index, enabled) {
|
|
20779
|
+
if (!api.setMcpServerEnabled || state.mcpMutationPending) return;
|
|
20780
|
+
var server = (state.mcpServers || [])[index];
|
|
20781
|
+
if (!server) return;
|
|
20782
|
+
var generation = ++state.mcpMutationGeneration;
|
|
20783
|
+
state.mcpMutationPending = true;
|
|
20784
|
+
window.renderMcpManagerContent();
|
|
20785
|
+
Promise.resolve(api.setMcpServerEnabled(server.id, !!enabled)).then(function(result) {
|
|
20786
|
+
if (!result || result.ok !== true) throw new Error(result && result.error || t('plugins.mcpMutationFailed'));
|
|
20787
|
+
if (Array.isArray(result.servers)) state.mcpServers = result.servers;
|
|
20788
|
+
}).catch(function(error) {
|
|
20789
|
+
if (mcpMutationUiActive(generation)) showUiNotice(error && error.message ? error.message : String(error), 'error', 'mcp-toggle');
|
|
20790
|
+
}).finally(function() {
|
|
20791
|
+
state.mcpMutationPending = false;
|
|
20792
|
+
if (mcpMutationUiActive(generation)) window.renderMcpManager();
|
|
20793
|
+
});
|
|
20794
|
+
};
|
|
20795
|
+
|
|
20796
|
+
window.removeMcpServerAt = function(index) {
|
|
20797
|
+
if (!api.removeMcpServer || state.mcpMutationPending) return;
|
|
20798
|
+
var server = (state.mcpServers || [])[index];
|
|
20799
|
+
if (!server || !confirm(pluginText('plugins.mcpRemoveConfirm', { name: server.name || '' }))) return;
|
|
20800
|
+
var generation = ++state.mcpMutationGeneration;
|
|
20801
|
+
state.mcpMutationPending = true;
|
|
20802
|
+
window.renderMcpManagerContent();
|
|
20803
|
+
Promise.resolve(api.removeMcpServer(server.id)).then(function(result) {
|
|
20804
|
+
if (!result || result.ok !== true) throw new Error(result && result.error || t('plugins.mcpMutationFailed'));
|
|
20805
|
+
if (Array.isArray(result.servers)) state.mcpServers = result.servers;
|
|
20806
|
+
if (state.mcpEditingId === server.id) { state.mcpEditingId = ''; state.mcpDraft = null; }
|
|
20807
|
+
}).catch(function(error) {
|
|
20808
|
+
if (mcpMutationUiActive(generation)) showUiNotice(error && error.message ? error.message : String(error), 'error', 'mcp-remove');
|
|
20809
|
+
}).finally(function() {
|
|
20810
|
+
state.mcpMutationPending = false;
|
|
20811
|
+
if (mcpMutationUiActive(generation)) window.renderMcpManager();
|
|
20812
|
+
});
|
|
18983
20813
|
};
|
|
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
20814
|
|
|
18987
20815
|
window.filteredSkillMarket = function() {
|
|
18988
20816
|
var market = state._skillMarketAll || [];
|
|
@@ -19003,7 +20831,7 @@ window.filteredSkillMarket = function() {
|
|
|
19003
20831
|
|
|
19004
20832
|
window.renderSkillsMarketList = function() {
|
|
19005
20833
|
var panel = document.getElementById('plugin-panel');
|
|
19006
|
-
if (!panel) return;
|
|
20834
|
+
if (!panel || state.pluginActiveTab !== 'market' || !state.activeSubWindowView || state.activeSubWindowView.name !== 'plugins') return;
|
|
19007
20835
|
var market = window.filteredSkillMarket();
|
|
19008
20836
|
var total = (state._skillMarketAll || []).length;
|
|
19009
20837
|
var query = state.skillMarketQuery || '';
|
|
@@ -19272,13 +21100,14 @@ window.renderLeftWsList = function() {
|
|
|
19272
21100
|
var container = document.getElementById('left-ws-list');
|
|
19273
21101
|
if (!container) return;
|
|
19274
21102
|
var workspaces = state.workspaces || [];
|
|
21103
|
+
var hasActiveWorkspace = workspaces.some(function(item) { return workspaceIdentity(item) === String(state.currentWorkspaceId || ''); });
|
|
19275
21104
|
var html = '';
|
|
19276
21105
|
for (var i = 0; i < workspaces.length; i++) {
|
|
19277
21106
|
var ws = workspaces[i];
|
|
19278
21107
|
var identity = workspaceIdentity(ws);
|
|
19279
21108
|
var active = identity === String(state.currentWorkspaceId || '');
|
|
19280
21109
|
var runtimeStatus = workspaceRuntimeStatus(ws);
|
|
19281
|
-
html += '<div class="left-ws-item' + (active ? ' active' : '') + '" onclick="window.switchToWorkspace(\'' + escAttr(identity) + '\')">' +
|
|
21110
|
+
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
21111
|
'<span class="ws-icon">' + esc((ws.name || '?')[0].toUpperCase()) + '</span>' +
|
|
19283
21112
|
'<span class="ws-label">' + esc(ws.name || t('workspace.untitled')) + '</span>' +
|
|
19284
21113
|
(runtimeStatus ? '<span class="ws-runtime-dot ' + escAttr(runtimeStatus) + '" title="' + escAttr(runtimeStatus) + '"></span>' : '') +
|
|
@@ -19291,6 +21120,24 @@ window.renderLeftWsList = function() {
|
|
|
19291
21120
|
appendDomNodesInBatches(container, Array.from(holder.children), 'workspace-list', 24);
|
|
19292
21121
|
};
|
|
19293
21122
|
|
|
21123
|
+
window.handleWorkspaceKey = function(event) {
|
|
21124
|
+
if (!event || event.defaultPrevented || event.isComposing || event.key === 'Process' || event.keyCode === 229 || event.target !== event.currentTarget) return false;
|
|
21125
|
+
if (event.key === 'Enter' || event.key === ' ') return window.activateButtonLike(event);
|
|
21126
|
+
var items = Array.prototype.slice.call(document.querySelectorAll('#left-ws-list .left-ws-item'));
|
|
21127
|
+
var index = items.indexOf(event.currentTarget);
|
|
21128
|
+
if (index < 0 || !items.length) return false;
|
|
21129
|
+
var next = index;
|
|
21130
|
+
if (event.key === 'ArrowDown' || event.key === 'ArrowRight') next = (index + 1) % items.length;
|
|
21131
|
+
else if (event.key === 'ArrowUp' || event.key === 'ArrowLeft') next = (index - 1 + items.length) % items.length;
|
|
21132
|
+
else if (event.key === 'Home') next = 0;
|
|
21133
|
+
else if (event.key === 'End') next = items.length - 1;
|
|
21134
|
+
else return false;
|
|
21135
|
+
event.preventDefault();
|
|
21136
|
+
items[next].focus({ preventScroll:true });
|
|
21137
|
+
items[next].click();
|
|
21138
|
+
return true;
|
|
21139
|
+
};
|
|
21140
|
+
|
|
19294
21141
|
window.toggleWorkspacePinned = function(identity) {
|
|
19295
21142
|
if (!identity || !api.setWorkspacePinned) return;
|
|
19296
21143
|
var nextPinned = false;
|
|
@@ -19395,7 +21242,7 @@ window.showNewWorkspaceDialog = function() {
|
|
|
19395
21242
|
'<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
21243
|
'</div>' +
|
|
19397
21244
|
'<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()">' +
|
|
21245
|
+
'<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
21246
|
'<div id="ws-ext-path" style="display:none;margin-top:8px;">' +
|
|
19400
21247
|
'<label style="display:block;font-size:12px;color:var(--text-dim);margin-bottom:6px;">' + esc(t('workspace.folderPath')) + '</label>' +
|
|
19401
21248
|
'<div style="display:flex;gap:6px;">' +
|
|
@@ -19651,7 +21498,7 @@ window.openWorkspaceManager = async function() {
|
|
|
19651
21498
|
var ws = workspaces[i];
|
|
19652
21499
|
var identity = workspaceIdentity(ws);
|
|
19653
21500
|
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) + '\')">' +
|
|
21501
|
+
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
21502
|
'<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
21503
|
'<span style="flex:1;font-size:12px;color:var(--text);">' + esc(ws.name || t('workspace.untitled')) + '</span>' +
|
|
19657
21504
|
(isActive ? '<span style="font-size:10px;color:var(--accent2);">' + esc(t('workspace.current')) + '</span>' : '') +
|
|
@@ -19888,6 +21735,549 @@ function stopMarqueeJS() {
|
|
|
19888
21735
|
if (marqueeRAF) { cancelAnimationFrame(marqueeRAF); marqueeRAF = null; }
|
|
19889
21736
|
}
|
|
19890
21737
|
|
|
21738
|
+
// === Unified GUI Command Registry & Keyboard Routing ===
|
|
21739
|
+
function guiCommand(id, titleKey, category, options) {
|
|
21740
|
+
return Object.assign({ id: id, titleKey: titleKey, category: category, bindings: [], scope: 'palette', keywords: [] }, options || {});
|
|
21741
|
+
}
|
|
21742
|
+
|
|
21743
|
+
function guiIsMac() {
|
|
21744
|
+
return String(state.platform || navigator.platform || '').toLowerCase().indexOf('mac') >= 0;
|
|
21745
|
+
}
|
|
21746
|
+
|
|
21747
|
+
function guiBindingRecord(command, input) {
|
|
21748
|
+
return typeof input === 'string'
|
|
21749
|
+
? { keys: input, scope: command.scope || 'palette' }
|
|
21750
|
+
: { keys: String((input && input.keys) || ''), scope: String((input && input.scope) || command.scope || 'palette') };
|
|
21751
|
+
}
|
|
21752
|
+
|
|
21753
|
+
function guiDisplayBinding(binding) {
|
|
21754
|
+
var keys = typeof binding === 'string' ? binding : String((binding && binding.keys) || '');
|
|
21755
|
+
return keys.replace(/\bMod\b/g, guiIsMac() ? 'Cmd' : 'Ctrl').replace(/ /g, ' then ');
|
|
21756
|
+
}
|
|
21757
|
+
|
|
21758
|
+
function guiSetSelectValue(id, value) {
|
|
21759
|
+
var select = document.getElementById(id);
|
|
21760
|
+
if (!select) return false;
|
|
21761
|
+
select.value = value;
|
|
21762
|
+
select.dispatchEvent(new Event('change', { bubbles: true }));
|
|
21763
|
+
return true;
|
|
21764
|
+
}
|
|
21765
|
+
|
|
21766
|
+
function guiSubWindowOpen() {
|
|
21767
|
+
return !!(els['sub-win-overlay'] && els['sub-win-overlay'].classList.contains('open'));
|
|
21768
|
+
}
|
|
21769
|
+
|
|
21770
|
+
function guiFocusPrompt() {
|
|
21771
|
+
if (guiSubWindowOpen()) return false;
|
|
21772
|
+
if (els.prompt) {
|
|
21773
|
+
els.prompt.focus({ preventScroll: true });
|
|
21774
|
+
return true;
|
|
21775
|
+
}
|
|
21776
|
+
return false;
|
|
21777
|
+
}
|
|
21778
|
+
|
|
21779
|
+
function guiFocusTerminal() {
|
|
21780
|
+
if (guiSubWindowOpen()) return false;
|
|
21781
|
+
if (state.bottomCollapsed) window.toggleBottom();
|
|
21782
|
+
var input = document.querySelector('#terminal-body .terminal-pane.active .terminal-input') || document.querySelector('#terminal-body .terminal-input');
|
|
21783
|
+
if (input) {
|
|
21784
|
+
input.focus({ preventScroll: true });
|
|
21785
|
+
return true;
|
|
21786
|
+
}
|
|
21787
|
+
return false;
|
|
21788
|
+
}
|
|
21789
|
+
|
|
21790
|
+
function guiFocusBrowserAddress() {
|
|
21791
|
+
if (guiSubWindowOpen()) return false;
|
|
21792
|
+
window.switchRightTab('browser');
|
|
21793
|
+
requestAnimationFrame(function() {
|
|
21794
|
+
var input = document.getElementById('browser-url');
|
|
21795
|
+
if (input) { input.focus({ preventScroll: true }); input.select(); }
|
|
21796
|
+
});
|
|
21797
|
+
return true;
|
|
21798
|
+
}
|
|
21799
|
+
|
|
21800
|
+
function guiCycleConversation(direction) {
|
|
21801
|
+
var conversations = currentWorkspaceConversations ? currentWorkspaceConversations() : [];
|
|
21802
|
+
if (!conversations.length) return false;
|
|
21803
|
+
var current = Math.max(0, Math.min(conversations.length - 1, Number(state.activeConversation) || 0));
|
|
21804
|
+
var next = (current + direction + conversations.length) % conversations.length;
|
|
21805
|
+
window.switchConversation(next);
|
|
21806
|
+
return true;
|
|
21807
|
+
}
|
|
21808
|
+
|
|
21809
|
+
function guiHasSwitchableBranch() {
|
|
21810
|
+
var groups = state.conversationBranchGroups || [];
|
|
21811
|
+
var branches = state.conversationBranches || [];
|
|
21812
|
+
if (groups.length) return groups.some(function(group) { return (group.branches || []).length > 1; });
|
|
21813
|
+
return branches.length > 1;
|
|
21814
|
+
}
|
|
21815
|
+
|
|
21816
|
+
function guiToggleTheme() {
|
|
21817
|
+
var current = state.theme === 'light' ? 'light' : 'dark';
|
|
21818
|
+
window.setTheme(current === 'light' ? 'dark' : 'light');
|
|
21819
|
+
}
|
|
21820
|
+
|
|
21821
|
+
var NEWMARK_GUI_COMMANDS = [
|
|
21822
|
+
guiCommand('app.commandPalette', 'shortcuts.openPalette', 'general', { bindings: [{ keys:'Mod+Shift+P', scope:'global' }], run:function(){ window.openCommandSurface('palette'); } }),
|
|
21823
|
+
guiCommand('help.keyboardShortcuts', 'shortcuts.openHelp', 'general', { bindings: [{ keys:'F1', scope:'global' }], run:function(){ window.openCommandSurface('help'); } }),
|
|
21824
|
+
guiCommand('settings.open', 'settings.title', 'general', { bindings: [{ keys:'Mod+,', scope:'global' }, { keys:'Mod+K S', scope:'whenNotEditing' }], run:function(){ window.openSettings(); } }),
|
|
21825
|
+
guiCommand('window.minimize', 'top.minimize', 'general', { run:function(){ api.minimize(); } }),
|
|
21826
|
+
guiCommand('window.maximize', 'top.maximize', 'general', { run:function(){ api.maximize(); } }),
|
|
21827
|
+
guiCommand('view.toggleTheme', 'shortcuts.toggleTheme', 'general', { bindings:[{ keys:'Mod+K Q', scope:'whenNotEditing' }], run:guiToggleTheme }),
|
|
21828
|
+
|
|
21829
|
+
guiCommand('conversation.new', 'left.newChat', 'workspace', { bindings:[{ keys:'Mod+K N', scope:'whenNotEditing' }], run:function(){ if (state.currentWorkspaceId) window.newConversation(); else window.showNewConversationPage(); } }),
|
|
21830
|
+
guiCommand('conversation.next', 'shortcuts.nextConversation', 'workspace', { bindings:[{ keys:'Mod+Shift+ArrowRight', scope:'whenNotEditing' }], run:function(){ guiCycleConversation(1); }, available:function(){ return currentWorkspaceConversations().length > 1; } }),
|
|
21831
|
+
guiCommand('conversation.previous', 'shortcuts.previousConversation', 'workspace', { bindings:[{ keys:'Mod+Shift+ArrowLeft', scope:'whenNotEditing' }], run:function(){ guiCycleConversation(-1); }, available:function(){ return currentWorkspaceConversations().length > 1; } }),
|
|
21832
|
+
guiCommand('conversation.archive', 'archive.current', 'workspace', { run:function(){ window.archiveCurrent(); }, available:function(){ return !!state.currentWorkspaceId; } }),
|
|
21833
|
+
guiCommand('branch.previous', 'shortcuts.previousBranch', 'workspace', { bindings:[{ keys:'Alt+ArrowUp', scope:'whenNotEditing' }], run:function(){ window.switchConversationBranch(-1); }, available:function(){ return guiHasSwitchableBranch(); } }),
|
|
21834
|
+
guiCommand('branch.next', 'shortcuts.nextBranch', 'workspace', { bindings:[{ keys:'Alt+ArrowDown', scope:'whenNotEditing' }], run:function(){ window.switchConversationBranch(1); }, available:function(){ return guiHasSwitchableBranch(); } }),
|
|
21835
|
+
guiCommand('workspace.manager', 'workspace.manager', 'workspace', { bindings:[{ keys:'Mod+K W', scope:'whenNotEditing' }], run:function(){ window.openWorkspaceManager(); } }),
|
|
21836
|
+
guiCommand('workspace.new', 'workspace.new', 'workspace', { run:function(){ window.showNewWorkspaceDialog(); } }),
|
|
21837
|
+
guiCommand('workspace.settings', 'workspace.settingsTitle', 'workspace', { run:function(){ window.openWsSettings(); }, available:function(){ return !!state.currentWorkspaceId; } }),
|
|
21838
|
+
|
|
21839
|
+
guiCommand('view.plugins', 'plugins.title', 'navigation', { bindings:[{ keys:'Mod+K P', scope:'whenNotEditing' }], run:function(){ window.showPluginList(); } }),
|
|
21840
|
+
guiCommand('view.plugins.mcp', 'plugins.mcp', 'navigation', { run:function(){ window.showPluginList('mcp'); } }),
|
|
21841
|
+
guiCommand('view.plugins.dsh', 'plugins.dsh', 'navigation', { bindings:[{ keys:'Mod+K D', scope:'whenNotEditing' }], run:function(){ window.showPluginList('dsh'); } }),
|
|
21842
|
+
guiCommand('view.plugins.skills', 'plugins.management', 'navigation', { run:function(){ window.showPluginList('installed'); } }),
|
|
21843
|
+
guiCommand('view.plugins.market', 'plugins.market', 'navigation', { run:function(){ window.showPluginList('market'); } }),
|
|
21844
|
+
guiCommand('view.plugins.github', 'plugins.github', 'navigation', { run:function(){ window.showPluginList('github'); } }),
|
|
21845
|
+
guiCommand('view.memoryLab', 'memoryLab.title', 'navigation', { bindings:[{ keys:'Mod+K M', scope:'whenNotEditing' }], run:function(){ window.showMemoryLab(); } }),
|
|
21846
|
+
guiCommand('view.automation', 'automation.title', 'navigation', { bindings:[{ keys:'Mod+K A', scope:'whenNotEditing' }], run:function(){ window.showAutomationWindow(); } }),
|
|
21847
|
+
guiCommand('automation.new', 'automation.new', 'navigation', { run:function(){ window.showNewAutomationForm(); } }),
|
|
21848
|
+
guiCommand('view.flowEditor', 'flow.title', 'navigation', { bindings:[{ keys:'Mod+K F', scope:'whenNotEditing' }], run:function(){ window.showFlowEditor(); } }),
|
|
21849
|
+
guiCommand('flow.new', 'flow.new', 'navigation', { run:function(){ window.newFlowWork(); } }),
|
|
21850
|
+
|
|
21851
|
+
guiCommand('focus.primaryInput', 'shortcuts.focusPrimary', 'layout', { bindings:[{ keys:'Mod+K C', scope:'whenNotEditing' }], run:guiFocusPrompt, available:function(){ return !guiSubWindowOpen(); } }),
|
|
21852
|
+
guiCommand('focus.nextRegion', 'shortcuts.focusNext', 'layout', { bindings:[{ keys:'F6', scope:'global' }], run:function(){ window.cycleGuiRegionFocus(1); }, available:function(){ return !guiSubWindowOpen() && !window.commandSurfaceIsOpen(); } }),
|
|
21853
|
+
guiCommand('focus.previousRegion', 'shortcuts.focusPrevious', 'layout', { bindings:[{ keys:'Shift+F6', scope:'global' }], run:function(){ window.cycleGuiRegionFocus(-1); }, available:function(){ return !guiSubWindowOpen() && !window.commandSurfaceIsOpen(); } }),
|
|
21854
|
+
guiCommand('view.toggleLeft', 'shortcuts.toggleLeft', 'layout', { bindings:[{ keys:'Mod+B', scope:'whenNotEditing' }], run:function(){ window.toggleLeft(); } }),
|
|
21855
|
+
guiCommand('view.toggleWorkspacePanel', 'shortcuts.toggleWorkspacePanel', 'layout', { run:function(){ window.toggleSecondarySidebar(); } }),
|
|
21856
|
+
guiCommand('view.toggleRight', 'shortcuts.toggleRight', 'layout', { run:function(){ window.toggleRight(); } }),
|
|
21857
|
+
guiCommand('view.toggleTerminal', 'shortcuts.toggleTerminal', 'layout', { bindings:[{ keys:'Mod+`', scope:'whenNotEditing' }], run:function(){ window.toggleBottom(); } }),
|
|
21858
|
+
guiCommand('chat.scrollBottom', 'shortcuts.scrollBottom', 'layout', { bindings:[{ keys:'Mod+End', scope:'whenNotEditing' }], run:function(){ window.scrollToBottom(); } }),
|
|
21859
|
+
|
|
21860
|
+
guiCommand('right.files', 'right.files', 'navigation', { bindings:[{ keys:'Mod+K 1', scope:'whenNotEditing' }], run:function(){ window.switchRightTab('file-tree'); } }),
|
|
21861
|
+
guiCommand('right.editor', 'right.editor', 'navigation', { bindings:[{ keys:'Mod+K 2', scope:'whenNotEditing' }], run:function(){ window.switchRightTab('editor'); } }),
|
|
21862
|
+
guiCommand('right.plan', 'right.plan', 'navigation', { bindings:[{ keys:'Mod+K 3', scope:'whenNotEditing' }], run:function(){ window.switchRightTab('plan'); } }),
|
|
21863
|
+
guiCommand('right.subagents', 'right.subagents', 'navigation', { run:function(){ window.switchRightTab('subagent'); } }),
|
|
21864
|
+
guiCommand('right.browser', 'right.browser', 'navigation', { bindings:[{ keys:'Mod+K 4', scope:'whenNotEditing' }], run:function(){ window.switchRightTab('browser'); } }),
|
|
21865
|
+
guiCommand('right.status', 'right.status', 'navigation', { run:function(){ window.switchRightTab('status'); } }),
|
|
21866
|
+
guiCommand('right.archives', 'right.archives', 'navigation', { run:function(){ window.switchRightTab('archives'); } }),
|
|
21867
|
+
|
|
21868
|
+
guiCommand('mode.build', 'mode.build', 'input', { bindings:[{ keys:'Mod+1', scope:'whenNotEditing' }], run:function(){ guiSetSelectValue('mode-select','build'); } }),
|
|
21869
|
+
guiCommand('mode.plan', 'mode.plan', 'input', { bindings:[{ keys:'Mod+2', scope:'whenNotEditing' }], run:function(){ guiSetSelectValue('mode-select','plan'); } }),
|
|
21870
|
+
guiCommand('mode.goal', 'mode.goal', 'input', { bindings:[{ keys:'Mod+3', scope:'whenNotEditing' }], run:function(){ guiSetSelectValue('mode-select','goal'); } }),
|
|
21871
|
+
guiCommand('mode.flow', 'mode.flow', 'input', { bindings:[{ keys:'Mod+4', scope:'whenNotEditing' }], run:function(){ guiSetSelectValue('mode-select','flow'); } }),
|
|
21872
|
+
guiCommand('input.guide', 'input.guide', 'input', { bindings:[{ keys:'Mod+K G', scope:'whenNotEditing' }], run:function(){ window.setInputMode('guide'); } }),
|
|
21873
|
+
guiCommand('input.next', 'input.next', 'input', { bindings:[{ keys:'Mod+K E', scope:'whenNotEditing' }], run:function(){ window.setInputMode('next'); } }),
|
|
21874
|
+
guiCommand('goal.edit', 'goal.edit', 'input', { run:function(){ window.editGoal(); } }),
|
|
21875
|
+
guiCommand('goal.pauseResume', 'goal.pause', 'input', { bindings:[{ keys:'Mod+K Shift+G', scope:'whenNotEditing' }], run:function(){ window.toggleGoalPause(); }, available:function(){ return !!state.goalVisible; } }),
|
|
21876
|
+
|
|
21877
|
+
guiCommand('editor.save', 'common.save', 'editor', { bindings:[{ keys:'Mod+S', scope:'editor' }], run:function(){ window.saveEditor(); }, available:function(){ return !!state.editorPath; } }),
|
|
21878
|
+
guiCommand('editor.close', 'common.close', 'editor', { run:function(){ window.closeEditor(); }, available:function(){ return !!state.editorPath; } }),
|
|
21879
|
+
guiCommand('editor.markdownPreview', 'right.md', 'editor', { run:function(){ window.toggleEditorMarkdownPreview(); }, available:function(){ return !!state.editorPath; } }),
|
|
21880
|
+
guiCommand('editor.prediction', 'model.thinking', 'editor', { run:function(){ window.toggleEditorPrediction(); }, available:function(){ return !!state.editorPath; } }),
|
|
21881
|
+
guiCommand('editor.completion', 'model.validationCurrent', 'editor', { run:function(){ window.requestEditorCompletion({ force:true }); }, available:function(){ return !!state.editorPath; } }),
|
|
21882
|
+
|
|
21883
|
+
guiCommand('terminal.focus', 'shortcuts.focusTerminal', 'terminal', { bindings:[{ keys:'Mod+K T', scope:'whenNotEditing' }], run:guiFocusTerminal, available:function(){ return !guiSubWindowOpen(); } }),
|
|
21884
|
+
guiCommand('terminal.new', 'shortcuts.newTerminal', 'terminal', { run:function(){ window.addTerminalTab(); } }),
|
|
21885
|
+
guiCommand('terminal.clear', 'terminal.clear', 'terminal', { run:function(){ window.clearTerminal(); } }),
|
|
21886
|
+
|
|
21887
|
+
guiCommand('browser.focusAddress', 'shortcuts.focusBrowserAddress', 'browser', { bindings:[{ keys:'Mod+L', scope:'browser' }, { keys:'Mod+K B', scope:'whenNotEditing' }], run:guiFocusBrowserAddress, available:function(){ return !guiSubWindowOpen(); } }),
|
|
21888
|
+
guiCommand('browser.back', 'browser.back', 'browser', { bindings:[{ keys:'Alt+ArrowLeft', scope:'browser' }], run:function(){ window.browserBack(); } }),
|
|
21889
|
+
guiCommand('browser.forward', 'browser.forward', 'browser', { bindings:[{ keys:'Alt+ArrowRight', scope:'browser' }], run:function(){ window.browserForward(); } }),
|
|
21890
|
+
guiCommand('browser.reload', 'browser.reload', 'browser', { bindings:[{ keys:'Mod+R', scope:'browser' }, { keys:'F5', scope:'browser' }], run:function(){ window.browserReload(); } }),
|
|
21891
|
+
guiCommand('browser.computerUse', 'right.browser', 'browser', { run:function(){ window.toggleComputerUse(); } }),
|
|
21892
|
+
|
|
21893
|
+
guiCommand('settings.general', 'settings.general', 'context', { run:function(){ window.openSettings('general'); } }),
|
|
21894
|
+
guiCommand('settings.models', 'settings.models', 'context', { run:function(){ window.openSettings('models'); } }),
|
|
21895
|
+
guiCommand('settings.tools', 'settings.tools', 'context', { run:function(){ window.openSettings('tools'); } }),
|
|
21896
|
+
guiCommand('settings.archive', 'settings.archive', 'context', { run:function(){ window.openSettings('archive'); } }),
|
|
21897
|
+
guiCommand('settings.updates', 'settings.updates', 'context', { run:function(){ window.openSettings('updates'); } })
|
|
21898
|
+
];
|
|
21899
|
+
window.NEWMARK_GUI_COMMANDS = NEWMARK_GUI_COMMANDS;
|
|
21900
|
+
|
|
21901
|
+
window.activateButtonLike = function(event) {
|
|
21902
|
+
if (!event || event.defaultPrevented || event.isComposing || event.key === 'Process' || event.keyCode === 229) return false;
|
|
21903
|
+
if (event.key !== 'Enter' && event.key !== ' ') return false;
|
|
21904
|
+
if (event.target !== event.currentTarget) return false;
|
|
21905
|
+
event.preventDefault();
|
|
21906
|
+
event.currentTarget.click();
|
|
21907
|
+
return true;
|
|
21908
|
+
};
|
|
21909
|
+
|
|
21910
|
+
function guiCommandTitle(command) {
|
|
21911
|
+
return t(command.titleKey || command.id);
|
|
21912
|
+
}
|
|
21913
|
+
|
|
21914
|
+
function guiCommandCategory(command) {
|
|
21915
|
+
return t('shortcuts.category.' + (command.category || 'general'));
|
|
21916
|
+
}
|
|
21917
|
+
|
|
21918
|
+
function guiCommandAvailable(command) {
|
|
21919
|
+
try { return !command.available || command.available() !== false; }
|
|
21920
|
+
catch(e) { return false; }
|
|
21921
|
+
}
|
|
21922
|
+
|
|
21923
|
+
function guiKeyboardContext(event) {
|
|
21924
|
+
var target = event && event.target && event.target.nodeType === 1 ? event.target : document.activeElement;
|
|
21925
|
+
var closest = function(selector) { return target && target.closest ? target.closest(selector) : null; };
|
|
21926
|
+
var editable = !!(target && ((target.matches && target.matches('input, textarea, select, [role="textbox"], [role="combobox"]')) || target.isContentEditable || closest('[contenteditable]:not([contenteditable="false"])')));
|
|
21927
|
+
return {
|
|
21928
|
+
target: target,
|
|
21929
|
+
editable: editable,
|
|
21930
|
+
editor: !!closest('#native-editor, #panel-editor'),
|
|
21931
|
+
terminal: !!closest('#bottom, .terminal-pane'),
|
|
21932
|
+
browser: !!closest('#panel-browser, .browser-url-bar') || state.rightTab === 'browser' && !!closest('#right'),
|
|
21933
|
+
prompt: !!(els.prompt && (target === els.prompt || (els.prompt.contains && els.prompt.contains(target)))),
|
|
21934
|
+
dialog: !!closest('[role="dialog"]')
|
|
21935
|
+
};
|
|
21936
|
+
}
|
|
21937
|
+
|
|
21938
|
+
function guiBindingScopeMatches(scope, context) {
|
|
21939
|
+
if (scope === 'global') return true;
|
|
21940
|
+
if (scope === 'whenNotEditing') return !context.editable && !context.editor && !context.terminal && !context.browser && !context.dialog;
|
|
21941
|
+
if (scope === 'editor') return context.editor;
|
|
21942
|
+
if (scope === 'terminal') return context.terminal;
|
|
21943
|
+
if (scope === 'browser') return context.browser;
|
|
21944
|
+
if (scope === 'prompt') return context.prompt;
|
|
21945
|
+
if (scope === 'dialog') return context.dialog;
|
|
21946
|
+
return false;
|
|
21947
|
+
}
|
|
21948
|
+
|
|
21949
|
+
function guiEventSegment(event) {
|
|
21950
|
+
var key = String(event.key || '');
|
|
21951
|
+
if (!key || ['Control','Shift','Alt','Meta','AltGraph'].indexOf(key) >= 0) return '';
|
|
21952
|
+
var parts = [];
|
|
21953
|
+
var mac = guiIsMac();
|
|
21954
|
+
if ((mac && event.metaKey) || (!mac && event.ctrlKey)) parts.push('Mod');
|
|
21955
|
+
if ((mac && event.ctrlKey) || (!mac && event.metaKey)) parts.push(mac ? 'Ctrl' : 'Meta');
|
|
21956
|
+
if (event.altKey) parts.push('Alt');
|
|
21957
|
+
if (event.shiftKey) parts.push('Shift');
|
|
21958
|
+
var named = { ' ':'Space', 'Esc':'Escape', 'Left':'ArrowLeft', 'Right':'ArrowRight', 'Up':'ArrowUp', 'Down':'ArrowDown' };
|
|
21959
|
+
key = named[key] || key;
|
|
21960
|
+
if (key.length === 1 && /[a-z]/i.test(key)) key = key.toUpperCase();
|
|
21961
|
+
parts.push(key);
|
|
21962
|
+
return parts.join('+');
|
|
21963
|
+
}
|
|
21964
|
+
|
|
21965
|
+
var guiCommandSurfaceOriginFocus = null;
|
|
21966
|
+
var guiCommandSurfaceMode = 'palette';
|
|
21967
|
+
var guiCommandSurfaceMatches = [];
|
|
21968
|
+
var guiCommandSurfaceSelection = 0;
|
|
21969
|
+
var guiPendingChord = null;
|
|
21970
|
+
var guiPendingChordTimer = 0;
|
|
21971
|
+
|
|
21972
|
+
window.commandSurfaceIsOpen = function() {
|
|
21973
|
+
var overlay = document.getElementById('command-surface-overlay');
|
|
21974
|
+
return !!(overlay && overlay.classList.contains('open'));
|
|
21975
|
+
};
|
|
21976
|
+
|
|
21977
|
+
function guiClearChord() {
|
|
21978
|
+
guiPendingChord = null;
|
|
21979
|
+
if (guiPendingChordTimer) clearTimeout(guiPendingChordTimer);
|
|
21980
|
+
guiPendingChordTimer = 0;
|
|
21981
|
+
var hint = document.getElementById('shortcut-chord-hint');
|
|
21982
|
+
if (hint) hint.classList.remove('open');
|
|
21983
|
+
}
|
|
21984
|
+
|
|
21985
|
+
function guiShowChord(prefix, candidates) {
|
|
21986
|
+
guiClearChord();
|
|
21987
|
+
guiPendingChord = { prefix:prefix, candidates:candidates };
|
|
21988
|
+
var seconds = candidates.map(function(item){ return item.binding.keys.split(' ')[1]; }).filter(function(key,index,array){ return array.indexOf(key) === index; });
|
|
21989
|
+
var hint = document.getElementById('shortcut-chord-hint');
|
|
21990
|
+
if (hint) {
|
|
21991
|
+
hint.textContent = t('shortcuts.chordHint').replace('{prefix}', guiDisplayBinding(prefix)).replace('{keys}', seconds.join(' · '));
|
|
21992
|
+
hint.classList.add('open');
|
|
21993
|
+
}
|
|
21994
|
+
guiPendingChordTimer = setTimeout(guiClearChord, 1800);
|
|
21995
|
+
}
|
|
21996
|
+
|
|
21997
|
+
function guiNormalizeCommandSearchText(value) {
|
|
21998
|
+
return String(value || '')
|
|
21999
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
22000
|
+
.replace(/[._:/\\-]+/g, ' ')
|
|
22001
|
+
.replace(/\s+/g, ' ')
|
|
22002
|
+
.trim()
|
|
22003
|
+
.toLocaleLowerCase(uiLocale());
|
|
22004
|
+
}
|
|
22005
|
+
|
|
22006
|
+
function guiCommandSearchText(command) {
|
|
22007
|
+
var bindings = (command.bindings || []).map(guiDisplayBinding).join(' ');
|
|
22008
|
+
return guiNormalizeCommandSearchText([command.id, guiCommandTitle(command), guiCommandCategory(command), bindings].concat(command.keywords || []).join(' '));
|
|
22009
|
+
}
|
|
22010
|
+
|
|
22011
|
+
function guiCommandContextLabel(command) {
|
|
22012
|
+
var scopes = (command.bindings || []).map(function(binding){ return guiBindingRecord(command,binding).scope; });
|
|
22013
|
+
var scope = scopes[0] || command.scope || 'palette';
|
|
22014
|
+
if (scope === 'editor') return t('shortcuts.context.editor');
|
|
22015
|
+
if (scope === 'browser') return t('shortcuts.context.browser');
|
|
22016
|
+
if (scope === 'terminal') return t('shortcuts.context.terminal');
|
|
22017
|
+
if (scope === 'prompt') return t('shortcuts.context.prompt');
|
|
22018
|
+
if (scope === 'dialog') return t('shortcuts.context.dialog');
|
|
22019
|
+
return t('shortcuts.context.global');
|
|
22020
|
+
}
|
|
22021
|
+
|
|
22022
|
+
window.renderCommandSurface = function() {
|
|
22023
|
+
var list = document.getElementById('command-list');
|
|
22024
|
+
var search = document.getElementById('command-search');
|
|
22025
|
+
if (!list || !search) return;
|
|
22026
|
+
var query = guiNormalizeCommandSearchText(search.value);
|
|
22027
|
+
guiCommandSurfaceMatches = NEWMARK_GUI_COMMANDS.filter(function(command){ return !query || guiCommandSearchText(command).indexOf(query) >= 0; });
|
|
22028
|
+
if (guiCommandSurfaceSelection >= guiCommandSurfaceMatches.length) guiCommandSurfaceSelection = Math.max(0, guiCommandSurfaceMatches.length - 1);
|
|
22029
|
+
if (!guiCommandSurfaceMatches.length) {
|
|
22030
|
+
list.innerHTML = '<div class="command-empty">' + esc(t('shortcuts.noResults')) + '</div>';
|
|
22031
|
+
search.removeAttribute('aria-activedescendant');
|
|
22032
|
+
return;
|
|
22033
|
+
}
|
|
22034
|
+
var html = '';
|
|
22035
|
+
var priorCategory = '';
|
|
22036
|
+
for (var i = 0; i < guiCommandSurfaceMatches.length; i++) {
|
|
22037
|
+
var command = guiCommandSurfaceMatches[i];
|
|
22038
|
+
var category = guiCommandCategory(command);
|
|
22039
|
+
if (category !== priorCategory) {
|
|
22040
|
+
html += '<div class="command-category">' + esc(category) + '</div>';
|
|
22041
|
+
priorCategory = category;
|
|
22042
|
+
}
|
|
22043
|
+
var available = guiCommandAvailable(command);
|
|
22044
|
+
var keys = (command.bindings || []).map(function(binding){ return '<span class="command-key">' + esc(guiDisplayBinding(binding)) + '</span>'; }).join('');
|
|
22045
|
+
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 + ')">' +
|
|
22046
|
+
'<span><span class="command-option-title">' + esc(guiCommandTitle(command)) + '</span><span class="command-option-context">' + esc(guiCommandContextLabel(command)) + '</span></span>' +
|
|
22047
|
+
'<span class="command-shortcuts">' + keys + '</span></button>';
|
|
22048
|
+
}
|
|
22049
|
+
list.innerHTML = html;
|
|
22050
|
+
search.setAttribute('aria-activedescendant', 'command-option-' + guiCommandSurfaceSelection);
|
|
22051
|
+
var active = document.getElementById('command-option-' + guiCommandSurfaceSelection);
|
|
22052
|
+
if (active) active.scrollIntoView({ block:'nearest' });
|
|
22053
|
+
};
|
|
22054
|
+
|
|
22055
|
+
function guiMoveCommandSelection(delta, edge) {
|
|
22056
|
+
if (!guiCommandSurfaceMatches.length) return;
|
|
22057
|
+
if (edge === 'start') guiCommandSurfaceSelection = 0;
|
|
22058
|
+
else if (edge === 'end') guiCommandSurfaceSelection = guiCommandSurfaceMatches.length - 1;
|
|
22059
|
+
else guiCommandSurfaceSelection = (guiCommandSurfaceSelection + delta + guiCommandSurfaceMatches.length) % guiCommandSurfaceMatches.length;
|
|
22060
|
+
window.renderCommandSurface();
|
|
22061
|
+
}
|
|
22062
|
+
|
|
22063
|
+
window.openCommandSurface = function(mode) {
|
|
22064
|
+
var overlay = document.getElementById('command-surface-overlay');
|
|
22065
|
+
var search = document.getElementById('command-search');
|
|
22066
|
+
if (!overlay || !search) return;
|
|
22067
|
+
guiClearChord();
|
|
22068
|
+
if (!window.commandSurfaceIsOpen() && document.activeElement && typeof document.activeElement.focus === 'function') guiCommandSurfaceOriginFocus = document.activeElement;
|
|
22069
|
+
guiCommandSurfaceMode = mode === 'help' ? 'help' : 'palette';
|
|
22070
|
+
document.getElementById('command-surface-title').textContent = t(guiCommandSurfaceMode === 'help' ? 'shortcuts.helpTitle' : 'shortcuts.paletteTitle');
|
|
22071
|
+
document.getElementById('command-surface-subtitle').textContent = t(guiCommandSurfaceMode === 'help' ? 'shortcuts.helpSubtitle' : 'shortcuts.paletteSubtitle');
|
|
22072
|
+
document.getElementById('command-surface-footer').textContent = t('shortcuts.footer');
|
|
22073
|
+
search.setAttribute('placeholder', t(guiCommandSurfaceMode === 'help' ? 'shortcuts.searchShortcuts' : 'shortcuts.searchCommands'));
|
|
22074
|
+
search.value = '';
|
|
22075
|
+
guiCommandSurfaceSelection = 0;
|
|
22076
|
+
overlay.classList.add('open');
|
|
22077
|
+
updateApplicationInertState();
|
|
22078
|
+
window.renderCommandSurface();
|
|
22079
|
+
requestAnimationFrame(function(){ search.focus({ preventScroll:true }); });
|
|
22080
|
+
};
|
|
22081
|
+
|
|
22082
|
+
window.closeCommandSurface = function(options) {
|
|
22083
|
+
options = options || {};
|
|
22084
|
+
var overlay = document.getElementById('command-surface-overlay');
|
|
22085
|
+
if (!overlay || !overlay.classList.contains('open')) return;
|
|
22086
|
+
overlay.classList.remove('open');
|
|
22087
|
+
updateApplicationInertState();
|
|
22088
|
+
var restore = guiCommandSurfaceOriginFocus;
|
|
22089
|
+
guiCommandSurfaceOriginFocus = null;
|
|
22090
|
+
if (options.restoreFocus !== false) requestAnimationFrame(function(){ if (restore && restore.isConnected && typeof restore.focus === 'function') restore.focus({ preventScroll:true }); });
|
|
22091
|
+
return restore;
|
|
22092
|
+
};
|
|
22093
|
+
|
|
22094
|
+
window.executeGuiCommand = function(id, options) {
|
|
22095
|
+
var command = NEWMARK_GUI_COMMANDS.find(function(item){ return item.id === id; });
|
|
22096
|
+
if (!command || !guiCommandAvailable(command) || typeof command.run !== 'function') return false;
|
|
22097
|
+
try {
|
|
22098
|
+
var result = command.run(options || {});
|
|
22099
|
+
if (result && typeof result.catch === 'function') result.catch(function(error){ showUiNotice(error && error.message ? error.message : String(error), 'error', 'gui-command-' + id); });
|
|
22100
|
+
return true;
|
|
22101
|
+
} catch(error) {
|
|
22102
|
+
showUiNotice(error && error.message ? error.message : String(error), 'error', 'gui-command-' + id);
|
|
22103
|
+
return false;
|
|
22104
|
+
}
|
|
22105
|
+
};
|
|
22106
|
+
|
|
22107
|
+
window.executeCommandSurfaceIndex = function(index) {
|
|
22108
|
+
var command = guiCommandSurfaceMatches[index];
|
|
22109
|
+
if (!command || !guiCommandAvailable(command)) return false;
|
|
22110
|
+
var restore = window.closeCommandSurface({ restoreFocus:false });
|
|
22111
|
+
setTimeout(function(){
|
|
22112
|
+
window.executeGuiCommand(command.id, { source:'commandSurface' });
|
|
22113
|
+
requestAnimationFrame(function() {
|
|
22114
|
+
if (!guiSubWindowOpen() && !window.commandSurfaceIsOpen() && restore && restore.isConnected && typeof restore.focus === 'function') restore.focus({ preventScroll:true });
|
|
22115
|
+
});
|
|
22116
|
+
}, 0);
|
|
22117
|
+
return true;
|
|
22118
|
+
};
|
|
22119
|
+
|
|
22120
|
+
function guiVisible(element) {
|
|
22121
|
+
return !!(element && element.isConnected && element.getClientRects().length && !element.closest('[inert]'));
|
|
22122
|
+
}
|
|
22123
|
+
|
|
22124
|
+
function guiRegionTargets() {
|
|
22125
|
+
var activeTerminalInput = document.querySelector('#terminal-body .terminal-pane.active .terminal-input') || document.getElementById('bottom-toggle-btn');
|
|
22126
|
+
var activeRightTab = document.querySelector('#right-tabs .tab-btn[data-tab].active') || document.querySelector('#right-tabs .tab-btn[data-tab]');
|
|
22127
|
+
return [
|
|
22128
|
+
{ container:document.getElementById('left'), target:document.querySelector('#left-content .left-nav-icon') || document.querySelector('#left-thumb .lt-item') },
|
|
22129
|
+
{ container:document.getElementById('left-secondary'), target:document.querySelector('#left-secondary button, #conversation-list button, #conversation-list [tabindex="0"]') },
|
|
22130
|
+
{ container:document.getElementById('center'), target:els.prompt },
|
|
22131
|
+
{ container:document.getElementById('bottom'), target:activeTerminalInput },
|
|
22132
|
+
{ container:document.getElementById('right'), target:activeRightTab }
|
|
22133
|
+
].filter(function(region){ return guiVisible(region.container) && guiVisible(region.target); });
|
|
22134
|
+
}
|
|
22135
|
+
|
|
22136
|
+
window.cycleGuiRegionFocus = function(direction) {
|
|
22137
|
+
var regions = guiRegionTargets();
|
|
22138
|
+
if (!regions.length) return false;
|
|
22139
|
+
var active = document.activeElement;
|
|
22140
|
+
var current = regions.findIndex(function(region){ return region.container === active || region.container.contains(active); });
|
|
22141
|
+
var next = current < 0 ? (direction > 0 ? 0 : regions.length - 1) : (current + direction + regions.length) % regions.length;
|
|
22142
|
+
regions[next].target.focus({ preventScroll:true });
|
|
22143
|
+
return true;
|
|
22144
|
+
};
|
|
22145
|
+
|
|
22146
|
+
window.validateGuiCommandRegistry = function() {
|
|
22147
|
+
var errors = [];
|
|
22148
|
+
var ids = Object.create(null);
|
|
22149
|
+
var bindings = Object.create(null);
|
|
22150
|
+
for (var i = 0; i < NEWMARK_GUI_COMMANDS.length; i++) {
|
|
22151
|
+
var command = NEWMARK_GUI_COMMANDS[i];
|
|
22152
|
+
if (!command.id || ids[command.id]) errors.push('duplicate command id: ' + command.id);
|
|
22153
|
+
ids[command.id] = true;
|
|
22154
|
+
if (typeof command.run !== 'function') errors.push('missing command handler: ' + command.id);
|
|
22155
|
+
for (var j = 0; j < (command.bindings || []).length; j++) {
|
|
22156
|
+
var binding = guiBindingRecord(command, command.bindings[j]);
|
|
22157
|
+
if (!binding.keys) { errors.push('empty binding: ' + command.id); continue; }
|
|
22158
|
+
var identity = binding.scope + '::' + binding.keys;
|
|
22159
|
+
if (bindings[identity]) errors.push('binding conflict: ' + binding.keys + ' (' + binding.scope + ')');
|
|
22160
|
+
bindings[identity] = command.id;
|
|
22161
|
+
if (/\bMeta\b/.test(binding.keys) || /(?:^|\+)Mod\+Alt\+/.test(binding.keys)) errors.push('reserved modifier: ' + binding.keys);
|
|
22162
|
+
if (/^(Alt\+F4|Alt\+Tab|Mod\+Alt\+Delete|Mod\+Shift\+Escape)$/.test(binding.keys)) errors.push('reserved shortcut: ' + binding.keys);
|
|
22163
|
+
}
|
|
22164
|
+
}
|
|
22165
|
+
return errors;
|
|
22166
|
+
};
|
|
22167
|
+
|
|
22168
|
+
function guiManifestHash(value) {
|
|
22169
|
+
var input = String(value || '');
|
|
22170
|
+
var hash = 2166136261;
|
|
22171
|
+
for (var i = 0; i < input.length; i++) {
|
|
22172
|
+
hash ^= input.charCodeAt(i);
|
|
22173
|
+
hash = Math.imul(hash, 16777619);
|
|
22174
|
+
}
|
|
22175
|
+
return ('00000000' + (hash >>> 0).toString(16)).slice(-8);
|
|
22176
|
+
}
|
|
22177
|
+
|
|
22178
|
+
window.getGuiCommandManifest = function() {
|
|
22179
|
+
var commands = NEWMARK_GUI_COMMANDS.map(function(command) {
|
|
22180
|
+
return {
|
|
22181
|
+
id: command.id,
|
|
22182
|
+
category: command.category || 'general',
|
|
22183
|
+
bindings: (command.bindings || []).map(function(binding) {
|
|
22184
|
+
var record = guiBindingRecord(command, binding);
|
|
22185
|
+
return { keys: record.keys, scope: record.scope };
|
|
22186
|
+
})
|
|
22187
|
+
};
|
|
22188
|
+
});
|
|
22189
|
+
var serialized = JSON.stringify(commands);
|
|
22190
|
+
return {
|
|
22191
|
+
schemaVersion: 1,
|
|
22192
|
+
revision: 'fnv1a-' + guiManifestHash(serialized),
|
|
22193
|
+
commands: commands,
|
|
22194
|
+
errors: window.validateGuiCommandRegistry()
|
|
22195
|
+
};
|
|
22196
|
+
};
|
|
22197
|
+
|
|
22198
|
+
function guiHandleCommandKeydown(event) {
|
|
22199
|
+
if (!event || event.defaultPrevented || event.isComposing || event.key === 'Process' || event.keyCode === 229) return false;
|
|
22200
|
+
if (window.commandSurfaceIsOpen()) {
|
|
22201
|
+
if (event.key === 'Escape' && !event.repeat) { event.preventDefault(); event.stopPropagation(); window.closeCommandSurface(); return true; }
|
|
22202
|
+
if (event.key === 'Tab') return trapNewmarkDialogFocus(event, document.getElementById('command-surface'));
|
|
22203
|
+
return false;
|
|
22204
|
+
}
|
|
22205
|
+
if (event.repeat) return false;
|
|
22206
|
+
var segment = guiEventSegment(event);
|
|
22207
|
+
if (!segment) return false;
|
|
22208
|
+
if (guiPendingChord) {
|
|
22209
|
+
var match = guiPendingChord.candidates.find(function(item){ return item.binding.keys.split(' ')[1] === segment; });
|
|
22210
|
+
guiClearChord();
|
|
22211
|
+
event.preventDefault();
|
|
22212
|
+
event.stopPropagation();
|
|
22213
|
+
if (match) window.executeGuiCommand(match.command.id, { source:'shortcut' });
|
|
22214
|
+
return true;
|
|
22215
|
+
}
|
|
22216
|
+
var context = guiKeyboardContext(event);
|
|
22217
|
+
var direct = [];
|
|
22218
|
+
var chords = [];
|
|
22219
|
+
for (var i = 0; i < NEWMARK_GUI_COMMANDS.length; i++) {
|
|
22220
|
+
var command = NEWMARK_GUI_COMMANDS[i];
|
|
22221
|
+
if (!guiCommandAvailable(command)) continue;
|
|
22222
|
+
for (var j = 0; j < (command.bindings || []).length; j++) {
|
|
22223
|
+
var binding = guiBindingRecord(command, command.bindings[j]);
|
|
22224
|
+
if (!guiBindingScopeMatches(binding.scope, context)) continue;
|
|
22225
|
+
var pieces = binding.keys.split(' ');
|
|
22226
|
+
if (pieces[0] !== segment) continue;
|
|
22227
|
+
if (pieces.length === 1) direct.push({ command:command, binding:binding });
|
|
22228
|
+
else if (pieces.length === 2) chords.push({ command:command, binding:binding });
|
|
22229
|
+
}
|
|
22230
|
+
}
|
|
22231
|
+
if (direct.length) {
|
|
22232
|
+
event.preventDefault();
|
|
22233
|
+
event.stopPropagation();
|
|
22234
|
+
window.executeGuiCommand(direct[0].command.id, { source:'shortcut' });
|
|
22235
|
+
return true;
|
|
22236
|
+
}
|
|
22237
|
+
if (chords.length) {
|
|
22238
|
+
event.preventDefault();
|
|
22239
|
+
event.stopPropagation();
|
|
22240
|
+
guiShowChord(segment, chords);
|
|
22241
|
+
return true;
|
|
22242
|
+
}
|
|
22243
|
+
return false;
|
|
22244
|
+
}
|
|
22245
|
+
|
|
22246
|
+
function setupGuiKeyboard() {
|
|
22247
|
+
if (state._guiKeyboardReady) return;
|
|
22248
|
+
state._guiKeyboardReady = true;
|
|
22249
|
+
var errors = window.validateGuiCommandRegistry();
|
|
22250
|
+
if (errors.length) console.error('[Keyboard] command registry conflicts:', errors);
|
|
22251
|
+
var search = document.getElementById('command-search');
|
|
22252
|
+
if (search) {
|
|
22253
|
+
search.addEventListener('input', function(){ guiCommandSurfaceSelection = 0; window.renderCommandSurface(); });
|
|
22254
|
+
search.addEventListener('keydown', function(event){
|
|
22255
|
+
if (event.isComposing || event.key === 'Process' || event.keyCode === 229) return;
|
|
22256
|
+
if (event.key === 'ArrowDown') { event.preventDefault(); guiMoveCommandSelection(1); }
|
|
22257
|
+
else if (event.key === 'ArrowUp') { event.preventDefault(); guiMoveCommandSelection(-1); }
|
|
22258
|
+
else if (event.key === 'Home' && !event.ctrlKey && !event.metaKey) { event.preventDefault(); guiMoveCommandSelection(0,'start'); }
|
|
22259
|
+
else if (event.key === 'End' && !event.ctrlKey && !event.metaKey) { event.preventDefault(); guiMoveCommandSelection(0,'end'); }
|
|
22260
|
+
else if (event.key === 'Enter') { event.preventDefault(); window.executeCommandSurfaceIndex(guiCommandSurfaceSelection); }
|
|
22261
|
+
});
|
|
22262
|
+
}
|
|
22263
|
+
document.addEventListener('keydown', guiHandleCommandKeydown, true);
|
|
22264
|
+
if (api.onKeyboardCommand) api.onKeyboardCommand(function(payload){ if (payload && payload.id) window.executeGuiCommand(String(payload.id), { source:'browserGuest' }); });
|
|
22265
|
+
var attributes = [
|
|
22266
|
+
['#left-collapse-btn','view.toggleLeft'],
|
|
22267
|
+
['#bottom-toggle-btn','view.toggleTerminal'],
|
|
22268
|
+
['.sub-win-close','common.close']
|
|
22269
|
+
];
|
|
22270
|
+
for (var i = 0; i < attributes.length; i++) {
|
|
22271
|
+
var element = document.querySelector(attributes[i][0]);
|
|
22272
|
+
var command = NEWMARK_GUI_COMMANDS.find(function(item){ return item.id === attributes[i][1]; });
|
|
22273
|
+
if (!element || !command || !command.bindings.length) continue;
|
|
22274
|
+
var direct = guiBindingRecord(command,command.bindings[0]).keys;
|
|
22275
|
+
if (direct.indexOf(' ') < 0) element.setAttribute('aria-keyshortcuts', direct.replace(/\bMod\b/g, guiIsMac() ? 'Meta' : 'Control'));
|
|
22276
|
+
}
|
|
22277
|
+
var manifest = window.getGuiCommandManifest();
|
|
22278
|
+
document.documentElement.dataset.keyboardRegistry = manifest.errors.length ? 'invalid' : manifest.revision;
|
|
22279
|
+
}
|
|
22280
|
+
|
|
19891
22281
|
function schedulePostStartupUiRendering() {
|
|
19892
22282
|
if (state._postStartupUiRendering && state._postStartupUiRendering.cancel) state._postStartupUiRendering.cancel();
|
|
19893
22283
|
var tasks = [
|
|
@@ -19936,8 +22326,33 @@ function schedulePostStartupUiRendering() {
|
|
|
19936
22326
|
(function initResize() {
|
|
19937
22327
|
var handles = document.querySelectorAll('.resize-handle');
|
|
19938
22328
|
for (var i = 0; i < handles.length; i++) {
|
|
22329
|
+
var resizeTarget = handles[i].getAttribute('data-target');
|
|
22330
|
+
if (resizeTarget === 'left') { handles[i].setAttribute('aria-valuemin', '220'); handles[i].setAttribute('aria-valuemax', '460'); }
|
|
22331
|
+
if (resizeTarget === 'right') { handles[i].setAttribute('aria-valuemin', '340'); handles[i].setAttribute('aria-valuemax', '680'); }
|
|
22332
|
+
handles[i].addEventListener('keydown', function(e) {
|
|
22333
|
+
if (!e || e.defaultPrevented || e.isComposing || e.key === 'Process' || e.keyCode === 229 || e.ctrlKey || e.metaKey || e.altKey) return;
|
|
22334
|
+
var target = this.getAttribute('data-target');
|
|
22335
|
+
var side = this.getAttribute('data-side');
|
|
22336
|
+
var el = target === 'left' ? (els.left || document.getElementById('left')) : (target === 'right' ? (els.right || document.getElementById('right')) : null);
|
|
22337
|
+
if (!el || (target === 'left' && state.leftCollapsed) || (target === 'right' && state.rightCollapsed)) return;
|
|
22338
|
+
var min = target === 'left' ? 220 : 340;
|
|
22339
|
+
var max = target === 'left' ? 460 : 680;
|
|
22340
|
+
var size = el.offsetWidth;
|
|
22341
|
+
var delta = e.shiftKey ? 32 : 12;
|
|
22342
|
+
if (e.key === 'Home') size = min;
|
|
22343
|
+
else if (e.key === 'End') size = max;
|
|
22344
|
+
else if (e.key === 'ArrowLeft') size += side === 'left' ? delta : -delta;
|
|
22345
|
+
else if (e.key === 'ArrowRight') size += side === 'left' ? -delta : delta;
|
|
22346
|
+
else return;
|
|
22347
|
+
e.preventDefault();
|
|
22348
|
+
size = Math.max(min, Math.min(max, size));
|
|
22349
|
+
if (target === 'left') { setLeftWidthPx(size); state.leftWidth = size; }
|
|
22350
|
+
else window.setRightWidthPx(size);
|
|
22351
|
+
this.setAttribute('aria-valuenow', String(Math.round(size)));
|
|
22352
|
+
});
|
|
19939
22353
|
handles[i].addEventListener('mousedown', function(e) {
|
|
19940
22354
|
e.preventDefault();
|
|
22355
|
+
var handle = this;
|
|
19941
22356
|
var target = this.getAttribute('data-target');
|
|
19942
22357
|
var side = this.getAttribute('data-side');
|
|
19943
22358
|
var el = target === 'left' ? els.left : (target === 'right' ? els.right : null);
|
|
@@ -19957,10 +22372,12 @@ function schedulePostStartupUiRendering() {
|
|
|
19957
22372
|
var leftSize = Math.max(220, Math.min(460, newSize));
|
|
19958
22373
|
setLeftWidthPx(leftSize);
|
|
19959
22374
|
state.leftWidth = leftSize;
|
|
22375
|
+
handle.setAttribute('aria-valuenow', String(Math.round(leftSize)));
|
|
19960
22376
|
} else if (side === 'left') {
|
|
19961
22377
|
var newSize2 = startSize - dx;
|
|
19962
22378
|
var rightSize = Math.max(340, Math.min(680, newSize2));
|
|
19963
22379
|
window.setRightWidthPx(rightSize);
|
|
22380
|
+
handle.setAttribute('aria-valuenow', String(Math.round(rightSize)));
|
|
19964
22381
|
} else if (side === 'top') {
|
|
19965
22382
|
var newSize3 = startSize - dy;
|
|
19966
22383
|
el.style.height = Math.max(0, Math.min(400, newSize3)) + 'px';
|
|
@@ -20059,6 +22476,10 @@ function schedulePostStartupUiRendering() {
|
|
|
20059
22476
|
var startupHydrationError = null;
|
|
20060
22477
|
cacheEls();
|
|
20061
22478
|
setupAgentWorkEvents();
|
|
22479
|
+
if (api.onEditorCompletionDelta && !state._editorCompletionDeltaReady) {
|
|
22480
|
+
state._editorCompletionDeltaReady = true;
|
|
22481
|
+
api.onEditorCompletionDelta(function(payload) { window.applyEditorCompletionDelta(payload); });
|
|
22482
|
+
}
|
|
20062
22483
|
if (api.onBrowserEnsureGuest) {
|
|
20063
22484
|
api.onBrowserEnsureGuest(function(target) {
|
|
20064
22485
|
cancelBrowserGuestIdleDestroy();
|
|
@@ -20171,6 +22592,7 @@ function schedulePostStartupUiRendering() {
|
|
|
20171
22592
|
startupHydrationError = e;
|
|
20172
22593
|
}
|
|
20173
22594
|
applyUiAppearance();
|
|
22595
|
+
setupGuiKeyboard();
|
|
20174
22596
|
window.renderContextWindow();
|
|
20175
22597
|
if (api.onAutomationUpdated) {
|
|
20176
22598
|
api.onAutomationUpdated(function() {
|
|
@@ -20194,6 +22616,11 @@ function schedulePostStartupUiRendering() {
|
|
|
20194
22616
|
// navigation surfaces render after promotion on cancellable browser tasks.
|
|
20195
22617
|
updateWorkspaceGate();
|
|
20196
22618
|
|
|
22619
|
+
if (document.documentElement.classList.contains('config-reloading')) {
|
|
22620
|
+
document.documentElement.classList.remove('config-reloading');
|
|
22621
|
+
try { sessionStorage.removeItem('newmark-config-reloading'); } catch (_) {}
|
|
22622
|
+
}
|
|
22623
|
+
|
|
20197
22624
|
// === Event Listeners ===
|
|
20198
22625
|
function escapeBelongsToFocusedControl(event) {
|
|
20199
22626
|
var target = event && event.target;
|
|
@@ -20216,12 +22643,12 @@ function schedulePostStartupUiRendering() {
|
|
|
20216
22643
|
|
|
20217
22644
|
function stopRunningFromEscape(event) {
|
|
20218
22645
|
if (!event || event.key !== 'Escape' || event.defaultPrevented || escapeBelongsToFocusedControl(event)) return false;
|
|
20219
|
-
if (currentFlowRunning() && flowTakeoverMatchesCurrent()
|
|
22646
|
+
if (currentFlowRunning() && flowTakeoverMatchesCurrent()) {
|
|
20220
22647
|
event.preventDefault();
|
|
20221
22648
|
window.stopFlowRun();
|
|
20222
22649
|
return true;
|
|
20223
22650
|
}
|
|
20224
|
-
if (isCurrentConversationRunning()
|
|
22651
|
+
if (isCurrentConversationRunning()) {
|
|
20225
22652
|
event.preventDefault();
|
|
20226
22653
|
window.stopCurrentConversation();
|
|
20227
22654
|
return true;
|
|
@@ -20234,22 +22661,30 @@ function schedulePostStartupUiRendering() {
|
|
|
20234
22661
|
// after focus moved to the chat, title bar, button, or another non-editor
|
|
20235
22662
|
// surface. Modal/editor/select Escape behavior remains owned by that UI.
|
|
20236
22663
|
document.addEventListener('keydown', function(event) {
|
|
22664
|
+
if (!event || event.defaultPrevented || event.repeat || event.isComposing || event.key === 'Process' || event.keyCode === 229) return;
|
|
22665
|
+
if (event.key === 'Escape' && !event.defaultPrevented && els['sub-win-overlay'] && els['sub-win-overlay'].classList.contains('open')) {
|
|
22666
|
+
event.preventDefault();
|
|
22667
|
+
event.stopPropagation();
|
|
22668
|
+
window.closeSubWin();
|
|
22669
|
+
return;
|
|
22670
|
+
}
|
|
20237
22671
|
if (stopRunningFromEscape(event)) event.stopPropagation();
|
|
20238
22672
|
});
|
|
20239
22673
|
|
|
20240
22674
|
if (els.prompt) {
|
|
20241
22675
|
els.prompt.addEventListener('keydown', function(e) {
|
|
20242
|
-
if (e.key === '
|
|
22676
|
+
if (e.isComposing || e.key === 'Process' || e.keyCode === 229) return;
|
|
22677
|
+
if (e.key === 'Escape' && currentFlowRunning() && flowTakeoverMatchesCurrent()) {
|
|
20243
22678
|
e.preventDefault();
|
|
20244
22679
|
window.stopFlowRun();
|
|
20245
22680
|
return;
|
|
20246
22681
|
}
|
|
20247
|
-
if (e.key === 'Escape' && isCurrentConversationRunning()
|
|
22682
|
+
if (e.key === 'Escape' && isCurrentConversationRunning()) {
|
|
20248
22683
|
e.preventDefault();
|
|
20249
22684
|
window.stopCurrentConversation();
|
|
20250
22685
|
return;
|
|
20251
22686
|
}
|
|
20252
|
-
if (e.key === 'Enter' && e.ctrlKey) {
|
|
22687
|
+
if (e.key === 'Enter' && (e.ctrlKey || e.metaKey) && !e.altKey && !e.shiftKey) {
|
|
20253
22688
|
e.preventDefault();
|
|
20254
22689
|
if (state.mode === 'flow' || (currentFlowRunning() && flowTakeoverMatchesCurrent())) {
|
|
20255
22690
|
window.submitCurrentAction();
|
|
@@ -20259,9 +22694,9 @@ function schedulePostStartupUiRendering() {
|
|
|
20259
22694
|
window.sendMessage(opposite);
|
|
20260
22695
|
return;
|
|
20261
22696
|
}
|
|
20262
|
-
if (e.key === 'Enter' && !e.shiftKey) {
|
|
22697
|
+
if (e.key === 'Enter' && !e.shiftKey && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
20263
22698
|
e.preventDefault();
|
|
20264
|
-
window.submitCurrentAction();
|
|
22699
|
+
window.submitCurrentAction('enter');
|
|
20265
22700
|
}
|
|
20266
22701
|
});
|
|
20267
22702
|
els.prompt.addEventListener('input', function() {
|
|
@@ -20356,10 +22791,10 @@ function schedulePostStartupUiRendering() {
|
|
|
20356
22791
|
els['editor-textarea'].addEventListener('select', window.handleEditorCaretChange);
|
|
20357
22792
|
els['editor-textarea'].addEventListener('keyup', window.handleEditorCaretChange);
|
|
20358
22793
|
els['editor-textarea'].addEventListener('keydown', function(e) {
|
|
22794
|
+
if (e.isComposing || e.key === 'Process' || e.keyCode === 229) return;
|
|
20359
22795
|
if (state.editorCompletionText && e.key === 'Tab') { e.preventDefault(); window.acceptEditorCompletion(); return; }
|
|
20360
22796
|
if (e.key === 'Escape' && (state.editorCompletionText || (els['editor-completion'] && els['editor-completion'].classList.contains('open')))) { e.preventDefault(); window.dismissEditorCompletion(); return; }
|
|
20361
22797
|
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
22798
|
if (state.editorVimEnabled && e.key === 'Escape') { state.editorVimMode = 'normal'; state.editorVimPending = ''; e.preventDefault(); window.renderNativeEditor(); return; }
|
|
20364
22799
|
if (window.handleEditorVimKey(e)) return;
|
|
20365
22800
|
});
|