newmark-agent 0.3.11 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config.example.json +6 -0
- package/dist/cli-commands.d.ts +8 -0
- package/dist/cli-commands.js +216 -16
- package/dist/cli-discovery.d.ts +15 -0
- package/dist/cli-discovery.js +182 -0
- package/dist/cli-help.d.ts +2 -0
- package/dist/cli-help.js +25 -1
- 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 +1503 -214
- package/dist/conversation-utility-host.js +3 -0
- package/dist/core/agent.d.ts +157 -8
- package/dist/core/agent.js +1176 -112
- 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 +174 -27
- package/dist/core/config.d.ts +7 -2
- package/dist/core/config.js +24 -6
- package/dist/core/conversationKernel.d.ts +5 -0
- package/dist/core/conversationKernel.js +30 -1
- 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 +19 -0
- package/dist/core/electronUtilityRuntimePool.js +76 -0
- package/dist/core/flow-runner.js +1 -1
- package/dist/core/mcpManager.d.ts +1 -0
- package/dist/core/mcpManager.js +100 -10
- package/dist/core/modelValidationStore.d.ts +4 -1
- package/dist/core/modelValidationStore.js +7 -1
- package/dist/core/subagent.d.ts +6 -0
- package/dist/core/subagent.js +22 -1
- package/dist/core/toolPolicy.d.ts +6 -0
- package/dist/core/toolPolicy.js +49 -1
- package/dist/core/types.d.ts +1 -1
- package/dist/core/utilityAgentProtocol.d.ts +8 -1
- package/dist/core/workspace.d.ts +15 -0
- package/dist/core/workspace.js +62 -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 +12 -0
- package/dist/core/wslAgentRuntimePool.js +71 -0
- package/dist/launcher.js +48 -11
- package/dist/llm/provider.d.ts +9 -6
- package/dist/llm/provider.js +89 -36
- package/dist/main.js +326 -52
- package/dist/preload.js +17 -0
- package/dist/providers/chat-completions.adapter.js +42 -20
- package/dist/providers/provider-adapter.d.ts +3 -0
- package/dist/providers/provider-events.d.ts +7 -0
- package/dist/providers/provider-events.js +44 -0
- package/dist/providers/responses.adapter.js +1 -3
- package/dist/toolchain/registry/tool-registry.d.ts +13 -1
- package/dist/toolchain/registry/tool-registry.js +8 -0
- package/dist/toolchain/registry-seeder.js +51 -5
- package/dist/tools/index.js +11 -2
- package/dist/tools/nativeTools.js +5 -1
- package/dist/tui/src/adapters/core-runtime-adapter.js +40 -3
- package/dist/tui/src/app.js +47 -13
- package/dist/tui/src/render.js +23 -7
- package/dist/tui/src/state.js +61 -9
- package/dist/ui/index.html +2775 -284
- package/dist/ui/lucide-sprite.svg +26 -0
- package/dist/wsl-agent-host.bundle.cjs +1503 -214
- package/dist/wsl-agent-host.js +3 -0
- package/package.json +16 -5
package/dist/ui/index.html
CHANGED
|
@@ -136,6 +136,21 @@ try {
|
|
|
136
136
|
--duration-normal: 250ms;
|
|
137
137
|
--duration-slow: 400ms;
|
|
138
138
|
|
|
139
|
+
/* Stable Newmark semantic layers. Components depend on meaning, not on an
|
|
140
|
+
upstream developer-preview framework's private tokens or brand palette. */
|
|
141
|
+
--nm-surface-canvas: var(--app-bg);
|
|
142
|
+
--nm-surface-sunken: var(--glass-bg-1);
|
|
143
|
+
--nm-surface-raised: var(--glass-bg-2);
|
|
144
|
+
--nm-surface-overlay: var(--modal-surface);
|
|
145
|
+
--nm-label-primary: var(--text-bright);
|
|
146
|
+
--nm-label-secondary: var(--text);
|
|
147
|
+
--nm-label-tertiary: var(--text-dim);
|
|
148
|
+
--nm-state-info: var(--accent);
|
|
149
|
+
--nm-state-success: var(--accent2);
|
|
150
|
+
--nm-state-warning: #f4c95d;
|
|
151
|
+
--nm-state-danger: #ff7785;
|
|
152
|
+
--nm-focus-ring: 0 0 0 3px var(--accent-glow);
|
|
153
|
+
|
|
139
154
|
/* Layout sizes */
|
|
140
155
|
--left-width: 200px;
|
|
141
156
|
--left-secondary-width: 220px;
|
|
@@ -338,6 +353,19 @@ html, body {
|
|
|
338
353
|
border: 0;
|
|
339
354
|
}
|
|
340
355
|
button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus { outline: none; }
|
|
356
|
+
:where(button, select, input, textarea, [contenteditable], [tabindex]):focus-visible {
|
|
357
|
+
outline: 2px solid var(--accent);
|
|
358
|
+
outline-offset: 2px;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
@media (prefers-reduced-motion: reduce) {
|
|
362
|
+
*, *::before, *::after {
|
|
363
|
+
scroll-behavior: auto !important;
|
|
364
|
+
animation-duration: 0.01ms !important;
|
|
365
|
+
animation-iteration-count: 1 !important;
|
|
366
|
+
transition-duration: 0.01ms !important;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
341
369
|
::-webkit-scrollbar { width: 4px; height: 4px; }
|
|
342
370
|
::-webkit-scrollbar-track { background: transparent; }
|
|
343
371
|
::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.10); border-radius: var(--radius-full); }
|
|
@@ -527,6 +555,24 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
527
555
|
flex-shrink: 0;
|
|
528
556
|
}
|
|
529
557
|
|
|
558
|
+
button.lt-item,
|
|
559
|
+
button.left-nav-icon {
|
|
560
|
+
border: 0;
|
|
561
|
+
background: transparent;
|
|
562
|
+
font-family: var(--font-ui);
|
|
563
|
+
text-align: left;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
button.left-nav-icon { width: calc(100% - 12px); }
|
|
567
|
+
|
|
568
|
+
.lt-item:focus-visible,
|
|
569
|
+
.left-nav-icon:focus-visible {
|
|
570
|
+
outline: none;
|
|
571
|
+
color: var(--text-bright);
|
|
572
|
+
background: var(--control-hover-bg);
|
|
573
|
+
box-shadow: inset 0 0 0 2px var(--accent);
|
|
574
|
+
}
|
|
575
|
+
|
|
530
576
|
.lt-item:hover {
|
|
531
577
|
background: var(--glass-bg-2);
|
|
532
578
|
color: var(--text);
|
|
@@ -749,6 +795,14 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
749
795
|
overflow: hidden;
|
|
750
796
|
}
|
|
751
797
|
|
|
798
|
+
button.left-ws-item {
|
|
799
|
+
width: 100%;
|
|
800
|
+
border: 0;
|
|
801
|
+
background: transparent;
|
|
802
|
+
font-family: var(--font-ui);
|
|
803
|
+
text-align: left;
|
|
804
|
+
}
|
|
805
|
+
|
|
752
806
|
.left-ws-item:hover { background: var(--glass-bg-2); }
|
|
753
807
|
.left-ws-item.active { background: var(--accent-glow); color: var(--text-bright); }
|
|
754
808
|
|
|
@@ -1055,6 +1109,11 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
1055
1109
|
}
|
|
1056
1110
|
|
|
1057
1111
|
.resize-handle:hover { background: var(--accent); }
|
|
1112
|
+
.resize-handle:focus-visible {
|
|
1113
|
+
outline: none;
|
|
1114
|
+
background: var(--accent);
|
|
1115
|
+
box-shadow: 0 0 0 2px var(--accent-glow);
|
|
1116
|
+
}
|
|
1058
1117
|
|
|
1059
1118
|
.resize-handle[data-side="left"] {
|
|
1060
1119
|
cursor: col-resize;
|
|
@@ -1883,12 +1942,12 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
1883
1942
|
|
|
1884
1943
|
.terminal-output {
|
|
1885
1944
|
flex: 1;
|
|
1886
|
-
overflow
|
|
1945
|
+
overflow: auto;
|
|
1887
1946
|
padding: 8px 12px;
|
|
1888
1947
|
font-family: var(--font-mono);
|
|
1889
1948
|
font-size: 12px;
|
|
1890
1949
|
color: var(--text-dim);
|
|
1891
|
-
white-space: pre
|
|
1950
|
+
white-space: pre;
|
|
1892
1951
|
line-height: 1.5;
|
|
1893
1952
|
}
|
|
1894
1953
|
|
|
@@ -2419,6 +2478,8 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
2419
2478
|
.conversation-work-subagent-chip.completed .conversation-work-subagent-status { color: var(--accent2); }
|
|
2420
2479
|
.conversation-work-command-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2421
2480
|
.conversation-work-activity-detail { margin-top: 2px; color: color-mix(in srgb, var(--text-dim) 88%, transparent); font: 10px/1.45 var(--font-mono); white-space: pre-wrap; word-break: break-word; }
|
|
2481
|
+
.conversation-work-thought-text { margin: 4px 0 5px 24px; color: color-mix(in srgb, var(--text-dim) 92%, transparent); font: 11px/1.55 var(--font-mono); white-space: pre-wrap; word-break: break-word; }
|
|
2482
|
+
.conversation-work-thought-pending { color: var(--text-dim); font-style: italic; }
|
|
2422
2483
|
.conversation-work-files { margin-top: 1px; }
|
|
2423
2484
|
.conversation-work-files > summary { display: grid; grid-template-columns: 17px minmax(0,1fr) 10px; gap: 7px; align-items: center; min-height: 26px; cursor: pointer; list-style: none; color: var(--text); font-size: 11px; font-weight: 600; }
|
|
2424
2485
|
.conversation-work-files > summary::-webkit-details-marker,
|
|
@@ -2524,7 +2585,7 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
2524
2585
|
.shell-block {
|
|
2525
2586
|
margin: 8px 0;
|
|
2526
2587
|
border-radius: var(--radius-md);
|
|
2527
|
-
background:
|
|
2588
|
+
background: var(--nm-surface-sunken);
|
|
2528
2589
|
border: 1px solid var(--glass-border-1);
|
|
2529
2590
|
overflow: hidden;
|
|
2530
2591
|
}
|
|
@@ -2550,7 +2611,7 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
2550
2611
|
font-family: var(--font-mono);
|
|
2551
2612
|
font-size: 12px;
|
|
2552
2613
|
color: var(--text-dim);
|
|
2553
|
-
white-space: pre
|
|
2614
|
+
white-space: pre;
|
|
2554
2615
|
line-height: 1.5;
|
|
2555
2616
|
max-height: 400px;
|
|
2556
2617
|
overflow: auto;
|
|
@@ -2583,6 +2644,23 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
2583
2644
|
.diff-block-header .arrow { transition: transform var(--duration-fast) var(--ease-out-expo); font-size: 9px; }
|
|
2584
2645
|
.diff-block.collapsed .diff-block-header .arrow { transform: rotate(-90deg); }
|
|
2585
2646
|
|
|
2647
|
+
button.shell-block-header,
|
|
2648
|
+
button.diff-block-header,
|
|
2649
|
+
button.flow-item-header,
|
|
2650
|
+
button.work-review-head,
|
|
2651
|
+
button.todo-item {
|
|
2652
|
+
width: 100%;
|
|
2653
|
+
border: 0;
|
|
2654
|
+
font-family: var(--font-ui);
|
|
2655
|
+
text-align: left;
|
|
2656
|
+
}
|
|
2657
|
+
|
|
2658
|
+
button.shell-block-header { background: rgba(255,255,255,0.03); }
|
|
2659
|
+
button.diff-block-header,
|
|
2660
|
+
button.flow-item-header,
|
|
2661
|
+
button.work-review-head,
|
|
2662
|
+
button.todo-item { background: transparent; }
|
|
2663
|
+
|
|
2586
2664
|
.diff-stat { display: flex; gap: 8px; margin-left: auto; }
|
|
2587
2665
|
.diff-add { color: var(--accent2); font-size: 11px; }
|
|
2588
2666
|
.diff-del { color: #ff6666; font-size: 11px; }
|
|
@@ -2958,6 +3036,8 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
2958
3036
|
.work-review-actions { display:flex; align-items:center; gap:5px; }
|
|
2959
3037
|
.work-review-btn { height:28px; padding:0 10px; border:1px solid var(--glass-border-2); border-radius:6px; background:transparent; color:var(--text); cursor:pointer; font:600 11px var(--font); }
|
|
2960
3038
|
.work-review-btn:hover { background:var(--control-hover-bg); border-color:var(--border-hover); }
|
|
3039
|
+
.work-review-toggle { width:28px; height:28px; display:inline-flex; align-items:center; justify-content:center; padding:0; border:1px solid transparent; border-radius:6px; background:transparent; color:var(--text-dim); cursor:pointer; }
|
|
3040
|
+
.work-review-toggle:hover { background:var(--control-hover-bg); border-color:var(--border-hover); }
|
|
2961
3041
|
.work-review-list { border-top:1px solid var(--glass-border-1); }
|
|
2962
3042
|
.work-review.collapsed .work-review-list { display: none; }
|
|
2963
3043
|
.work-review-head { cursor: pointer; }
|
|
@@ -3057,6 +3137,16 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
3057
3137
|
font: 9px var(--font-mono);
|
|
3058
3138
|
}
|
|
3059
3139
|
|
|
3140
|
+
.conv-branch-comm-badge {
|
|
3141
|
+
flex: 0 0 auto;
|
|
3142
|
+
padding: 2px 5px;
|
|
3143
|
+
border-radius: 999px;
|
|
3144
|
+
background: color-mix(in srgb, var(--accent) 16%, transparent);
|
|
3145
|
+
color: var(--accent);
|
|
3146
|
+
font: 9px var(--font-mono);
|
|
3147
|
+
white-space: nowrap;
|
|
3148
|
+
}
|
|
3149
|
+
|
|
3060
3150
|
.conv-runtime-badge.running { color: var(--accent2); }
|
|
3061
3151
|
.conv-runtime-badge.stopping,
|
|
3062
3152
|
.conv-runtime-badge.force_restarting { color: #ffd27a; }
|
|
@@ -3391,9 +3481,47 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
3391
3481
|
flex: 0 0 auto;
|
|
3392
3482
|
}
|
|
3393
3483
|
|
|
3484
|
+
#context-inspector {
|
|
3485
|
+
position: absolute;
|
|
3486
|
+
right: -8px;
|
|
3487
|
+
bottom: calc(100% + 10px);
|
|
3488
|
+
z-index: 80;
|
|
3489
|
+
display: none;
|
|
3490
|
+
width: min(320px, calc(100vw - 24px));
|
|
3491
|
+
padding: 12px;
|
|
3492
|
+
border: 1px solid var(--glass-border-2);
|
|
3493
|
+
border-radius: var(--radius-lg);
|
|
3494
|
+
background: var(--modal-surface);
|
|
3495
|
+
box-shadow: var(--shadow-lg);
|
|
3496
|
+
backdrop-filter: blur(var(--glass-blur-3)) saturate(1.08);
|
|
3497
|
+
color: var(--text);
|
|
3498
|
+
font-size: 10px;
|
|
3499
|
+
line-height: 1.45;
|
|
3500
|
+
}
|
|
3501
|
+
#context-inspector.open { display: block; animation: model-menu-in 150ms var(--ease-out-expo); }
|
|
3502
|
+
.context-inspector-head { display:flex; align-items:flex-start; gap:8px; margin-bottom:10px; }
|
|
3503
|
+
.context-inspector-title { flex:1; min-width:0; color:var(--text-bright); font-size:12px; font-weight:700; }
|
|
3504
|
+
.context-inspector-subtitle { margin-top:2px; color:var(--text-dim); font-size:9px; }
|
|
3505
|
+
.context-inspector-close { width:22px; height:22px; padding:0; border:0; border-radius:var(--radius-sm); background:transparent; color:var(--text-dim); cursor:pointer; }
|
|
3506
|
+
.context-inspector-close:hover, .context-inspector-close:focus-visible { color:var(--text-bright); background:var(--control-hover-bg); outline:none; }
|
|
3507
|
+
.context-inspector-meter { height:6px; margin:8px 0 10px; overflow:hidden; border-radius:var(--radius-full); background:rgba(168,168,168,.18); }
|
|
3508
|
+
.context-inspector-meter-fill { height:100%; border-radius:inherit; background:var(--accent); transition:width var(--duration-normal) var(--ease-out-expo), background var(--duration-fast) var(--ease-out-expo); }
|
|
3509
|
+
.context-inspector-grid { display:grid; grid-template-columns:1fr 1fr; gap:7px; }
|
|
3510
|
+
.context-inspector-cell { padding:7px 8px; border:1px solid var(--glass-border-1); border-radius:var(--radius-sm); background:var(--glass-bg-1); }
|
|
3511
|
+
.context-inspector-label { display:block; color:var(--text-dim); font-size:9px; }
|
|
3512
|
+
.context-inspector-value { display:block; margin-top:2px; color:var(--text-bright); font:600 10px var(--font-mono); }
|
|
3513
|
+
.context-inspector-section { margin-top:10px; padding-top:9px; border-top:1px solid var(--glass-border-1); }
|
|
3514
|
+
.context-inspector-section-title { color:var(--text-bright); font-size:10px; font-weight:650; }
|
|
3515
|
+
.context-inspector-meta { margin-top:3px; color:var(--text-dim); overflow-wrap:anywhere; }
|
|
3516
|
+
.context-inspector-actions { display:flex; align-items:center; gap:7px; margin-top:10px; }
|
|
3517
|
+
.context-inspector-actions .sec-btn { flex:1; min-width:0; }
|
|
3518
|
+
.context-inspector-actions .sec-btn:disabled { opacity:.55; cursor:wait; }
|
|
3519
|
+
|
|
3394
3520
|
#context-token-ring {
|
|
3395
3521
|
width: 16px;
|
|
3396
3522
|
height: 16px;
|
|
3523
|
+
padding: 0;
|
|
3524
|
+
border: 0;
|
|
3397
3525
|
border-radius: 50%;
|
|
3398
3526
|
background: conic-gradient(#a8a8a8 0deg, rgba(168,168,168,0.22) 0deg);
|
|
3399
3527
|
cursor: default;
|
|
@@ -3601,6 +3729,124 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
3601
3729
|
50% { box-shadow: 0 0 24px rgba(91,120,255,0.5), 0 0 60px rgba(91,120,255,0.15); }
|
|
3602
3730
|
}
|
|
3603
3731
|
|
|
3732
|
+
/* ============================================================
|
|
3733
|
+
KEYBOARD COMMAND SURFACE
|
|
3734
|
+
============================================================ */
|
|
3735
|
+
.command-surface-overlay {
|
|
3736
|
+
position: fixed;
|
|
3737
|
+
inset: 0;
|
|
3738
|
+
z-index: 320;
|
|
3739
|
+
display: flex;
|
|
3740
|
+
align-items: flex-start;
|
|
3741
|
+
justify-content: center;
|
|
3742
|
+
padding: min(12vh, 96px) 18px 18px;
|
|
3743
|
+
background: color-mix(in srgb, var(--nm-surface-canvas) 62%, transparent);
|
|
3744
|
+
opacity: 0;
|
|
3745
|
+
visibility: hidden;
|
|
3746
|
+
pointer-events: none;
|
|
3747
|
+
transition: opacity var(--duration-fast) var(--ease-out-expo), visibility 0ms linear var(--duration-fast);
|
|
3748
|
+
}
|
|
3749
|
+
|
|
3750
|
+
.command-surface-overlay.open {
|
|
3751
|
+
opacity: 1;
|
|
3752
|
+
visibility: visible;
|
|
3753
|
+
pointer-events: auto;
|
|
3754
|
+
transition-delay: 0ms, 0ms;
|
|
3755
|
+
}
|
|
3756
|
+
|
|
3757
|
+
.command-surface {
|
|
3758
|
+
width: min(680px, calc(100vw - 36px));
|
|
3759
|
+
max-height: min(680px, calc(100vh - 132px));
|
|
3760
|
+
display: flex;
|
|
3761
|
+
flex-direction: column;
|
|
3762
|
+
overflow: hidden;
|
|
3763
|
+
border: 1px solid var(--glass-border-2);
|
|
3764
|
+
border-radius: var(--radius-xl);
|
|
3765
|
+
background: var(--nm-surface-overlay);
|
|
3766
|
+
box-shadow: var(--shadow-lg);
|
|
3767
|
+
backdrop-filter: blur(var(--glass-blur-3)) saturate(150%);
|
|
3768
|
+
transform: translateY(-8px) scale(0.985);
|
|
3769
|
+
transition: transform var(--duration-fast) var(--ease-out-expo);
|
|
3770
|
+
}
|
|
3771
|
+
|
|
3772
|
+
.command-surface-overlay.open .command-surface { transform: translateY(0) scale(1); }
|
|
3773
|
+
.command-surface-header { display:flex; align-items:flex-start; gap:12px; padding:14px 16px 10px; }
|
|
3774
|
+
.command-surface-heading { flex:1; min-width:0; }
|
|
3775
|
+
.command-surface-title { color:var(--text-bright); font-size:14px; font-weight:700; }
|
|
3776
|
+
.command-surface-subtitle { margin-top:3px; color:var(--text-dim); font-size:10px; line-height:1.45; }
|
|
3777
|
+
.command-surface-close { width:28px; height:28px; border:0; border-radius:var(--radius-sm); background:transparent; color:var(--text-dim); cursor:pointer; }
|
|
3778
|
+
.command-surface-close:hover { color:var(--text-bright); background:var(--control-hover-bg); }
|
|
3779
|
+
.command-search-wrap { padding:0 14px 12px; }
|
|
3780
|
+
.command-search {
|
|
3781
|
+
width:100%;
|
|
3782
|
+
height:40px;
|
|
3783
|
+
box-sizing:border-box;
|
|
3784
|
+
padding:0 12px;
|
|
3785
|
+
border:1px solid var(--glass-border-2);
|
|
3786
|
+
border-radius:var(--radius-md);
|
|
3787
|
+
background:var(--control-bg);
|
|
3788
|
+
color:var(--text);
|
|
3789
|
+
font:12px var(--font-ui);
|
|
3790
|
+
}
|
|
3791
|
+
.command-search:focus { border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-glow); }
|
|
3792
|
+
.command-list { min-height:96px; overflow:auto; padding:0 8px 8px; }
|
|
3793
|
+
.command-category { padding:9px 9px 5px; color:var(--text-dim); font-size:9px; font-weight:700; letter-spacing:.07em; text-transform:uppercase; }
|
|
3794
|
+
.command-option {
|
|
3795
|
+
width:100%;
|
|
3796
|
+
min-height:42px;
|
|
3797
|
+
display:grid;
|
|
3798
|
+
grid-template-columns:minmax(0,1fr) auto;
|
|
3799
|
+
align-items:center;
|
|
3800
|
+
gap:12px;
|
|
3801
|
+
padding:6px 9px;
|
|
3802
|
+
border:1px solid transparent;
|
|
3803
|
+
border-radius:var(--radius-md);
|
|
3804
|
+
background:transparent;
|
|
3805
|
+
color:var(--text);
|
|
3806
|
+
text-align:left;
|
|
3807
|
+
cursor:pointer;
|
|
3808
|
+
font-family:var(--font-ui);
|
|
3809
|
+
}
|
|
3810
|
+
.command-option.active,
|
|
3811
|
+
.command-option:hover { background:var(--control-hover-bg); border-color:var(--glass-border-1); }
|
|
3812
|
+
.command-option[aria-disabled="true"] { opacity:.48; cursor:not-allowed; }
|
|
3813
|
+
.command-option-title { display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:12px; }
|
|
3814
|
+
.command-option-context { display:block; margin-top:2px; color:var(--text-dim); font-size:9px; }
|
|
3815
|
+
.command-shortcuts { display:flex; justify-content:flex-end; gap:4px; }
|
|
3816
|
+
.command-key {
|
|
3817
|
+
min-width:22px;
|
|
3818
|
+
padding:3px 6px;
|
|
3819
|
+
border:1px solid var(--glass-border-2);
|
|
3820
|
+
border-bottom-color:var(--border-hover);
|
|
3821
|
+
border-radius:5px;
|
|
3822
|
+
background:var(--glass-bg-1);
|
|
3823
|
+
color:var(--text-dim);
|
|
3824
|
+
font:10px var(--font-mono);
|
|
3825
|
+
text-align:center;
|
|
3826
|
+
white-space:nowrap;
|
|
3827
|
+
}
|
|
3828
|
+
.command-empty { padding:24px 12px; color:var(--text-dim); font-size:11px; text-align:center; }
|
|
3829
|
+
.command-surface-footer { padding:8px 14px 10px; border-top:1px solid var(--glass-border-1); color:var(--text-dim); font-size:9px; }
|
|
3830
|
+
.shortcut-chord-hint {
|
|
3831
|
+
position:fixed;
|
|
3832
|
+
z-index:330;
|
|
3833
|
+
left:50%;
|
|
3834
|
+
bottom:22px;
|
|
3835
|
+
max-width:min(520px, calc(100vw - 32px));
|
|
3836
|
+
padding:7px 10px;
|
|
3837
|
+
border:1px solid var(--glass-border-2);
|
|
3838
|
+
border-radius:var(--radius-md);
|
|
3839
|
+
background:var(--modal-surface);
|
|
3840
|
+
color:var(--text);
|
|
3841
|
+
box-shadow:var(--shadow-md);
|
|
3842
|
+
font:10px var(--font-mono);
|
|
3843
|
+
opacity:0;
|
|
3844
|
+
visibility:hidden;
|
|
3845
|
+
transform:translate(-50%, 4px);
|
|
3846
|
+
transition:opacity var(--duration-fast) var(--ease-out-expo), transform var(--duration-fast) var(--ease-out-expo), visibility 0ms linear var(--duration-fast);
|
|
3847
|
+
}
|
|
3848
|
+
.shortcut-chord-hint.open { opacity:1; visibility:visible; transform:translate(-50%, 0); transition-delay:0ms; }
|
|
3849
|
+
|
|
3604
3850
|
/* ============================================================
|
|
3605
3851
|
SUB-WINDOW SYSTEM
|
|
3606
3852
|
============================================================ */
|
|
@@ -3702,6 +3948,7 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
3702
3948
|
}
|
|
3703
3949
|
|
|
3704
3950
|
.sub-win-close:hover { background: rgba(255,68,68,0.15); color: #ff6666; }
|
|
3951
|
+
.sub-win-close:focus-visible { outline:none; color:#ff7777; box-shadow:inset 0 0 0 2px currentColor; }
|
|
3705
3952
|
|
|
3706
3953
|
.sub-win-body {
|
|
3707
3954
|
flex: 1;
|
|
@@ -3734,6 +3981,81 @@ button:focus, select:focus, input:focus, textarea:focus, [contenteditable]:focus
|
|
|
3734
3981
|
|
|
3735
3982
|
.stab-btn:hover { background: rgba(255,255,255,0.05); color: var(--text); }
|
|
3736
3983
|
.stab-btn.active { background: rgba(91,120,255,0.12); color: var(--accent); border-color: rgba(91,120,255,0.25); }
|
|
3984
|
+
.stab-btn:focus-visible { outline:none; border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-glow); color:var(--text-bright); }
|
|
3985
|
+
|
|
3986
|
+
.plugin-tabs { overflow-x:auto; scrollbar-width:thin; }
|
|
3987
|
+
.plugin-tabs .stab-btn { flex:0 0 auto; }
|
|
3988
|
+
.plugin-panel { min-height:180px; margin-top:10px; }
|
|
3989
|
+
.plugin-panel-state { display:flex; align-items:flex-start; gap:10px; padding:14px; border:1px solid var(--glass-border-1); border-radius:var(--radius-md); background:var(--glass-bg-1); color:var(--text-dim); font-size:11px; line-height:1.5; }
|
|
3990
|
+
.plugin-panel-state::before { content:""; flex:0 0 auto; width:7px; height:7px; margin-top:5px; border-radius:50%; background:var(--nm-state-info); box-shadow:0 0 0 3px color-mix(in srgb, var(--nm-state-info) 14%, transparent); }
|
|
3991
|
+
.plugin-panel-state.error::before { background:var(--nm-state-danger); box-shadow:0 0 0 3px color-mix(in srgb, var(--nm-state-danger) 14%, transparent); }
|
|
3992
|
+
.plugin-panel-state.error { border-color:var(--notice-error-border); color:var(--notice-error-text); }
|
|
3993
|
+
.plugin-panel-state .sec-btn { flex:0 0 auto; margin-left:auto; }
|
|
3994
|
+
.plugin-toolbar { display:flex; align-items:center; gap:8px; margin-bottom:12px; }
|
|
3995
|
+
.plugin-toolbar-copy { flex:1; min-width:0; }
|
|
3996
|
+
.plugin-toolbar-title { color:var(--text-bright); font-size:13px; font-weight:650; }
|
|
3997
|
+
.plugin-toolbar-meta { margin-top:2px; color:var(--text-dim); font-size:10px; }
|
|
3998
|
+
.plugin-toolbar .sec-btn { flex:0 0 auto; }
|
|
3999
|
+
.plugin-search { width:min(220px, 38%); height:34px; padding:0 10px; border:1px solid var(--glass-border-2); border-radius:var(--radius-md); background:var(--control-bg); color:var(--text); font:11px var(--font-ui); }
|
|
4000
|
+
.plugin-search:focus { border-color:var(--accent); box-shadow:0 0 0 2px var(--accent-glow); }
|
|
4001
|
+
.plugin-section { margin-top:14px; }
|
|
4002
|
+
.plugin-section-head { display:flex; align-items:center; gap:8px; margin-bottom:8px; }
|
|
4003
|
+
.plugin-section-title { color:var(--text-bright); font-size:12px; font-weight:650; }
|
|
4004
|
+
.plugin-count-badge,
|
|
4005
|
+
.plugin-status-badge { display:inline-flex; align-items:center; min-height:20px; padding:1px 7px; border:1px solid var(--glass-border-2); border-radius:var(--radius-full); color:var(--text-dim); font-size:9px; font-weight:650; }
|
|
4006
|
+
.plugin-status-badge.enabled { border-color:color-mix(in srgb, var(--accent2) 45%, transparent); color:var(--accent2); }
|
|
4007
|
+
.plugin-status-badge.preview { border-color:color-mix(in srgb, var(--accent) 45%, transparent); color:var(--text-accent); }
|
|
4008
|
+
.plugin-empty { padding:18px 12px; border:1px dashed var(--glass-border-2); border-radius:var(--radius-md); color:var(--text-dim); text-align:center; font-size:11px; line-height:1.5; }
|
|
4009
|
+
.mcp-form-card { padding:12px; margin-bottom:14px; border:1px solid var(--glass-border-2); border-radius:var(--radius-md); background:var(--glass-bg-1); }
|
|
4010
|
+
.mcp-form-head { display:flex; align-items:flex-start; gap:10px; margin-bottom:12px; }
|
|
4011
|
+
.mcp-form-copy { flex:1; min-width:0; }
|
|
4012
|
+
.mcp-form-title { color:var(--text-bright); font-size:13px; font-weight:650; }
|
|
4013
|
+
.mcp-form-subtitle { margin-top:2px; color:var(--text-dim); font-size:10px; line-height:1.45; }
|
|
4014
|
+
.mcp-field-grid { display:grid; grid-template-columns:minmax(0,1fr) 130px; gap:10px; }
|
|
4015
|
+
.mcp-field { display:flex; flex-direction:column; gap:5px; margin-bottom:10px; }
|
|
4016
|
+
.mcp-field label { color:var(--text); font-size:10px; font-weight:600; }
|
|
4017
|
+
.mcp-input { width:100%; min-height:36px; padding:8px 10px; border:1px solid var(--glass-border-2); border-radius:var(--radius-md); background:var(--control-bg); color:var(--text); font:11px var(--font-ui); }
|
|
4018
|
+
textarea.mcp-input { min-height:76px; resize:vertical; font-family:var(--font-mono); line-height:1.5; }
|
|
4019
|
+
.mcp-input:focus { border-color:var(--accent); box-shadow:0 0 0 2px var(--accent-glow); }
|
|
4020
|
+
.mcp-field-help { margin-top:-1px; color:var(--text-dim); font-size:9px; line-height:1.45; word-break:break-word; }
|
|
4021
|
+
.mcp-enabled-check { display:inline-flex; align-items:center; gap:7px; color:var(--text); font-size:10px; cursor:pointer; }
|
|
4022
|
+
.mcp-enabled-check input { accent-color:var(--accent); }
|
|
4023
|
+
.mcp-form-actions { display:flex; align-items:center; justify-content:flex-end; gap:8px; margin-top:4px; }
|
|
4024
|
+
.mcp-form-actions .sec-btn { flex:0 0 auto; }
|
|
4025
|
+
.mcp-server-row { display:flex; align-items:center; gap:10px; padding:10px; margin:7px 0; border:1px solid var(--glass-border-1); border-radius:var(--radius-md); background:var(--glass-bg-1); }
|
|
4026
|
+
.mcp-server-copy { flex:1; min-width:0; }
|
|
4027
|
+
.mcp-server-title { display:flex; align-items:center; gap:6px; flex-wrap:wrap; color:var(--text-bright); font-size:12px; font-weight:650; }
|
|
4028
|
+
.mcp-server-meta { margin-top:4px; color:var(--text-dim); font:10px/1.45 var(--font-mono); overflow-wrap:anywhere; }
|
|
4029
|
+
.mcp-row-actions { display:flex; align-items:center; gap:5px; flex-wrap:wrap; justify-content:flex-end; }
|
|
4030
|
+
.mcp-row-actions .sec-btn { flex:0 0 auto; }
|
|
4031
|
+
.dsh-hero { padding:14px; border:1px solid var(--glass-border-2); border-radius:var(--radius-md); background:var(--glass-bg-1); }
|
|
4032
|
+
.dsh-hero-head { display:flex; align-items:flex-start; gap:10px; }
|
|
4033
|
+
.dsh-hero-copy { flex:1; min-width:0; }
|
|
4034
|
+
.dsh-title { color:var(--text-bright); font-size:14px; font-weight:700; }
|
|
4035
|
+
.dsh-description { margin-top:5px; color:var(--text-dim); font-size:11px; line-height:1.55; }
|
|
4036
|
+
.dsh-actions { display:flex; flex-wrap:wrap; gap:7px; margin-top:11px; }
|
|
4037
|
+
.dsh-actions .sec-btn { flex:0 0 auto; }
|
|
4038
|
+
.dsh-grid { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:10px; margin-top:10px; }
|
|
4039
|
+
.dsh-card { min-width:0; padding:11px; border:1px solid var(--glass-border-1); border-radius:var(--radius-md); background:var(--glass-bg-1); }
|
|
4040
|
+
.dsh-card-title { color:var(--text-bright); font-size:11px; font-weight:650; }
|
|
4041
|
+
.dsh-kv { display:grid; grid-template-columns:minmax(92px,auto) minmax(0,1fr); gap:5px 10px; margin-top:8px; font-size:10px; line-height:1.45; }
|
|
4042
|
+
.dsh-kv dt { color:var(--text-dim); }
|
|
4043
|
+
.dsh-kv dd { color:var(--text); overflow-wrap:anywhere; }
|
|
4044
|
+
.dsh-list { display:flex; flex-direction:column; gap:6px; margin-top:8px; }
|
|
4045
|
+
.dsh-list-item { padding:7px 8px; border:1px solid var(--glass-border-1); border-radius:var(--radius-sm); color:var(--text); font-size:10px; line-height:1.45; overflow-wrap:anywhere; }
|
|
4046
|
+
.dsh-list-item.warning { border-color:var(--notice-error-border); color:var(--notice-error-text); }
|
|
4047
|
+
.dsh-layer-profile { margin-top:10px; padding-top:9px; border-top:1px solid var(--glass-border-1); }
|
|
4048
|
+
.dsh-candidate-actions { display:flex; align-items:center; gap:7px; margin-top:7px; }
|
|
4049
|
+
.dsh-candidate-actions .sec-btn { flex:0 0 auto; }
|
|
4050
|
+
|
|
4051
|
+
@media (max-width: 560px) {
|
|
4052
|
+
.sub-win { width:calc(100vw - 20px); min-width:0; }
|
|
4053
|
+
.plugin-toolbar { align-items:stretch; flex-wrap:wrap; }
|
|
4054
|
+
.plugin-search { width:100%; order:3; }
|
|
4055
|
+
.mcp-field-grid, .dsh-grid { grid-template-columns:1fr; }
|
|
4056
|
+
.mcp-server-row { align-items:flex-start; flex-direction:column; }
|
|
4057
|
+
.mcp-row-actions { width:100%; justify-content:flex-start; }
|
|
4058
|
+
}
|
|
3737
4059
|
|
|
3738
4060
|
.stab-panel {
|
|
3739
4061
|
display: none;
|
|
@@ -4806,6 +5128,89 @@ html.newmark-memory-overview-viewer body {
|
|
|
4806
5128
|
|
|
4807
5129
|
.hidden { display: none !important; }
|
|
4808
5130
|
.no-select { user-select: none; -webkit-user-select: none; }
|
|
5131
|
+
|
|
5132
|
+
/* ============================================================
|
|
5133
|
+
NEWMARK CONVERSATION HIERARCHY (三级字体体系)
|
|
5134
|
+
最终回复 > Build 内联历史 > 工具调用 toolcall
|
|
5135
|
+
保持原有 DOM 结构不变,仅通过字体大小/行高/不透明度体现差异。
|
|
5136
|
+
============================================================ */
|
|
5137
|
+
|
|
5138
|
+
/* --- Level 1: 最终回复(最大、最醒目) --- */
|
|
5139
|
+
.chat-msg.assistant {
|
|
5140
|
+
font-size: 15px;
|
|
5141
|
+
line-height: 1.72;
|
|
5142
|
+
}
|
|
5143
|
+
|
|
5144
|
+
/* Build 块内的最终回复同样以 Level 1 呈现 */
|
|
5145
|
+
.chat-msg.run-final-response {
|
|
5146
|
+
font-size: 15px;
|
|
5147
|
+
line-height: 1.72;
|
|
5148
|
+
}
|
|
5149
|
+
|
|
5150
|
+
/* 用户消息保持可读的稍大字号 */
|
|
5151
|
+
.chat-msg.user {
|
|
5152
|
+
font-size: 14px;
|
|
5153
|
+
line-height: 1.65;
|
|
5154
|
+
}
|
|
5155
|
+
|
|
5156
|
+
/* --- Level 2: Build 内联历史(中等字号) --- */
|
|
5157
|
+
.conversation-work-event.narrative {
|
|
5158
|
+
font-size: 13px;
|
|
5159
|
+
line-height: 1.6;
|
|
5160
|
+
opacity: 0.9;
|
|
5161
|
+
}
|
|
5162
|
+
|
|
5163
|
+
/* Build 块标题保持中等偏小,作为历史导航 */
|
|
5164
|
+
.conversation-work-run-head {
|
|
5165
|
+
font-size: 12px;
|
|
5166
|
+
opacity: 0.78;
|
|
5167
|
+
}
|
|
5168
|
+
|
|
5169
|
+
/* --- Level 3: 工具调用 toolcall(最小、最淡、等宽) --- */
|
|
5170
|
+
.tool-event-summary {
|
|
5171
|
+
font-size: 11px;
|
|
5172
|
+
font-family: var(--font-mono);
|
|
5173
|
+
opacity: 0.78;
|
|
5174
|
+
}
|
|
5175
|
+
|
|
5176
|
+
.tool-event-content {
|
|
5177
|
+
font-size: 11px;
|
|
5178
|
+
font-family: var(--font-mono);
|
|
5179
|
+
line-height: 1.45;
|
|
5180
|
+
opacity: 0.72;
|
|
5181
|
+
color: var(--text-dim);
|
|
5182
|
+
}
|
|
5183
|
+
|
|
5184
|
+
/* 工具调用外的活动/状态项也归入 Level 3 */
|
|
5185
|
+
.conversation-work-event:not(.narrative):not(.guide):not(.error) {
|
|
5186
|
+
font-size: 11px;
|
|
5187
|
+
line-height: 1.45;
|
|
5188
|
+
opacity: 0.72;
|
|
5189
|
+
font-family: var(--font-mono);
|
|
5190
|
+
}
|
|
5191
|
+
|
|
5192
|
+
.conversation-work-event.activity-summary {
|
|
5193
|
+
font-size: 11px;
|
|
5194
|
+
}
|
|
5195
|
+
|
|
5196
|
+
/* 工具调用活动列表项保持最小字号 */
|
|
5197
|
+
.conversation-work-activity-item {
|
|
5198
|
+
font-size: 10.5px;
|
|
5199
|
+
opacity: 0.68;
|
|
5200
|
+
}
|
|
5201
|
+
|
|
5202
|
+
/* --- 层级间距调整,强化视觉层次 --- */
|
|
5203
|
+
.chat-msg.assistant { margin-top: 2px; }
|
|
5204
|
+
.chat-msg.run-final-response { margin-bottom: 6px; }
|
|
5205
|
+
.conversation-work-run { margin: 4px 0 7px; }
|
|
5206
|
+
|
|
5207
|
+
/* 浅色主题下放宽不透明度,保证可读性 */
|
|
5208
|
+
.light .tool-event-content,
|
|
5209
|
+
.light .tool-event-summary,
|
|
5210
|
+
.light .conversation-work-event:not(.narrative):not(.guide):not(.error) {
|
|
5211
|
+
opacity: 0.8;
|
|
5212
|
+
}
|
|
5213
|
+
|
|
4809
5214
|
</style>
|
|
4810
5215
|
</head>
|
|
4811
5216
|
<body>
|
|
@@ -4941,6 +5346,14 @@ html.newmark-memory-overview-viewer body {
|
|
|
4941
5346
|
<circle cx="15" cy="5" r="1" />
|
|
4942
5347
|
<circle cx="15" cy="19" r="1" />
|
|
4943
5348
|
</symbol>
|
|
5349
|
+
<symbol id="group" viewBox="0 0 24 24">
|
|
5350
|
+
<path d="M3 7V5c0-1.1.9-2 2-2h2" />
|
|
5351
|
+
<path d="M17 3h2c1.1 0 2 .9 2 2v2" />
|
|
5352
|
+
<path d="M21 17v2c0 1.1-.9 2-2 2h-2" />
|
|
5353
|
+
<path d="M7 21H5c-1.1 0-2-.9-2-2v-2" />
|
|
5354
|
+
<rect width="7" height="5" x="7" y="7" rx="1" />
|
|
5355
|
+
<rect width="7" height="5" x="10" y="12" rx="1" />
|
|
5356
|
+
</symbol>
|
|
4944
5357
|
<symbol id="image" viewBox="0 0 24 24">
|
|
4945
5358
|
<rect width="18" height="18" x="3" y="3" rx="2" ry="2" />
|
|
4946
5359
|
<circle cx="9" cy="9" r="2" />
|
|
@@ -4968,6 +5381,14 @@ html.newmark-memory-overview-viewer body {
|
|
|
4968
5381
|
<path d="m3 17 2 2 4-4" />
|
|
4969
5382
|
<path d="m3 7 2 2 4-4" />
|
|
4970
5383
|
</symbol>
|
|
5384
|
+
<symbol id="list" viewBox="0 0 24 24">
|
|
5385
|
+
<path d="M3 5h.01" />
|
|
5386
|
+
<path d="M3 12h.01" />
|
|
5387
|
+
<path d="M3 19h.01" />
|
|
5388
|
+
<path d="M8 5h13" />
|
|
5389
|
+
<path d="M8 12h13" />
|
|
5390
|
+
<path d="M8 19h13" />
|
|
5391
|
+
</symbol>
|
|
4971
5392
|
<symbol id="loader-circle" viewBox="0 0 24 24">
|
|
4972
5393
|
<path d="M21 12a9 9 0 1 1-6.219-8.56" />
|
|
4973
5394
|
</symbol>
|
|
@@ -5008,6 +5429,9 @@ html.newmark-memory-overview-viewer body {
|
|
|
5008
5429
|
<path d="m5 9-3 3 3 3" />
|
|
5009
5430
|
<path d="m9 5 3-3 3 3" />
|
|
5010
5431
|
</symbol>
|
|
5432
|
+
<symbol id="navigation" viewBox="0 0 24 24">
|
|
5433
|
+
<polygon points="3 11 22 2 13 21 11 13 3 11" />
|
|
5434
|
+
</symbol>
|
|
5011
5435
|
<symbol id="octagon-x" viewBox="0 0 24 24">
|
|
5012
5436
|
<path d="m15 9-6 6" />
|
|
5013
5437
|
<path d="M2.586 16.726A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2h6.624a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586z" />
|
|
@@ -5020,6 +5444,13 @@ html.newmark-memory-overview-viewer body {
|
|
|
5020
5444
|
<path d="M3 3h6l6 18h6" />
|
|
5021
5445
|
<path d="M14 3h7" />
|
|
5022
5446
|
</symbol>
|
|
5447
|
+
<symbol id="palette" viewBox="0 0 24 24">
|
|
5448
|
+
<path d="M12 22a1 1 0 0 1 0-20 10 9 0 0 1 10 9 5 5 0 0 1-5 5h-2.25a1.75 1.75 0 0 0-1.4 2.8l.3.4a1.75 1.75 0 0 1-1.4 2.8z" />
|
|
5449
|
+
<circle cx="13.5" cy="6.5" r=".5" fill="currentColor" />
|
|
5450
|
+
<circle cx="17.5" cy="10.5" r=".5" fill="currentColor" />
|
|
5451
|
+
<circle cx="6.5" cy="12.5" r=".5" fill="currentColor" />
|
|
5452
|
+
<circle cx="8.5" cy="7.5" r=".5" fill="currentColor" />
|
|
5453
|
+
</symbol>
|
|
5023
5454
|
<symbol id="panel-left-open" viewBox="0 0 24 24">
|
|
5024
5455
|
<rect width="18" height="18" x="3" y="3" rx="2" />
|
|
5025
5456
|
<path d="M9 3v18" />
|
|
@@ -5231,37 +5662,37 @@ html.newmark-memory-overview-viewer body {
|
|
|
5231
5662
|
<!-- Left Sidebar -->
|
|
5232
5663
|
<div id="left">
|
|
5233
5664
|
<div id="left-thumb">
|
|
5234
|
-
<
|
|
5235
|
-
<
|
|
5236
|
-
<
|
|
5237
|
-
<
|
|
5238
|
-
<
|
|
5239
|
-
<
|
|
5240
|
-
<
|
|
5665
|
+
<button type="button" class="lt-item" onclick="window.showNewConversationPage()" title="New conversation"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#message-square"></use></svg><span class="icon-only-label">New conversation</span></button>
|
|
5666
|
+
<button type="button" class="lt-item" onclick="window.showPluginList()" title="Plugins"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#plug"></use></svg><span class="icon-only-label">Plugins</span></button>
|
|
5667
|
+
<button type="button" class="lt-item" onclick="window.showMemoryLab()" title="Memory Lab"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#brain"></use></svg><span class="icon-only-label">Memory Lab</span></button>
|
|
5668
|
+
<button type="button" class="lt-item" onclick="window.showAutomationWindow()" title="Automation"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#calendar"></use></svg><span class="icon-only-label">Automation</span></button>
|
|
5669
|
+
<button type="button" class="lt-item" onclick="window.showFlowEditor()" title="Flow"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#workflow"></use></svg><span class="icon-only-label">Flow</span></button>
|
|
5670
|
+
<button type="button" class="lt-item" onclick="window.openSettings()" title="Settings"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#settings"></use></svg><span class="icon-only-label">Settings</span></button>
|
|
5671
|
+
<button type="button" class="lt-item" id="lt-ws-icon" onclick="window.toggleSecondarySidebar()" title="Workspaces"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#folder-open"></use></svg><span class="icon-only-label">Workspaces</span></button>
|
|
5241
5672
|
</div>
|
|
5242
5673
|
<div id="left-content">
|
|
5243
5674
|
<div style="padding:10px 12px 4px;font-size:10px;color:var(--text-dim);text-transform:uppercase;letter-spacing:0.05em;flex-shrink:0;">Tools</div>
|
|
5244
|
-
<
|
|
5675
|
+
<button type="button" class="left-nav-icon" onclick="window.showNewConversationPage()" title="New conversation">
|
|
5245
5676
|
<span class="icon"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#message-square"></use></svg></span><span>New chat</span>
|
|
5246
|
-
</
|
|
5247
|
-
<
|
|
5677
|
+
</button>
|
|
5678
|
+
<button type="button" class="left-nav-icon" onclick="window.showPluginList()">
|
|
5248
5679
|
<span class="icon"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#plug"></use></svg></span><span>Plugins</span>
|
|
5249
|
-
</
|
|
5250
|
-
<
|
|
5680
|
+
</button>
|
|
5681
|
+
<button type="button" class="left-nav-icon" onclick="window.showMemoryLab()">
|
|
5251
5682
|
<span class="icon"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#brain"></use></svg></span><span>Memory Lab</span>
|
|
5252
|
-
</
|
|
5253
|
-
<
|
|
5683
|
+
</button>
|
|
5684
|
+
<button type="button" class="left-nav-icon" onclick="window.showAutomationWindow()">
|
|
5254
5685
|
<span class="icon"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#calendar"></use></svg></span><span>Automation</span>
|
|
5255
|
-
</
|
|
5256
|
-
<
|
|
5686
|
+
</button>
|
|
5687
|
+
<button type="button" class="left-nav-icon" onclick="window.showFlowEditor()">
|
|
5257
5688
|
<span class="icon"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#workflow"></use></svg></span><span>Flow</span>
|
|
5258
|
-
</
|
|
5259
|
-
<
|
|
5689
|
+
</button>
|
|
5690
|
+
<button type="button" class="left-nav-icon" onclick="window.openSettings()">
|
|
5260
5691
|
<span class="icon"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#settings"></use></svg></span><span>Settings</span>
|
|
5261
|
-
</
|
|
5692
|
+
</button>
|
|
5262
5693
|
<div id="left-ws-section">
|
|
5263
5694
|
<div id="left-ws-header">Workspaces</div>
|
|
5264
|
-
<div id="left-ws-list"></div>
|
|
5695
|
+
<div id="left-ws-list" role="list" aria-label="Workspaces"></div>
|
|
5265
5696
|
<button id="left-ws-add" class="icon-label-btn" onclick="window.showNewWorkspaceDialog()"><svg class="nm-icon tiny" aria-hidden="true" focusable="false"><use href="#plus"></use></svg><span>New</span></button>
|
|
5266
5697
|
</div>
|
|
5267
5698
|
</div>
|
|
@@ -5275,11 +5706,11 @@ html.newmark-memory-overview-viewer body {
|
|
|
5275
5706
|
<button class="sec-btn primary icon-label-btn" onclick="window.newConversation()"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#message-square"></use></svg><span>New chat</span></button>
|
|
5276
5707
|
<button class="sec-btn" onclick="window.toggleLeftSecondary()" title="Collapse" style="flex:0;padding:6px 8px;"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#chevron-left"></use></svg><span class="icon-only-label">Collapse</span></button>
|
|
5277
5708
|
</div>
|
|
5278
|
-
|
|
5709
|
+
<div id="conversation-list" role="list" aria-label="Conversations"></div>
|
|
5279
5710
|
</div>
|
|
5280
5711
|
|
|
5281
5712
|
<!-- Resize Handle: left area (left + secondary) to center-stack -->
|
|
5282
|
-
<div class="resize-handle" data-side="right" data-target="left" title="Resize left sidebar"></div>
|
|
5713
|
+
<div class="resize-handle" data-side="right" data-target="left" role="separator" aria-orientation="vertical" aria-label="Resize left sidebar" tabindex="0" title="Resize left sidebar"></div>
|
|
5283
5714
|
|
|
5284
5715
|
<!-- Center Stack (chat + terminal) -->
|
|
5285
5716
|
<div id="center-stack">
|
|
@@ -5305,7 +5736,7 @@ html.newmark-memory-overview-viewer body {
|
|
|
5305
5736
|
<div id="todo-header" class="stack-row" onclick="window.toggleTodoCollapse()">
|
|
5306
5737
|
<span id="todo-header-label" class="stack-title">Task</span>
|
|
5307
5738
|
<span class="stack-actions">
|
|
5308
|
-
<button class="stack-icon-btn" onclick="event.stopPropagation();window.toggleTodoCollapse()" title="Expand tasks"><svg class="nm-icon tiny" aria-hidden="true" focusable="false"><use href="#chevron-up"></use></svg><span class="icon-only-label">Expand tasks</span></button>
|
|
5739
|
+
<button class="stack-icon-btn" aria-expanded="false" aria-controls="todo-list" onclick="event.stopPropagation();window.toggleTodoCollapse()" title="Expand tasks"><svg class="nm-icon tiny" aria-hidden="true" focusable="false"><use href="#chevron-up"></use></svg><span class="icon-only-label">Expand tasks</span></button>
|
|
5309
5740
|
</span>
|
|
5310
5741
|
</div>
|
|
5311
5742
|
<div id="todo-list"></div>
|
|
@@ -5317,7 +5748,7 @@ html.newmark-memory-overview-viewer body {
|
|
|
5317
5748
|
<span id="queue-header-label" class="stack-title">Next</span>
|
|
5318
5749
|
<span class="stack-actions">
|
|
5319
5750
|
<button class="stack-icon-btn" id="queue-pause-btn" onclick="event.stopPropagation();window.toggleQueuePause()" title="Pause queue" aria-pressed="false"><svg class="nm-icon tiny" aria-hidden="true" focusable="false"><use href="#pause"></use></svg><span class="icon-only-label">Pause queue</span></button>
|
|
5320
|
-
<button class="stack-icon-btn" id="queue-expand-btn" onclick="event.stopPropagation();window.toggleQueuePanel()" title="Expand queue"><svg class="nm-icon tiny" aria-hidden="true" focusable="false"><use href="#chevron-up"></use></svg><span class="icon-only-label">Expand queue</span></button>
|
|
5751
|
+
<button class="stack-icon-btn" id="queue-expand-btn" aria-expanded="false" aria-controls="queue-list" onclick="event.stopPropagation();window.toggleQueuePanel()" title="Expand queue"><svg class="nm-icon tiny" aria-hidden="true" focusable="false"><use href="#chevron-up"></use></svg><span class="icon-only-label">Expand queue</span></button>
|
|
5321
5752
|
</span>
|
|
5322
5753
|
</div>
|
|
5323
5754
|
<div id="queue-list"></div>
|
|
@@ -5361,8 +5792,9 @@ html.newmark-memory-overview-viewer body {
|
|
|
5361
5792
|
<div class="model-select-menu" id="model-select-menu" role="listbox" aria-label="Model" popover="manual"></div>
|
|
5362
5793
|
</div>
|
|
5363
5794
|
<div class="context-token-wrap">
|
|
5364
|
-
<
|
|
5795
|
+
<button type="button" id="context-token-ring" title="Context tokens" aria-haspopup="dialog" aria-expanded="false" onclick="window.toggleContextInspector()" onmouseenter="window.showContextWindowTooltip()" onmouseleave="window.hideContextWindowTooltip()" onfocus="window.showContextWindowTooltip()" onblur="window.hideContextWindowTooltip()"><span class="icon-only-label">Context tokens</span></button>
|
|
5365
5796
|
<div id="context-token-tooltip"></div>
|
|
5797
|
+
<div id="context-inspector" role="dialog" aria-label="Context management" aria-live="polite"></div>
|
|
5366
5798
|
</div>
|
|
5367
5799
|
<select class="tool-select" id="intel-select">
|
|
5368
5800
|
<option value="low">low</option>
|
|
@@ -5376,7 +5808,7 @@ html.newmark-memory-overview-viewer body {
|
|
|
5376
5808
|
<button class="mode-toggle-btn active" data-mode="guide" onclick="window.setInputMode('guide')">Guide</button>
|
|
5377
5809
|
<button class="mode-toggle-btn" data-mode="next" onclick="window.setInputMode('next')">Next</button>
|
|
5378
5810
|
</div>
|
|
5379
|
-
<button id="submit-btn" onclick="window.submitCurrentAction()" title="Send"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#send"></use></svg><span class="icon-only-label">Send</span></button>
|
|
5811
|
+
<button id="submit-btn" onclick="window.submitCurrentAction('click')" title="Send"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#send"></use></svg><span class="icon-only-label">Send</span></button>
|
|
5380
5812
|
</div>
|
|
5381
5813
|
</div>
|
|
5382
5814
|
</div>
|
|
@@ -5384,7 +5816,7 @@ html.newmark-memory-overview-viewer body {
|
|
|
5384
5816
|
<!-- Bottom Terminal -->
|
|
5385
5817
|
<div id="bottom" class="open">
|
|
5386
5818
|
<div id="bottom-header">
|
|
5387
|
-
<div id="terminal-tabs"></div>
|
|
5819
|
+
<div id="terminal-tabs" role="tablist" aria-label="Terminals"></div>
|
|
5388
5820
|
<select id="terminal-shell-select" onchange="window.spawnTerminal(this.value)">
|
|
5389
5821
|
<option value="powershell" data-platform-shell="win32">PowerShell</option>
|
|
5390
5822
|
<option value="cmd" data-platform-shell="win32">CMD</option>
|
|
@@ -5402,7 +5834,7 @@ html.newmark-memory-overview-viewer body {
|
|
|
5402
5834
|
<div class="terminal-output"><span style="color:var(--text-dim);opacity:0.5;">Terminal ready</span></div>
|
|
5403
5835
|
<div class="terminal-input-row">
|
|
5404
5836
|
<span class="terminal-prompt">PS></span>
|
|
5405
|
-
<input class="terminal-input" type="text" placeholder="Enter command..." onfocus="window.ensureTerminalStarted&&window.ensureTerminalStarted()" onkeydown="if(event.key==='Enter')window.terminalSend()">
|
|
5837
|
+
<input class="terminal-input" type="text" placeholder="Enter command..." onfocus="window.ensureTerminalStarted&&window.ensureTerminalStarted()" onkeydown="if(event.key==='Enter'&&!event.isComposing&&event.key!=='Process'&&event.keyCode!==229)window.terminalSend()">
|
|
5406
5838
|
</div>
|
|
5407
5839
|
</div>
|
|
5408
5840
|
</div>
|
|
@@ -5410,25 +5842,25 @@ html.newmark-memory-overview-viewer body {
|
|
|
5410
5842
|
</div>
|
|
5411
5843
|
|
|
5412
5844
|
<!-- Right Resize Handle -->
|
|
5413
|
-
<div class="resize-handle" data-side="left" data-target="right" title="Resize right sidebar"></div>
|
|
5845
|
+
<div class="resize-handle" data-side="left" data-target="right" role="separator" aria-orientation="vertical" aria-label="Resize right sidebar" tabindex="0" title="Resize right sidebar"></div>
|
|
5414
5846
|
|
|
5415
5847
|
<!-- Right Sidebar -->
|
|
5416
5848
|
<div id="right" class="open">
|
|
5417
|
-
<div id="right-tabs">
|
|
5418
|
-
<button class="tab-btn active" data-tab="file-tree" onclick="window.switchRightTab('file-tree')" title="Files"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#folder"></use></svg><span class="icon-only-label">Files</span></button>
|
|
5419
|
-
<button class="tab-btn" data-tab="editor" onclick="window.switchRightTab('editor')" title="Editor"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#square-pen"></use></svg><span class="icon-only-label">Editor</span></button>
|
|
5420
|
-
<button class="tab-btn" data-tab="plan" onclick="window.switchRightTab('plan')" title="Conversation plan"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#list-checks"></use></svg><span class="icon-only-label">Conversation plan</span></button>
|
|
5421
|
-
<button class="tab-btn" data-tab="subagent" onclick="window.switchRightTab('subagent')" title="Subagents"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#bot"></use></svg><span class="icon-only-label">Subagents</span></button>
|
|
5422
|
-
<button class="tab-btn" data-tab="browser" onclick="window.switchRightTab('browser')" title="Browser"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#globe"></use></svg><span class="icon-only-label">Browser</span></button>
|
|
5849
|
+
<div id="right-tabs" role="tablist" aria-label="Right sidebar">
|
|
5850
|
+
<button class="tab-btn active" id="right-tab-file-tree" role="tab" aria-selected="true" aria-controls="panel-file-tree" tabindex="0" data-tab="file-tree" onclick="window.switchRightTab('file-tree')" onkeydown="window.handleRightTabKey(event)" title="Files"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#folder"></use></svg><span class="icon-only-label">Files</span></button>
|
|
5851
|
+
<button class="tab-btn" id="right-tab-editor" role="tab" aria-selected="false" aria-controls="panel-editor" tabindex="-1" data-tab="editor" onclick="window.switchRightTab('editor')" onkeydown="window.handleRightTabKey(event)" title="Editor"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#square-pen"></use></svg><span class="icon-only-label">Editor</span></button>
|
|
5852
|
+
<button class="tab-btn" id="right-tab-plan" role="tab" aria-selected="false" aria-controls="panel-plan" tabindex="-1" data-tab="plan" onclick="window.switchRightTab('plan')" onkeydown="window.handleRightTabKey(event)" title="Conversation plan"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#list-checks"></use></svg><span class="icon-only-label">Conversation plan</span></button>
|
|
5853
|
+
<button class="tab-btn" id="right-tab-subagent" role="tab" aria-selected="false" aria-controls="panel-subagent" tabindex="-1" data-tab="subagent" onclick="window.switchRightTab('subagent')" onkeydown="window.handleRightTabKey(event)" title="Subagents"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#bot"></use></svg><span class="icon-only-label">Subagents</span></button>
|
|
5854
|
+
<button class="tab-btn" id="right-tab-browser" role="tab" aria-selected="false" aria-controls="panel-browser" tabindex="-1" data-tab="browser" onclick="window.switchRightTab('browser')" onkeydown="window.handleRightTabKey(event)" title="Browser"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#globe"></use></svg><span class="icon-only-label">Browser</span></button>
|
|
5423
5855
|
<div class="tab-divider"></div>
|
|
5424
5856
|
<button class="tab-btn" onclick="window.toggleRight()" title="Close right sidebar"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#x"></use></svg><span class="icon-only-label">Close right sidebar</span></button>
|
|
5425
5857
|
</div>
|
|
5426
5858
|
<div id="right-content">
|
|
5427
|
-
<div class="tab-panel active" id="panel-file-tree">
|
|
5859
|
+
<div class="tab-panel active" id="panel-file-tree" role="tabpanel" aria-labelledby="right-tab-file-tree">
|
|
5428
5860
|
<div style="font-size:11px;color:var(--text-dim);margin-bottom:8px;">Workspace file tree</div>
|
|
5429
|
-
<div id="file-tree-container"></div>
|
|
5861
|
+
<div id="file-tree-container" role="tree"></div>
|
|
5430
5862
|
</div>
|
|
5431
|
-
<div class="tab-panel" id="panel-editor">
|
|
5863
|
+
<div class="tab-panel" id="panel-editor" role="tabpanel" aria-labelledby="right-tab-editor" hidden>
|
|
5432
5864
|
<div class="editor-toolbar">
|
|
5433
5865
|
<button class="et-btn" onclick="window.saveEditor()" title="Save" aria-label="Save"><svg class="nm-icon" aria-hidden="true" focusable="false"><use href="#save"></use></svg></button>
|
|
5434
5866
|
<button class="et-btn editor-view-btn" id="editor-md-toggle" onclick="window.toggleEditorMarkdownPreview()" title="Markdown preview" aria-label="Markdown preview"><svg class="nm-icon" aria-hidden="true" focusable="false"><use href="#book-open"></use></svg></button>
|
|
@@ -5444,22 +5876,22 @@ html.newmark-memory-overview-viewer body {
|
|
|
5444
5876
|
<div class="editor-status"><span class="editor-vim-mode" id="editor-vim-mode">INSERT</span><span id="editor-language">text</span><span id="editor-position">1:1</span><span style="margin-left:auto" id="editor-dirty"></span></div>
|
|
5445
5877
|
</div>
|
|
5446
5878
|
</div>
|
|
5447
|
-
<div class="tab-panel" id="panel-plan">
|
|
5879
|
+
<div class="tab-panel" id="panel-plan" role="tabpanel" aria-labelledby="right-tab-plan" hidden>
|
|
5448
5880
|
<div class="right-section-head"><span class="right-section-title">Conversation plan</span><button class="archive-action-btn" onclick="window.refreshConversationPlan()">Refresh</button></div>
|
|
5449
5881
|
<div id="conversation-plan-content"></div>
|
|
5450
5882
|
<div class="right-section-head linked-plan-head"><span class="right-section-title">Linked plan</span><span class="right-row-meta" id="linked-plan-revision"></span></div>
|
|
5451
5883
|
<div id="linked-plan-content" class="linked-plan-reader md-rendered" aria-live="polite"></div>
|
|
5452
5884
|
</div>
|
|
5453
|
-
<div class="tab-panel" id="panel-subagent">
|
|
5885
|
+
<div class="tab-panel" id="panel-subagent" role="tabpanel" aria-labelledby="right-tab-subagent" hidden>
|
|
5454
5886
|
<div style="font-size:11px;color:var(--text-dim);margin-bottom:8px;">Subagents</div>
|
|
5455
5887
|
<div id="subagent-list"></div>
|
|
5456
5888
|
</div>
|
|
5457
|
-
<div class="tab-panel" id="panel-browser">
|
|
5889
|
+
<div class="tab-panel" id="panel-browser" role="tabpanel" aria-labelledby="right-tab-browser" hidden>
|
|
5458
5890
|
<div class="browser-url-bar">
|
|
5459
5891
|
<button class="shell-btn browser-action-btn" onclick="window.browserBack()" title="Back"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#chevron-left"></use></svg><span class="icon-only-label">Back</span></button>
|
|
5460
5892
|
<button class="shell-btn browser-action-btn" onclick="window.browserForward()" title="Forward"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#chevron-right"></use></svg><span class="icon-only-label">Forward</span></button>
|
|
5461
5893
|
<button class="shell-btn browser-action-btn" onclick="window.browserReload()" title="Reload"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#refresh-cw"></use></svg><span class="icon-only-label">Reload</span></button>
|
|
5462
|
-
<input class="browser-url-input" id="browser-url" placeholder="Enter URL..." onkeydown="if(event.key==='Enter')window.navigateBrowser(this.value)">
|
|
5894
|
+
<input class="browser-url-input" id="browser-url" placeholder="Enter URL..." onkeydown="if(event.key==='Enter'&&!event.isComposing&&event.key!=='Process'&&event.keyCode!==229)window.navigateBrowser(this.value)">
|
|
5463
5895
|
<button class="shell-btn" onclick="window.navigateBrowser(document.getElementById('browser-url').value)" title="Go"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#send"></use></svg><span class="icon-only-label">Go</span></button>
|
|
5464
5896
|
<button class="shell-btn" id="computer-use-toggle" onclick="window.toggleComputerUse()" title="ComputerUse: enabled for this conversation" aria-pressed="true">CU</button>
|
|
5465
5897
|
</div>
|
|
@@ -5476,7 +5908,7 @@ html.newmark-memory-overview-viewer body {
|
|
|
5476
5908
|
|
|
5477
5909
|
<!-- ========== SUB-WINDOW OVERLAY ========== -->
|
|
5478
5910
|
<div class="sub-win-overlay" id="sub-win-overlay" onclick="if(event.target===this)window.closeSubWin()">
|
|
5479
|
-
<div class="sub-win" id="sub-win">
|
|
5911
|
+
<div class="sub-win" id="sub-win" role="dialog" aria-modal="true" aria-labelledby="sub-win-title" tabindex="-1">
|
|
5480
5912
|
<div class="sub-win-header" id="sub-win-header">
|
|
5481
5913
|
<span class="sub-win-title" id="sub-win-title">Window</span>
|
|
5482
5914
|
<button class="sub-win-close" onclick="window.closeSubWin()" title="Close"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#x"></use></svg><span class="icon-only-label">Close</span></button>
|
|
@@ -5484,6 +5916,21 @@ html.newmark-memory-overview-viewer body {
|
|
|
5484
5916
|
<div class="sub-win-body" id="sub-win-body"></div>
|
|
5485
5917
|
</div>
|
|
5486
5918
|
</div>
|
|
5919
|
+
<div class="command-surface-overlay" id="command-surface-overlay" onclick="if(event.target===this)window.closeCommandSurface()">
|
|
5920
|
+
<section class="command-surface" id="command-surface" role="dialog" aria-modal="true" aria-labelledby="command-surface-title" tabindex="-1">
|
|
5921
|
+
<header class="command-surface-header">
|
|
5922
|
+
<div class="command-surface-heading">
|
|
5923
|
+
<div class="command-surface-title" id="command-surface-title"></div>
|
|
5924
|
+
<div class="command-surface-subtitle" id="command-surface-subtitle"></div>
|
|
5925
|
+
</div>
|
|
5926
|
+
<button type="button" class="command-surface-close" onclick="window.closeCommandSurface()" aria-label="Close"><svg class="nm-icon small" aria-hidden="true" focusable="false"><use href="#x"></use></svg></button>
|
|
5927
|
+
</header>
|
|
5928
|
+
<div class="command-search-wrap"><input class="command-search" id="command-search" type="search" autocomplete="off" role="combobox" aria-autocomplete="list" aria-expanded="true" aria-controls="command-list"></div>
|
|
5929
|
+
<div class="command-list" id="command-list" role="listbox"></div>
|
|
5930
|
+
<footer class="command-surface-footer" id="command-surface-footer"></footer>
|
|
5931
|
+
</section>
|
|
5932
|
+
</div>
|
|
5933
|
+
<div class="shortcut-chord-hint" id="shortcut-chord-hint" role="status" aria-live="polite"></div>
|
|
5487
5934
|
<script>
|
|
5488
5935
|
/* ============================================================
|
|
5489
5936
|
NEWMARK AGENT - Complete UI Controller v2.0
|
|
@@ -5579,6 +6026,8 @@ var state = {
|
|
|
5579
6026
|
automationItems: [],
|
|
5580
6027
|
contextCompression: null,
|
|
5581
6028
|
contextWindow: null,
|
|
6029
|
+
contextInspectorOpen: false,
|
|
6030
|
+
contextMutationPending: false,
|
|
5582
6031
|
flowWorks: [],
|
|
5583
6032
|
activeAgentRunning: false,
|
|
5584
6033
|
editorPath: '',
|
|
@@ -5596,6 +6045,9 @@ var state = {
|
|
|
5596
6045
|
editorCompletionText: '',
|
|
5597
6046
|
editorCompletionRequest: 0,
|
|
5598
6047
|
editorCompletionAnchor: null,
|
|
6048
|
+
editorCompletionCache: [],
|
|
6049
|
+
editorCompletionInFlight: false,
|
|
6050
|
+
editorCompletionStreamText: '',
|
|
5599
6051
|
editorCaretSignature: '',
|
|
5600
6052
|
editorPredictionEnabled: true,
|
|
5601
6053
|
editorCompletionTimer: null,
|
|
@@ -5651,7 +6103,14 @@ var state = {
|
|
|
5651
6103
|
githubOverviewPendingRepo: '',
|
|
5652
6104
|
mcpServers: [],
|
|
5653
6105
|
mcpDiscovered: [],
|
|
6106
|
+
dshCompatibility: null,
|
|
5654
6107
|
mcpEditingId: '',
|
|
6108
|
+
mcpDraft: null,
|
|
6109
|
+
mcpSearchQuery: '',
|
|
6110
|
+
mcpMutationPending: false,
|
|
6111
|
+
mcpMutationGeneration: 0,
|
|
6112
|
+
mcpFormFocusRequested: false,
|
|
6113
|
+
pluginPanelGeneration: 0,
|
|
5655
6114
|
skillMarketQuery: '',
|
|
5656
6115
|
memoryLab: null,
|
|
5657
6116
|
memoryLabComponentContents: {},
|
|
@@ -5720,6 +6179,48 @@ var NEWMARK_I18N = {
|
|
|
5720
6179
|
en: {
|
|
5721
6180
|
'app.ready': 'Ready',
|
|
5722
6181
|
'app.subtitle': 'Enter an instruction to begin. Enter sends. Shift+Enter inserts a newline.',
|
|
6182
|
+
'shortcuts.paletteTitle': 'Command palette',
|
|
6183
|
+
'shortcuts.helpTitle': 'Keyboard shortcuts',
|
|
6184
|
+
'shortcuts.paletteSubtitle': 'Search every registered Newmark GUI command. Shortcuts never replace standard editing keys.',
|
|
6185
|
+
'shortcuts.helpSubtitle': 'Common desktop keys plus conflict-safe Newmark command chords.',
|
|
6186
|
+
'shortcuts.searchCommands': 'Search commands...',
|
|
6187
|
+
'shortcuts.searchShortcuts': 'Search commands or shortcuts...',
|
|
6188
|
+
'shortcuts.noResults': 'No matching commands.',
|
|
6189
|
+
'shortcuts.footer': 'Up/Down navigate · Enter runs · Esc closes · Tab stays inside this dialog',
|
|
6190
|
+
'shortcuts.category.general': 'General',
|
|
6191
|
+
'shortcuts.category.navigation': 'Navigation',
|
|
6192
|
+
'shortcuts.category.workspace': 'Workspace and chat',
|
|
6193
|
+
'shortcuts.category.layout': 'Layout and focus',
|
|
6194
|
+
'shortcuts.category.input': 'Input and modes',
|
|
6195
|
+
'shortcuts.category.editor': 'Editor',
|
|
6196
|
+
'shortcuts.category.browser': 'Browser',
|
|
6197
|
+
'shortcuts.category.terminal': 'Terminal',
|
|
6198
|
+
'shortcuts.category.context': 'Context controls',
|
|
6199
|
+
'shortcuts.context.global': 'Application',
|
|
6200
|
+
'shortcuts.context.prompt': 'Prompt',
|
|
6201
|
+
'shortcuts.context.editor': 'Editor only',
|
|
6202
|
+
'shortcuts.context.browser': 'Browser only',
|
|
6203
|
+
'shortcuts.context.terminal': 'Terminal only',
|
|
6204
|
+
'shortcuts.context.dialog': 'Dialog',
|
|
6205
|
+
'shortcuts.openPalette': 'Open command palette',
|
|
6206
|
+
'shortcuts.openHelp': 'Show keyboard shortcuts',
|
|
6207
|
+
'shortcuts.focusPrimary': 'Focus primary input',
|
|
6208
|
+
'shortcuts.focusNext': 'Focus next application region',
|
|
6209
|
+
'shortcuts.focusPrevious': 'Focus previous application region',
|
|
6210
|
+
'shortcuts.toggleLeft': 'Toggle left sidebar',
|
|
6211
|
+
'shortcuts.toggleWorkspacePanel': 'Toggle workspace and conversation panel',
|
|
6212
|
+
'shortcuts.toggleRight': 'Toggle right sidebar',
|
|
6213
|
+
'shortcuts.toggleTerminal': 'Toggle terminal',
|
|
6214
|
+
'shortcuts.nextConversation': 'Next conversation',
|
|
6215
|
+
'shortcuts.previousConversation': 'Previous conversation',
|
|
6216
|
+
'shortcuts.nextBranch': 'Next branch',
|
|
6217
|
+
'shortcuts.previousBranch': 'Previous branch',
|
|
6218
|
+
'shortcuts.scrollBottom': 'Scroll chat to bottom',
|
|
6219
|
+
'shortcuts.newTerminal': 'New terminal',
|
|
6220
|
+
'shortcuts.focusTerminal': 'Focus terminal input',
|
|
6221
|
+
'shortcuts.focusBrowserAddress': 'Focus browser address',
|
|
6222
|
+
'shortcuts.toggleTheme': 'Toggle light and dark theme',
|
|
6223
|
+
'shortcuts.chordHint': '{prefix} waiting for: {keys}',
|
|
5723
6224
|
'top.minimize': 'Minimize',
|
|
5724
6225
|
'top.maximize': 'Maximize',
|
|
5725
6226
|
'top.close': 'Close',
|
|
@@ -5731,12 +6232,14 @@ var NEWMARK_I18N = {
|
|
|
5731
6232
|
'left.flow': 'Flow',
|
|
5732
6233
|
'left.settings': 'Settings',
|
|
5733
6234
|
'left.workspaces': 'Workspaces',
|
|
6235
|
+
'left.conversations': 'Conversations',
|
|
5734
6236
|
'left.new': 'New',
|
|
5735
6237
|
'left.collapse': 'Collapse left sidebar',
|
|
5736
6238
|
'left.collapseSecondary': 'Collapse workspace panel',
|
|
5737
6239
|
'input.placeholder': 'Input instruction...',
|
|
5738
6240
|
'input.send': 'Send',
|
|
5739
6241
|
'input.stop': 'Stop',
|
|
6242
|
+
'input.continue': 'Continue',
|
|
5740
6243
|
'input.guide': 'Guide',
|
|
5741
6244
|
'input.next': 'Next',
|
|
5742
6245
|
'mode.build': 'Build',
|
|
@@ -6063,9 +6566,16 @@ var NEWMARK_I18N = {
|
|
|
6063
6566
|
'flow.nextDisabled': 'Flow only accepts Guide input; Next is disabled.',
|
|
6064
6567
|
'flow.saved': 'Flow saved',
|
|
6065
6568
|
'flow.emptyRun': 'Flow is empty and cannot run.',
|
|
6569
|
+
'flow.noAvailable': 'No workflows are available to run.',
|
|
6066
6570
|
'flow.started': 'Flow started',
|
|
6067
6571
|
'plugins.title': 'Plugins',
|
|
6572
|
+
'plugins.tabMcp': 'MCP',
|
|
6573
|
+
'plugins.tabDsh': 'DSH Plugin',
|
|
6574
|
+
'plugins.tabSkills': 'Skills',
|
|
6575
|
+
'plugins.tabMarket': 'Market',
|
|
6576
|
+
'plugins.tabGithub': 'GitHub',
|
|
6068
6577
|
'plugins.mcp': 'MCP Management',
|
|
6578
|
+
'plugins.dsh': 'DSH Plugin',
|
|
6069
6579
|
'plugins.management': 'Skills Management',
|
|
6070
6580
|
'plugins.market': 'Skills Market',
|
|
6071
6581
|
'plugins.github': 'GitHub CLI',
|
|
@@ -6123,6 +6633,74 @@ var NEWMARK_I18N = {
|
|
|
6123
6633
|
'plugins.mcpNoServers': 'No user MCP servers.',
|
|
6124
6634
|
'plugins.mcpDiscovered': 'Discovered from plugins',
|
|
6125
6635
|
'plugins.mcpStored': 'User MCP servers',
|
|
6636
|
+
'plugins.mcpConfiguredCount': '{count} configured',
|
|
6637
|
+
'plugins.mcpSearch': 'Search MCP servers...',
|
|
6638
|
+
'plugins.mcpNoMatch': 'No MCP servers match this search.',
|
|
6639
|
+
'plugins.mcpRefresh': 'Refresh',
|
|
6640
|
+
'plugins.mcpRefreshing': 'Refreshing MCP servers...',
|
|
6641
|
+
'plugins.mcpLoadError': 'MCP servers could not be loaded.',
|
|
6642
|
+
'plugins.mcpUnavailable': 'MCP management is unavailable in this interface.',
|
|
6643
|
+
'plugins.mcpAddTitle': 'Add MCP server',
|
|
6644
|
+
'plugins.mcpEditTitle': 'Edit MCP server',
|
|
6645
|
+
'plugins.mcpReviewTitle': 'Review MCP candidate',
|
|
6646
|
+
'plugins.mcpFormHelp': 'Review every field before saving. Imported candidates always start disabled.',
|
|
6647
|
+
'plugins.mcpEnabled': 'Enable this server after saving',
|
|
6648
|
+
'plugins.mcpEndpointStdio': 'Command',
|
|
6649
|
+
'plugins.mcpEndpointHttp': 'Server URL',
|
|
6650
|
+
'plugins.mcpCwd': 'Working directory (optional)',
|
|
6651
|
+
'plugins.mcpSecretsHelp': 'When editing, leave blank to preserve saved values; enter {} to clear them. Secret values are never displayed.',
|
|
6652
|
+
'plugins.mcpSavedEnvKeys': 'Saved environment keys: {keys}',
|
|
6653
|
+
'plugins.mcpSavedHeaderKeys': 'Saved header keys: {keys}',
|
|
6654
|
+
'plugins.mcpNoSavedKeys': 'No saved keys.',
|
|
6655
|
+
'plugins.mcpInvalidArgs': 'Arguments must be a JSON array.',
|
|
6656
|
+
'plugins.mcpInvalidObject': '{field} must be a JSON object.',
|
|
6657
|
+
'plugins.mcpRequiredName': 'Enter a server name.',
|
|
6658
|
+
'plugins.mcpRequiredCommand': 'Enter a command for this stdio server.',
|
|
6659
|
+
'plugins.mcpRequiredUrl': 'Enter an http(s) URL for this server.',
|
|
6660
|
+
'plugins.mcpSaving': 'Saving...',
|
|
6661
|
+
'plugins.mcpSaved': 'MCP server saved.',
|
|
6662
|
+
'plugins.mcpEnabledStatus': 'Enabled',
|
|
6663
|
+
'plugins.mcpDisabledStatus': 'Disabled',
|
|
6664
|
+
'plugins.mcpMutationFailed': 'MCP operation failed.',
|
|
6665
|
+
'plugins.mcpRemoveConfirm': 'Remove MCP server "{name}"?',
|
|
6666
|
+
'plugins.mcpReadonly': 'Read-only metadata',
|
|
6667
|
+
'plugins.mcpDiscoveredEmpty': 'No MCP metadata was discovered from installed plugins.',
|
|
6668
|
+
'plugins.mcpStoredEmpty': 'No user MCP servers yet. Add one or review a compatible DSH candidate.',
|
|
6669
|
+
'plugins.mcpReviewImport': 'Review and import',
|
|
6670
|
+
'plugins.mcpCandidateHelp': 'This only pre-fills the MCP form. Nothing is installed, executed, or enabled automatically.',
|
|
6671
|
+
'plugins.retry': 'Retry',
|
|
6672
|
+
'plugins.dshTitle': 'DSH Plugin compatibility',
|
|
6673
|
+
'plugins.dshHelp': 'Developer preview: inspect the locally available official DSH CLI and package configuration. Discovery is read-only and never installs, executes, updates, or rewrites DSH.',
|
|
6674
|
+
'plugins.dshPreview': 'Developer preview',
|
|
6675
|
+
'plugins.dshRescan': 'Rescan',
|
|
6676
|
+
'plugins.dshScanning': 'Scanning DSH compatibility...',
|
|
6677
|
+
'plugins.dshLoadError': 'DSH compatibility information could not be loaded.',
|
|
6678
|
+
'plugins.dshUnavailable': 'DSH discovery is unavailable in this interface.',
|
|
6679
|
+
'plugins.dshCli': 'CLI and package',
|
|
6680
|
+
'plugins.dshCliPath': 'CLI path',
|
|
6681
|
+
'plugins.dshCliVersion': 'CLI version',
|
|
6682
|
+
'plugins.dshPackageVersion': 'Package version',
|
|
6683
|
+
'plugins.dshHome': 'DSH_HOME',
|
|
6684
|
+
'plugins.dshHomeSource': 'Home source',
|
|
6685
|
+
'plugins.dshConfigFiles': 'Configuration files',
|
|
6686
|
+
'plugins.dshLayers': 'Configuration layer order',
|
|
6687
|
+
'plugins.dshLayerOrder': 'Later layers override earlier rows; unknown keys remain visible and untouched.',
|
|
6688
|
+
'plugins.dshHomePatches': 'Home-level patches',
|
|
6689
|
+
'plugins.dshUpdateability': 'Updateability: use official DSH tooling or edit the shown patch files; Newmark never rewrites them.',
|
|
6690
|
+
'plugins.dshUpdateChannel': 'Update channel',
|
|
6691
|
+
'plugins.dshLatestChannel': 'latest (not locked)',
|
|
6692
|
+
'plugins.dshProfiles': 'Profiles',
|
|
6693
|
+
'plugins.dshBundles': 'Bundles',
|
|
6694
|
+
'plugins.dshWarnings': 'Warnings',
|
|
6695
|
+
'plugins.dshUnknownKeys': 'Unknown keys',
|
|
6696
|
+
'plugins.dshMcpCandidates': 'MCP candidates',
|
|
6697
|
+
'plugins.dshNone': 'None discovered',
|
|
6698
|
+
'plugins.dshNotAvailable': 'Not available',
|
|
6699
|
+
'plugins.dshOfficialRepo': 'Official repository',
|
|
6700
|
+
'plugins.dshOfficialDocs': 'Documentation',
|
|
6701
|
+
'plugins.dshOfficialNpm': 'npm package',
|
|
6702
|
+
'plugins.dshReadonly': 'Read-only compatibility policy',
|
|
6703
|
+
'plugins.dshReadonlyDetail': 'Newmark only reads local compatibility metadata. Use official DSH tooling to install, execute, update, or change DSH configuration.',
|
|
6126
6704
|
'workspace.new': 'New workspace',
|
|
6127
6705
|
'workspace.type': 'Type',
|
|
6128
6706
|
'workspace.internal': 'Internal workspace',
|
|
@@ -6222,6 +6800,21 @@ var NEWMARK_I18N = {
|
|
|
6222
6800
|
'status.contextModeModel': 'model',
|
|
6223
6801
|
'status.messages': 'messages',
|
|
6224
6802
|
'status.noCompression': 'No compression event in this conversation',
|
|
6803
|
+
'status.contextInspector': 'Context management',
|
|
6804
|
+
'status.contextInspectorHint': 'DSH-inspired live budget; visible chat history stays unchanged.',
|
|
6805
|
+
'status.activeBuild': 'Active Build',
|
|
6806
|
+
'status.longHistory': 'Long history',
|
|
6807
|
+
'status.trigger': 'Trigger',
|
|
6808
|
+
'status.retention': 'Retention',
|
|
6809
|
+
'status.hotCache': 'Hot cache',
|
|
6810
|
+
'status.coldArchive': 'Cold archive',
|
|
6811
|
+
'status.lastCompression': 'Last compression',
|
|
6812
|
+
'status.noCompressionShort': 'No compression yet',
|
|
6813
|
+
'status.compressNow': 'Compress now',
|
|
6814
|
+
'status.compressing': 'Compressing...',
|
|
6815
|
+
'status.compressedNow': 'Context compressed.',
|
|
6816
|
+
'status.compressionFailed': 'Context compression failed.',
|
|
6817
|
+
'status.compressionBusy': 'Compression is unavailable while this conversation is running.',
|
|
6225
6818
|
'status.recentFiles': 'Recent file changes',
|
|
6226
6819
|
'status.noFileChanges': 'No file changes recorded for the latest run.',
|
|
6227
6820
|
'status.pendingOptions': 'Pending options',
|
|
@@ -6242,6 +6835,8 @@ var NEWMARK_I18N = {
|
|
|
6242
6835
|
'conversation.reorderFailed': 'Could not save the conversation order.',
|
|
6243
6836
|
'conversation.pin': 'Pin conversation',
|
|
6244
6837
|
'conversation.unpin': 'Unpin conversation',
|
|
6838
|
+
'conversation.branchCommunication': 'Allow branch communication',
|
|
6839
|
+
'conversation.branchCommunicationBadge': 'Branch communication',
|
|
6245
6840
|
'conversation.loadingIsolated': 'Loading isolated conversation...',
|
|
6246
6841
|
'conversation.locked': 'Current conversation is locked while the agent is working.',
|
|
6247
6842
|
'queue.next': 'Next',
|
|
@@ -6285,6 +6880,48 @@ var NEWMARK_I18N = {
|
|
|
6285
6880
|
zh: {
|
|
6286
6881
|
'app.ready': '就绪',
|
|
6287
6882
|
'app.subtitle': '输入指令开始。Enter 发送,Shift+Enter 换行。',
|
|
6883
|
+
'shortcuts.paletteTitle': '命令面板',
|
|
6884
|
+
'shortcuts.helpTitle': '键盘快捷键',
|
|
6885
|
+
'shortcuts.paletteSubtitle': '搜索并执行所有已注册的 Newmark GUI 命令;不会覆盖标准文本编辑按键。',
|
|
6886
|
+
'shortcuts.helpSubtitle': '通用桌面快捷键与避免冲突的 Newmark 命令序列。',
|
|
6887
|
+
'shortcuts.searchCommands': '搜索命令...',
|
|
6888
|
+
'shortcuts.searchShortcuts': '搜索命令或快捷键...',
|
|
6889
|
+
'shortcuts.noResults': '没有匹配的命令。',
|
|
6890
|
+
'shortcuts.footer': '上/下选择 · Enter 执行 · Esc 关闭 · Tab 保持在对话框内',
|
|
6891
|
+
'shortcuts.category.general': '通用',
|
|
6892
|
+
'shortcuts.category.navigation': '导航',
|
|
6893
|
+
'shortcuts.category.workspace': '工作区与对话',
|
|
6894
|
+
'shortcuts.category.layout': '布局与焦点',
|
|
6895
|
+
'shortcuts.category.input': '输入与模式',
|
|
6896
|
+
'shortcuts.category.editor': '编辑器',
|
|
6897
|
+
'shortcuts.category.browser': '浏览器',
|
|
6898
|
+
'shortcuts.category.terminal': '终端',
|
|
6899
|
+
'shortcuts.category.context': '上下文操作',
|
|
6900
|
+
'shortcuts.context.global': '应用',
|
|
6901
|
+
'shortcuts.context.prompt': '输入框',
|
|
6902
|
+
'shortcuts.context.editor': '仅编辑器',
|
|
6903
|
+
'shortcuts.context.browser': '仅浏览器',
|
|
6904
|
+
'shortcuts.context.terminal': '仅终端',
|
|
6905
|
+
'shortcuts.context.dialog': '对话框',
|
|
6906
|
+
'shortcuts.openPalette': '打开命令面板',
|
|
6907
|
+
'shortcuts.openHelp': '显示键盘快捷键',
|
|
6908
|
+
'shortcuts.focusPrimary': '聚焦主要输入框',
|
|
6909
|
+
'shortcuts.focusNext': '聚焦下一个应用区域',
|
|
6910
|
+
'shortcuts.focusPrevious': '聚焦上一个应用区域',
|
|
6911
|
+
'shortcuts.toggleLeft': '切换左侧边栏',
|
|
6912
|
+
'shortcuts.toggleWorkspacePanel': '切换工作区与对话面板',
|
|
6913
|
+
'shortcuts.toggleRight': '切换右侧边栏',
|
|
6914
|
+
'shortcuts.toggleTerminal': '切换终端',
|
|
6915
|
+
'shortcuts.nextConversation': '下一个对话',
|
|
6916
|
+
'shortcuts.previousConversation': '上一个对话',
|
|
6917
|
+
'shortcuts.nextBranch': '下一个分支',
|
|
6918
|
+
'shortcuts.previousBranch': '上一个分支',
|
|
6919
|
+
'shortcuts.scrollBottom': '滚动到对话底部',
|
|
6920
|
+
'shortcuts.newTerminal': '新建终端',
|
|
6921
|
+
'shortcuts.focusTerminal': '聚焦终端输入框',
|
|
6922
|
+
'shortcuts.focusBrowserAddress': '聚焦浏览器地址栏',
|
|
6923
|
+
'shortcuts.toggleTheme': '切换明暗主题',
|
|
6924
|
+
'shortcuts.chordHint': '{prefix} 等待:{keys}',
|
|
6288
6925
|
'top.minimize': '最小化',
|
|
6289
6926
|
'top.maximize': '最大化',
|
|
6290
6927
|
'top.close': '关闭',
|
|
@@ -6296,12 +6933,14 @@ var NEWMARK_I18N = {
|
|
|
6296
6933
|
'left.flow': '工作流',
|
|
6297
6934
|
'left.settings': '设置',
|
|
6298
6935
|
'left.workspaces': '工作区',
|
|
6936
|
+
'left.conversations': '对话',
|
|
6299
6937
|
'left.new': '新建',
|
|
6300
6938
|
'left.collapse': '折叠左侧栏',
|
|
6301
6939
|
'left.collapseSecondary': '折叠工作区面板',
|
|
6302
6940
|
'input.placeholder': '输入指令...',
|
|
6303
6941
|
'input.send': '发送',
|
|
6304
6942
|
'input.stop': '停止',
|
|
6943
|
+
'input.continue': '继续',
|
|
6305
6944
|
'input.guide': 'Guide',
|
|
6306
6945
|
'input.next': 'Next',
|
|
6307
6946
|
'mode.build': 'Build',
|
|
@@ -6628,9 +7267,16 @@ var NEWMARK_I18N = {
|
|
|
6628
7267
|
'flow.nextDisabled': 'Flow 仅允许 Guide 输入,已禁用 Next。',
|
|
6629
7268
|
'flow.saved': 'Flow 已保存',
|
|
6630
7269
|
'flow.emptyRun': 'Flow 为空,无法运行。',
|
|
7270
|
+
'flow.noAvailable': '当前没有可运行的工作流。',
|
|
6631
7271
|
'flow.started': 'Flow 已启动',
|
|
6632
7272
|
'plugins.title': '插件',
|
|
7273
|
+
'plugins.tabMcp': 'MCP',
|
|
7274
|
+
'plugins.tabDsh': 'DSH Plugin',
|
|
7275
|
+
'plugins.tabSkills': 'Skills',
|
|
7276
|
+
'plugins.tabMarket': 'Market',
|
|
7277
|
+
'plugins.tabGithub': 'GitHub',
|
|
6633
7278
|
'plugins.mcp': 'MCP 管理',
|
|
7279
|
+
'plugins.dsh': 'DSH Plugin',
|
|
6634
7280
|
'plugins.management': 'Skills 管理',
|
|
6635
7281
|
'plugins.market': 'Skills Market',
|
|
6636
7282
|
'plugins.github': 'GitHub CLI',
|
|
@@ -6688,6 +7334,74 @@ var NEWMARK_I18N = {
|
|
|
6688
7334
|
'plugins.mcpNoServers': '暂无用户 MCP 服务器。',
|
|
6689
7335
|
'plugins.mcpDiscovered': '从插件发现',
|
|
6690
7336
|
'plugins.mcpStored': '用户 MCP 服务器',
|
|
7337
|
+
'plugins.mcpConfiguredCount': '已配置 {count} 项',
|
|
7338
|
+
'plugins.mcpSearch': '搜索 MCP 服务器...',
|
|
7339
|
+
'plugins.mcpNoMatch': '没有符合搜索条件的 MCP 服务器。',
|
|
7340
|
+
'plugins.mcpRefresh': '刷新',
|
|
7341
|
+
'plugins.mcpRefreshing': '正在刷新 MCP 服务器...',
|
|
7342
|
+
'plugins.mcpLoadError': '无法加载 MCP 服务器。',
|
|
7343
|
+
'plugins.mcpUnavailable': '当前界面不支持 MCP 管理。',
|
|
7344
|
+
'plugins.mcpAddTitle': '添加 MCP 服务器',
|
|
7345
|
+
'plugins.mcpEditTitle': '编辑 MCP 服务器',
|
|
7346
|
+
'plugins.mcpReviewTitle': '审核 MCP 候选项',
|
|
7347
|
+
'plugins.mcpFormHelp': '保存前请审核所有字段。从候选项导入时始终默认禁用。',
|
|
7348
|
+
'plugins.mcpEnabled': '保存后启用此服务器',
|
|
7349
|
+
'plugins.mcpEndpointStdio': '命令',
|
|
7350
|
+
'plugins.mcpEndpointHttp': '服务器 URL',
|
|
7351
|
+
'plugins.mcpCwd': '工作目录(可选)',
|
|
7352
|
+
'plugins.mcpSecretsHelp': '编辑时留空可保留已保存的值;输入 {} 可清空。界面绝不显示密钥值。',
|
|
7353
|
+
'plugins.mcpSavedEnvKeys': '已保存环境变量键:{keys}',
|
|
7354
|
+
'plugins.mcpSavedHeaderKeys': '已保存请求头键:{keys}',
|
|
7355
|
+
'plugins.mcpNoSavedKeys': '没有已保存的键。',
|
|
7356
|
+
'plugins.mcpInvalidArgs': '参数必须是 JSON 数组。',
|
|
7357
|
+
'plugins.mcpInvalidObject': '{field} 必须是 JSON 对象。',
|
|
7358
|
+
'plugins.mcpRequiredName': '请输入服务器名称。',
|
|
7359
|
+
'plugins.mcpRequiredCommand': '请输入 stdio 服务器命令。',
|
|
7360
|
+
'plugins.mcpRequiredUrl': '请输入 http(s) 服务器 URL。',
|
|
7361
|
+
'plugins.mcpSaving': '正在保存...',
|
|
7362
|
+
'plugins.mcpSaved': 'MCP 服务器已保存。',
|
|
7363
|
+
'plugins.mcpEnabledStatus': '已启用',
|
|
7364
|
+
'plugins.mcpDisabledStatus': '已禁用',
|
|
7365
|
+
'plugins.mcpMutationFailed': 'MCP 操作失败。',
|
|
7366
|
+
'plugins.mcpRemoveConfirm': '移除 MCP 服务器“{name}”?',
|
|
7367
|
+
'plugins.mcpReadonly': '只读元数据',
|
|
7368
|
+
'plugins.mcpDiscoveredEmpty': '未从已安装插件中发现 MCP 元数据。',
|
|
7369
|
+
'plugins.mcpStoredEmpty': '暂无用户 MCP 服务器。可以添加服务器,或审核兼容的 DSH 候选项。',
|
|
7370
|
+
'plugins.mcpReviewImport': '审核并导入',
|
|
7371
|
+
'plugins.mcpCandidateHelp': '此操作只会预填 MCP 表单,不会安装、执行或自动启用任何内容。',
|
|
7372
|
+
'plugins.retry': '重试',
|
|
7373
|
+
'plugins.dshTitle': 'DSH Plugin 兼容',
|
|
7374
|
+
'plugins.dshHelp': '开发者预览:检查本地官方 DSH CLI 与包配置。发现过程严格只读,绝不会安装、执行、更新或改写 DSH。',
|
|
7375
|
+
'plugins.dshPreview': '开发者预览',
|
|
7376
|
+
'plugins.dshRescan': '重新扫描',
|
|
7377
|
+
'plugins.dshScanning': '正在扫描 DSH 兼容信息...',
|
|
7378
|
+
'plugins.dshLoadError': '无法加载 DSH 兼容信息。',
|
|
7379
|
+
'plugins.dshUnavailable': '当前界面不支持 DSH 发现。',
|
|
7380
|
+
'plugins.dshCli': 'CLI 与软件包',
|
|
7381
|
+
'plugins.dshCliPath': 'CLI 路径',
|
|
7382
|
+
'plugins.dshCliVersion': 'CLI 版本',
|
|
7383
|
+
'plugins.dshPackageVersion': '软件包版本',
|
|
7384
|
+
'plugins.dshHome': 'DSH_HOME',
|
|
7385
|
+
'plugins.dshHomeSource': '目录来源',
|
|
7386
|
+
'plugins.dshConfigFiles': '配置文件',
|
|
7387
|
+
'plugins.dshLayers': '配置层顺序',
|
|
7388
|
+
'plugins.dshLayerOrder': '后面的层覆盖前面的条目;未知键会被展示但不会改写。',
|
|
7389
|
+
'plugins.dshHomePatches': 'Home 级 patch',
|
|
7390
|
+
'plugins.dshUpdateability': '可更新性:请使用官方 DSH 工具或编辑下方 patch 文件;Newmark 不会重写这些文件。',
|
|
7391
|
+
'plugins.dshUpdateChannel': '更新通道',
|
|
7392
|
+
'plugins.dshLatestChannel': 'latest(未锁定)',
|
|
7393
|
+
'plugins.dshProfiles': 'Profiles',
|
|
7394
|
+
'plugins.dshBundles': 'Bundles',
|
|
7395
|
+
'plugins.dshWarnings': '警告',
|
|
7396
|
+
'plugins.dshUnknownKeys': '未知配置键',
|
|
7397
|
+
'plugins.dshMcpCandidates': 'MCP 候选项',
|
|
7398
|
+
'plugins.dshNone': '未发现',
|
|
7399
|
+
'plugins.dshNotAvailable': '不可用',
|
|
7400
|
+
'plugins.dshOfficialRepo': '官方仓库',
|
|
7401
|
+
'plugins.dshOfficialDocs': '官方文档',
|
|
7402
|
+
'plugins.dshOfficialNpm': 'npm 软件包',
|
|
7403
|
+
'plugins.dshReadonly': '只读兼容策略',
|
|
7404
|
+
'plugins.dshReadonlyDetail': 'Newmark 只读取本地兼容元数据。安装、执行、更新或更改 DSH 配置请使用官方 DSH 工具。',
|
|
6691
7405
|
'workspace.new': '新建工作区',
|
|
6692
7406
|
'workspace.type': '类型',
|
|
6693
7407
|
'workspace.internal': '内部工作区',
|
|
@@ -6787,6 +7501,21 @@ var NEWMARK_I18N = {
|
|
|
6787
7501
|
'status.contextModeModel': '模型',
|
|
6788
7502
|
'status.messages': '条消息',
|
|
6789
7503
|
'status.noCompression': '当前对话暂无压缩事件',
|
|
7504
|
+
'status.contextInspector': '上下文管理',
|
|
7505
|
+
'status.contextInspectorHint': '借鉴 DSH 的动态预算;可见对话历史不会被改写。',
|
|
7506
|
+
'status.activeBuild': '当前 Build',
|
|
7507
|
+
'status.longHistory': '长期历史',
|
|
7508
|
+
'status.trigger': '触发线',
|
|
7509
|
+
'status.retention': '保留量',
|
|
7510
|
+
'status.hotCache': '热缓存',
|
|
7511
|
+
'status.coldArchive': '冷归档',
|
|
7512
|
+
'status.lastCompression': '最近一次压缩',
|
|
7513
|
+
'status.noCompressionShort': '尚未压缩',
|
|
7514
|
+
'status.compressNow': '立即压缩',
|
|
7515
|
+
'status.compressing': '正在压缩...',
|
|
7516
|
+
'status.compressedNow': '上下文已压缩。',
|
|
7517
|
+
'status.compressionFailed': '上下文压缩失败。',
|
|
7518
|
+
'status.compressionBusy': '对话运行中,暂时无法压缩上下文。',
|
|
6790
7519
|
'status.recentFiles': '最近文件变更',
|
|
6791
7520
|
'status.noFileChanges': '最近一轮没有记录文件变更。',
|
|
6792
7521
|
'status.pendingOptions': '待处理选项',
|
|
@@ -6807,6 +7536,8 @@ var NEWMARK_I18N = {
|
|
|
6807
7536
|
'conversation.reorderFailed': '无法保存对话顺序。',
|
|
6808
7537
|
'conversation.pin': '置顶对话',
|
|
6809
7538
|
'conversation.unpin': '取消置顶对话',
|
|
7539
|
+
'conversation.branchCommunication': '允许分支交流',
|
|
7540
|
+
'conversation.branchCommunicationBadge': '分支交流',
|
|
6810
7541
|
'conversation.loadingIsolated': '正在加载隔离对话...',
|
|
6811
7542
|
'conversation.locked': 'Agent 工作中,当前对话已锁定。',
|
|
6812
7543
|
'queue.next': '下一轮',
|
|
@@ -6931,6 +7662,10 @@ function applyLanguageToUi() {
|
|
|
6931
7662
|
}
|
|
6932
7663
|
var wsHead = document.getElementById('left-ws-header');
|
|
6933
7664
|
if (wsHead) wsHead.textContent = t('left.workspaces');
|
|
7665
|
+
var wsList = document.getElementById('left-ws-list');
|
|
7666
|
+
if (wsList) wsList.setAttribute('aria-label', t('left.workspaces'));
|
|
7667
|
+
var conversationList = document.getElementById('conversation-list');
|
|
7668
|
+
if (conversationList) conversationList.setAttribute('aria-label', t('left.conversations'));
|
|
6934
7669
|
var wsAdd = document.querySelector('#left-ws-add span:last-child');
|
|
6935
7670
|
if (wsAdd) wsAdd.textContent = t('left.new');
|
|
6936
7671
|
setTitleAndLabel('.secondary-top button[onclick="window.openWsSettings()"]', t('workspace.settingsTitle'));
|
|
@@ -6956,6 +7691,10 @@ function applyLanguageToUi() {
|
|
|
6956
7691
|
if (browserUrl) browserUrl.setAttribute('placeholder', t('browser.url'));
|
|
6957
7692
|
var terminalInputs = document.querySelectorAll('.terminal-input');
|
|
6958
7693
|
for (var ti = 0; ti < terminalInputs.length; ti++) terminalInputs[ti].setAttribute('placeholder', t('terminal.enterCommand'));
|
|
7694
|
+
var terminalTabs = document.getElementById('terminal-tabs');
|
|
7695
|
+
if (terminalTabs) terminalTabs.setAttribute('aria-label', t('shortcuts.category.terminal'));
|
|
7696
|
+
var fileTree = document.getElementById('file-tree-container');
|
|
7697
|
+
if (fileTree) fileTree.setAttribute('aria-label', t('right.fileTree'));
|
|
6959
7698
|
var terminalReady = document.querySelector('#terminal-pane-0 .terminal-output span');
|
|
6960
7699
|
if (terminalReady && terminalReady.textContent === 'Terminal ready') terminalReady.textContent = t('terminal.ready');
|
|
6961
7700
|
var terminalStatusSpans = document.querySelectorAll('.terminal-output span');
|
|
@@ -8218,6 +8957,8 @@ window.toggleWorkReview = function(head) {
|
|
|
8218
8957
|
var review = head && head.closest ? head.closest('.work-review') : null;
|
|
8219
8958
|
if (!review) return;
|
|
8220
8959
|
review.classList.toggle('collapsed');
|
|
8960
|
+
var toggle = review.querySelector('.work-review-toggle');
|
|
8961
|
+
if (toggle) toggle.setAttribute('aria-expanded', review.classList.contains('collapsed') ? 'false' : 'true');
|
|
8221
8962
|
};
|
|
8222
8963
|
|
|
8223
8964
|
window.toggleWorkReviewFiles = function(button) {
|
|
@@ -8322,22 +9063,33 @@ function addWorkReview(diffs) {
|
|
|
8322
9063
|
review.innerHTML = '<div class="work-review-head" onclick="window.toggleWorkReview(this)"><div class="work-review-mark">' + iconSvg('file-diff', t('review.fileChanges'), 'small') + '</div>' +
|
|
8323
9064
|
'<div><div class="work-review-title">' + esc(editedLabel) + '</div><div class="work-review-stats"><span class="work-review-add">+' + added + '</span><span class="work-review-del">-' + deleted + '</span></div></div>' +
|
|
8324
9065
|
'<div class="work-review-actions"><button class="work-review-btn" onclick="window.openWorkReview(this);event.stopPropagation()">' + esc(t('review.open')) + '</button>' +
|
|
8325
|
-
'<span class="work-review-chevron" aria-hidden="true"></span></div></div>' +
|
|
9066
|
+
'<button type="button" class="work-review-toggle" aria-expanded="false" onclick="event.stopPropagation();window.toggleWorkReview(this)" title="' + escAttr(t('queue.expand')) + '"><span class="work-review-chevron" aria-hidden="true"></span><span class="icon-only-label">' + esc(t('queue.expand')) + '</span></button></div></div>' +
|
|
8326
9067
|
'<div class="work-review-list">' + rows + (files.length > 3 ? '<button class="work-review-more" onclick="window.toggleWorkReviewFiles(this)">' + esc(t('review.showMore').replace('{count}', files.length - 3)) + '</button>' : '') + '</div>';
|
|
8327
9068
|
els['chat-area'].appendChild(review);
|
|
8328
9069
|
autoScrollIfAtBottom();
|
|
8329
9070
|
return review;
|
|
8330
9071
|
}
|
|
8331
9072
|
|
|
8332
|
-
|
|
9073
|
+
var STREAMING_PLAIN_TEXT_THRESHOLD = 12000;
|
|
9074
|
+
var STREAMING_LARGE_TEXT_INTERVAL_MS = 100;
|
|
9075
|
+
|
|
9076
|
+
function updateMsg(div, text, role, mode, model, options) {
|
|
8333
9077
|
if (!div) return;
|
|
8334
9078
|
if (role) div.className = 'chat-msg ' + role;
|
|
8335
9079
|
text = redactSensitiveText(text);
|
|
8336
9080
|
div._newmarkMessageText = String(text || '');
|
|
8337
9081
|
var body = div.querySelector('.msg-body');
|
|
8338
|
-
|
|
9082
|
+
var streaming = !!(options && options.streaming);
|
|
9083
|
+
if (body) {
|
|
9084
|
+
// Re-running the full Markdown parser and rebuilding the entire message
|
|
9085
|
+
// DOM for every streamed token makes long responses monopolize the
|
|
9086
|
+
// renderer event loop. Keep large in-flight responses as one safe text
|
|
9087
|
+
// node; the terminal `done`/`final_response` path renders Markdown once.
|
|
9088
|
+
if (streaming && String(text || '').length >= STREAMING_PLAIN_TEXT_THRESHOLD) body.textContent = text;
|
|
9089
|
+
else body.innerHTML = renderMessageContent(text);
|
|
9090
|
+
}
|
|
8339
9091
|
var meta = div.querySelector('.meta');
|
|
8340
|
-
if (meta && (mode || model)) {
|
|
9092
|
+
if (meta && (mode || model) && !streaming) {
|
|
8341
9093
|
var roleLabel = div.classList.contains('user')
|
|
8342
9094
|
? (String(mode || '').toLowerCase() === 'flow-user-input' ? t('flow.userInput') : t('message.user'))
|
|
8343
9095
|
: (div.classList.contains('workflow') ? t('message.workflow') : (div.classList.contains('system') ? t('message.system') : t('message.agent')));
|
|
@@ -8746,6 +9498,60 @@ function setConversationRuntimeState(target, status, runId, extra) {
|
|
|
8746
9498
|
return next;
|
|
8747
9499
|
}
|
|
8748
9500
|
|
|
9501
|
+
// A renderer send marks its target as provisionally running before the IPC
|
|
9502
|
+
// request reaches the target runtime. Escape/Stop can therefore arrive in
|
|
9503
|
+
// that handoff window while the backend still reports `not_running`. Remember
|
|
9504
|
+
// the exact provisional run so the pending send can be cancelled before it
|
|
9505
|
+
// allocates a provider request; once the backend has a real run, the normal
|
|
9506
|
+
// target-scoped stop path takes over.
|
|
9507
|
+
function markProvisionalStop(target, runId) {
|
|
9508
|
+
if (!state.pendingProvisionalStops) state.pendingProvisionalStops = {};
|
|
9509
|
+
state.pendingProvisionalStops[runtimeKeyFor(target.workspaceId, target.conversationId)] = String(runId || '');
|
|
9510
|
+
}
|
|
9511
|
+
|
|
9512
|
+
function pendingProvisionalStopRunId(target) {
|
|
9513
|
+
var key = runtimeKeyFor(target.workspaceId, target.conversationId);
|
|
9514
|
+
if (!state.pendingProvisionalStops || !Object.prototype.hasOwnProperty.call(state.pendingProvisionalStops, key)) return undefined;
|
|
9515
|
+
return state.pendingProvisionalStops[key];
|
|
9516
|
+
}
|
|
9517
|
+
|
|
9518
|
+
function clearProvisionalStop(target) {
|
|
9519
|
+
if (state.pendingProvisionalStops) delete state.pendingProvisionalStops[runtimeKeyFor(target.workspaceId, target.conversationId)];
|
|
9520
|
+
}
|
|
9521
|
+
|
|
9522
|
+
function consumeProvisionalStop(target, runId) {
|
|
9523
|
+
var pending = pendingProvisionalStopRunId(target);
|
|
9524
|
+
if (pending === undefined || String(pending) !== String(runId || '')) return false;
|
|
9525
|
+
clearProvisionalStop(target);
|
|
9526
|
+
return true;
|
|
9527
|
+
}
|
|
9528
|
+
|
|
9529
|
+
function requestBackendStopForProvisionalStart(target, runId) {
|
|
9530
|
+
var stopPromise = api.stopConversation
|
|
9531
|
+
? api.stopConversation({ target: target, runId: String(runId || ''), force: false })
|
|
9532
|
+
: (api.abortConversation ? api.abortConversation(target) : Promise.resolve({ action: 'not_running' }));
|
|
9533
|
+
Promise.resolve(stopPromise).then(function(result) {
|
|
9534
|
+
var action = String(result && result.action || '');
|
|
9535
|
+
if (action === 'not_running' || action === 'stale') {
|
|
9536
|
+
return refreshConversationRuntimeAfterStopRace(target, runId, result);
|
|
9537
|
+
}
|
|
9538
|
+
if (action === 'force' || String(result && result.status || '') === 'force_interrupted') {
|
|
9539
|
+
setConversationRuntimeState(target, 'force_interrupted', runId, { provisional: false });
|
|
9540
|
+
return;
|
|
9541
|
+
}
|
|
9542
|
+
if (action === 'graceful') {
|
|
9543
|
+
setConversationRuntimeState(target, 'stopping', runId, { provisional: false });
|
|
9544
|
+
return;
|
|
9545
|
+
}
|
|
9546
|
+
if (result === true || ['idle', 'interrupted'].indexOf(String(result && result.status || '')) >= 0) {
|
|
9547
|
+
setConversationRuntimeState(target, 'interrupted', runId, { provisional: false });
|
|
9548
|
+
}
|
|
9549
|
+
}).catch(function(error) {
|
|
9550
|
+
setConversationRuntimeState(target, 'running', runId, { provisional: false });
|
|
9551
|
+
showUiNotice(error && error.message ? error.message : String(error), 'error', 'stop-provisional-' + runtimeKeyFor(target.workspaceId, target.conversationId) + '-' + String(runId || ''));
|
|
9552
|
+
});
|
|
9553
|
+
}
|
|
9554
|
+
|
|
8749
9555
|
function formatWorkDuration(milliseconds) {
|
|
8750
9556
|
var seconds = Math.max(0, Math.floor(Number(milliseconds || 0) / 1000));
|
|
8751
9557
|
var hours = Math.floor(seconds / 3600);
|
|
@@ -8792,7 +9598,7 @@ function publicWorkEvent(event) {
|
|
|
8792
9598
|
var content = String(event && event.content || '');
|
|
8793
9599
|
var toolArgs = String(event && event.toolArgs || '');
|
|
8794
9600
|
if (/<think(?:\s|>)/i.test(content) || /<\/think>/i.test(content) || /<\/?think\b|(?:reasoning_content|thinking_delta)\s*[::]/i.test(toolArgs)) return false;
|
|
8795
|
-
return ['start', 'text', 'response', 'final_response', 'status', 'tool_call', 'tool_result', 'guide', 'guide_accepted', 'guide_applied', 'guide_deferred', 'guide_rejected', 'done', 'error', 'interrupted', 'force_interrupted'].indexOf(type) >= 0;
|
|
9601
|
+
return ['start', 'text', 'response', 'final_response', 'status', 'tool_call', 'tool_result', 'thought', 'thought_result', 'guide', 'guide_accepted', 'guide_applied', 'guide_deferred', 'guide_rejected', 'done', 'error', 'interrupted', 'force_interrupted'].indexOf(type) >= 0;
|
|
8796
9602
|
}
|
|
8797
9603
|
|
|
8798
9604
|
function publicToolNameForUi(value) {
|
|
@@ -9051,7 +9857,12 @@ function syncWorkRunsSnapshot(runs, target, branchId) {
|
|
|
9051
9857
|
return item;
|
|
9052
9858
|
});
|
|
9053
9859
|
state.workRunsByBranch[workRunBranchKey(target, selectedBranchId)] = normalized;
|
|
9054
|
-
|
|
9860
|
+
// 串分支修复:全局显示列表(workRunsByTarget)只在 sync 的分支就是「浏览分支」时
|
|
9861
|
+
// 才更新。当运行分支(runtime)的 streaming 结果到达、而用户正在浏览另一个分支时,
|
|
9862
|
+
// 只按分支存储(workRunsByBranch),不污染当前浏览分支的显示。
|
|
9863
|
+
if (selectedBranchId === branchIds.viewed) {
|
|
9864
|
+
state.workRunsByTarget[key] = normalized;
|
|
9865
|
+
}
|
|
9055
9866
|
return normalized;
|
|
9056
9867
|
}
|
|
9057
9868
|
|
|
@@ -9343,6 +10154,23 @@ function renderWorkToolGroup(event, eventIndex) {
|
|
|
9343
10154
|
activityRows + '</div></details>';
|
|
9344
10155
|
}
|
|
9345
10156
|
|
|
10157
|
+
function renderWorkThought(event, eventIndex) {
|
|
10158
|
+
var zh = currentLang() === 'zh';
|
|
10159
|
+
var content = String(event.content || '').trim();
|
|
10160
|
+
var completed = !!event.completed;
|
|
10161
|
+
var activityDomKey = String(event.id || ('thought-' + eventIndex));
|
|
10162
|
+
var label = completed ? (zh ? '进行了思考' : 'Thought') : (zh ? '思考中' : 'Thinking');
|
|
10163
|
+
var detailRows = '';
|
|
10164
|
+
if (content) {
|
|
10165
|
+
detailRows = '<div class="conversation-work-thought-text">' + esc(content) + '</div>';
|
|
10166
|
+
} else if (!completed) {
|
|
10167
|
+
detailRows = '<div class="conversation-work-thought-text conversation-work-thought-pending">' + esc(zh ? '正在思考…' : 'Thinking…') + '</div>';
|
|
10168
|
+
}
|
|
10169
|
+
return '<details class="conversation-work-activity conversation-work-thought" data-activity-key="' + escAttr(activityDomKey) + '"><summary>' +
|
|
10170
|
+
iconSvg('brain', 'thought', 'tiny') + '<span>' + esc(label) + '</span>' +
|
|
10171
|
+
'<span class="conversation-work-activity-chevron" aria-hidden="true"></span></summary>' + detailRows + '</details>';
|
|
10172
|
+
}
|
|
10173
|
+
|
|
9346
10174
|
function workEventLabel(event) {
|
|
9347
10175
|
var type = String(event && event.type || 'status').toLowerCase();
|
|
9348
10176
|
var content = String(event && event.content || '').trim();
|
|
@@ -9447,6 +10275,16 @@ function renderWorkRunEvents(run, includeGuides) {
|
|
|
9447
10275
|
}
|
|
9448
10276
|
if (!rawEvent) continue;
|
|
9449
10277
|
}
|
|
10278
|
+
if (rawType === 'thought_result') {
|
|
10279
|
+
for (var thoughtPriorIndex = events.length - 1; thoughtPriorIndex >= 0; thoughtPriorIndex--) {
|
|
10280
|
+
var thoughtPrior = events[thoughtPriorIndex];
|
|
10281
|
+
if (String(thoughtPrior && thoughtPrior.type || '').toLowerCase() !== 'thought' || thoughtPrior.completed) continue;
|
|
10282
|
+
events[thoughtPriorIndex] = Object.assign({}, thoughtPrior, { completed: true, content: rawEvent.content || thoughtPrior.content });
|
|
10283
|
+
rawEvent = null;
|
|
10284
|
+
break;
|
|
10285
|
+
}
|
|
10286
|
+
if (!rawEvent) continue;
|
|
10287
|
+
}
|
|
9450
10288
|
events.push(rawEvent);
|
|
9451
10289
|
}
|
|
9452
10290
|
flushPublicText();
|
|
@@ -9476,10 +10314,18 @@ function renderWorkRunEvents(run, includeGuides) {
|
|
|
9476
10314
|
var responseLabel = type === 'response' && terminalInterrupted
|
|
9477
10315
|
? (currentLang() === 'zh' ? '未完成回复片段\n' : 'Incomplete response fragment\n') + workEventLabel(event)
|
|
9478
10316
|
: workEventLabel(event);
|
|
9479
|
-
|
|
10317
|
+
// While a run is still receiving text, this view can be rebuilt once per
|
|
10318
|
+
// event. Avoid invoking the full Markdown parser for a large live
|
|
10319
|
+
// narrative; the final response path still gets the normal rich render.
|
|
10320
|
+
var liveNarrative = ['running', 'stopping', 'force_restarting'].indexOf(String(run && run.status || '').toLowerCase()) >= 0;
|
|
10321
|
+
var narrativeHtml = liveNarrative && String(responseLabel || '').length >= STREAMING_PLAIN_TEXT_THRESHOLD
|
|
10322
|
+
? esc(responseLabel)
|
|
10323
|
+
: renderMessageContent(responseLabel);
|
|
10324
|
+
return '<div class="conversation-work-event narrative"><div class="conversation-work-event-content">' + narrativeHtml + '</div></div>';
|
|
9480
10325
|
}
|
|
9481
10326
|
if (type.indexOf('guide') === 0 || event.guide) return renderWorkRunGuideMessage(event);
|
|
9482
10327
|
if (type === 'tool_group') return renderWorkToolGroup(event, eventIndex);
|
|
10328
|
+
if (type === 'thought') return renderWorkThought(event, eventIndex);
|
|
9483
10329
|
var activitySummary = type.indexOf('tool_') === 0 && type !== 'tool_call' && type !== 'tool_result';
|
|
9484
10330
|
var cls = type.indexOf('guide') === 0 ? ' guide' : (type === 'error' ? ' error' : (activitySummary ? ' activity-summary' : ''));
|
|
9485
10331
|
var label = activitySummary ? workToolActivityLabel(event.activity, Number(event.count || 1), !!event.completed) : workEventLabel(event) + (event.completed ? (currentLang() === 'zh' ? ' · 已完成' : ' · completed') : '');
|
|
@@ -10223,7 +11069,13 @@ function applyStreamingWorkflowText(ui, eventConversationId, mode, model) {
|
|
|
10223
11069
|
}
|
|
10224
11070
|
return;
|
|
10225
11071
|
}
|
|
10226
|
-
|
|
11072
|
+
var largeText = ui.activeWorkflowText.length >= STREAMING_PLAIN_TEXT_THRESHOLD;
|
|
11073
|
+
if (largeText) {
|
|
11074
|
+
var now = Date.now();
|
|
11075
|
+
if (ui._lastLargeStreamRenderAt && now - ui._lastLargeStreamRenderAt < STREAMING_LARGE_TEXT_INTERVAL_MS) return;
|
|
11076
|
+
ui._lastLargeStreamRenderAt = now;
|
|
11077
|
+
}
|
|
11078
|
+
updateMsg(ensureActiveAssistantMsg(mode, model, eventConversationId), ui.activeWorkflowText, 'assistant', mode, model, { streaming: true });
|
|
10227
11079
|
}
|
|
10228
11080
|
|
|
10229
11081
|
function scheduleStreamingWorkflowTextFlush(ui, eventConversationId, eventWorkspaceId) {
|
|
@@ -10254,6 +11106,7 @@ function renderAgentWorkEvent(event) {
|
|
|
10254
11106
|
ui.activeWorkflowText = '';
|
|
10255
11107
|
ui.lastCompletedWorkflow = null;
|
|
10256
11108
|
ui._streamFlushPending = false;
|
|
11109
|
+
ui._lastLargeStreamRenderAt = 0;
|
|
10257
11110
|
} else if (type === 'text') {
|
|
10258
11111
|
ui.activeWorkflowText = (ui.activeWorkflowText || '') + content;
|
|
10259
11112
|
if (workRun) return;
|
|
@@ -10264,6 +11117,7 @@ function renderAgentWorkEvent(event) {
|
|
|
10264
11117
|
ui.activeWorkflowText = '';
|
|
10265
11118
|
ui.activeWorkflowMsg = null;
|
|
10266
11119
|
ui._streamFlushPending = false;
|
|
11120
|
+
ui._lastLargeStreamRenderAt = 0;
|
|
10267
11121
|
} else if (type === 'final_response' && workRun) {
|
|
10268
11122
|
ui.activeWorkflowText = '';
|
|
10269
11123
|
ui.activeWorkflowMsg = null;
|
|
@@ -10297,6 +11151,7 @@ function renderAgentWorkEvent(event) {
|
|
|
10297
11151
|
}
|
|
10298
11152
|
ui.activeWorkflowMsg = null;
|
|
10299
11153
|
ui.activeWorkflowText = '';
|
|
11154
|
+
ui._lastLargeStreamRenderAt = 0;
|
|
10300
11155
|
finishToolBatch(eventConversationId);
|
|
10301
11156
|
} else if (type === 'error') {
|
|
10302
11157
|
flushStreamingWorkflowTextNow(ui, eventConversationId, event.mode || state.mode, event.model || state.model);
|
|
@@ -10366,7 +11221,14 @@ function appendAgentWorkEvent(event) {
|
|
|
10366
11221
|
var visibleRuntimeBranch = active && isViewingRuntimeConversationBranch(target);
|
|
10367
11222
|
if (active) markConversationTracked(id, state.conversationTrackMs || 300000, workspaceId);
|
|
10368
11223
|
if (active || isConversationTracked(id, workspaceId)) cacheAgentWorkEvent(event);
|
|
10369
|
-
|
|
11224
|
+
var pendingProvisionalStop = (event.type === 'start' || event.status === 'running')
|
|
11225
|
+
? pendingProvisionalStopRunId(target)
|
|
11226
|
+
: undefined;
|
|
11227
|
+
if (pendingProvisionalStop !== undefined && event.runId) {
|
|
11228
|
+
clearProvisionalStop(target);
|
|
11229
|
+
setConversationRuntimeState(target, 'stopping', event.runId, { provisional: false, generation: event.generation || 0, runtimeKey: event.runtimeKey || '' });
|
|
11230
|
+
requestBackendStopForProvisionalStart(target, event.runId);
|
|
11231
|
+
} else if (event.type === 'start') setConversationRuntimeState(target, event.status || 'running', event.runId || '', { provisional: false, generation: event.generation || 0, runtimeKey: event.runtimeKey || '' });
|
|
10370
11232
|
else if (event.status && ['running', 'stopping', 'force_restarting'].indexOf(String(event.status)) >= 0) setConversationRuntimeState(target, event.status, event.runId || '');
|
|
10371
11233
|
else if (event.status && ['completed', 'interrupted', 'force_interrupted', 'error'].indexOf(String(event.status)) >= 0) {
|
|
10372
11234
|
setConversationRuntimeState(target, event.status, event.runId || '');
|
|
@@ -10486,7 +11348,12 @@ function applyConversationSnapshot(s, requestedConversationId) {
|
|
|
10486
11348
|
if (s && s.runtimeKey) registerRuntimeKey(snapshotTarget, s.runtimeKey);
|
|
10487
11349
|
hydrateConversationBranchState(s);
|
|
10488
11350
|
rebindQueueToRuntimeBranch(snapshotTarget);
|
|
10489
|
-
if (s && Array.isArray(s.workRuns))
|
|
11351
|
+
if (s && Array.isArray(s.workRuns)) {
|
|
11352
|
+
var viewedBranchIdForSync = Array.isArray(s.viewedBranchNodePath) && s.viewedBranchNodePath.length
|
|
11353
|
+
? String(s.viewedBranchNodePath[s.viewedBranchNodePath.length - 1])
|
|
11354
|
+
: '';
|
|
11355
|
+
syncWorkRunsSnapshot(s.workRuns, snapshotTarget, viewedBranchIdForSync || undefined);
|
|
11356
|
+
}
|
|
10490
11357
|
applyAutoRouteRatingState(s);
|
|
10491
11358
|
if (s && s.chatMessages) {
|
|
10492
11359
|
renderChatMessages(s.chatMessages);
|
|
@@ -10549,9 +11416,9 @@ function addShellBlock(title, content) {
|
|
|
10549
11416
|
var div = document.createElement('div');
|
|
10550
11417
|
div.className = 'chat-msg assistant';
|
|
10551
11418
|
div.innerHTML = '<div class="shell-block collapsed">' +
|
|
10552
|
-
'<
|
|
11419
|
+
'<button type="button" class="shell-block-header" aria-expanded="false" onclick="this.parentElement.classList.toggle(\'collapsed\');this.setAttribute(\'aria-expanded\',this.parentElement.classList.contains(\'collapsed\')?\'false\':\'true\')">' +
|
|
10553
11420
|
'<span class="arrow">></span> ' + esc(title) +
|
|
10554
|
-
'</
|
|
11421
|
+
'</button><div class="shell-block-body">' + esc(content) + '</div></div>';
|
|
10555
11422
|
els['chat-area'].appendChild(div);
|
|
10556
11423
|
autoScrollIfAtBottom();
|
|
10557
11424
|
}
|
|
@@ -10560,10 +11427,10 @@ function addDiffBlock(title, adds, dels, linesHTML) {
|
|
|
10560
11427
|
var div = document.createElement('div');
|
|
10561
11428
|
div.className = 'chat-msg assistant';
|
|
10562
11429
|
div.innerHTML = '<div class="diff-block collapsed">' +
|
|
10563
|
-
'<
|
|
11430
|
+
'<button type="button" class="diff-block-header" aria-expanded="false" onclick="this.parentElement.classList.toggle(\'collapsed\');this.setAttribute(\'aria-expanded\',this.parentElement.classList.contains(\'collapsed\')?\'false\':\'true\')">' +
|
|
10564
11431
|
'<span class="arrow">></span> ' + esc(title) +
|
|
10565
11432
|
'<span class="diff-stat"><span class="diff-add">+' + adds + '</span><span class="diff-del">-' + dels + '</span></span>' +
|
|
10566
|
-
'</
|
|
11433
|
+
'</button><div class="diff-block-body">' + linesHTML + '</div></div>';
|
|
10567
11434
|
els['chat-area'].appendChild(div);
|
|
10568
11435
|
autoScrollIfAtBottom();
|
|
10569
11436
|
}
|
|
@@ -10977,18 +11844,33 @@ window.stopCurrentConversation = async function() {
|
|
|
10977
11844
|
if (!conversationId || !runtime) return false;
|
|
10978
11845
|
var target = runtime.target || currentConversationTarget(conversationId);
|
|
10979
11846
|
var runId = String(runtime.runId || '');
|
|
11847
|
+
var provisional = runtime.provisional === true;
|
|
10980
11848
|
if (String(runtime.status || '') === 'force_restarting') return false;
|
|
11849
|
+
if (provisional) markProvisionalStop(target, runId);
|
|
10981
11850
|
var force = String(runtime.status || '') === 'stopping';
|
|
10982
11851
|
if (typeof pauseQueueForTarget === 'function') pauseQueueForTarget(target);
|
|
10983
11852
|
setConversationRuntimeState(target, force ? 'force_restarting' : 'stopping', runId);
|
|
10984
11853
|
updateSubmitButtonState();
|
|
10985
11854
|
renderConversations();
|
|
11855
|
+
if (provisional) {
|
|
11856
|
+
// The backend may not have allocated a utility runtime yet. Keep the
|
|
11857
|
+
// exact local cancellation marker and let sendMessage consume it, or let
|
|
11858
|
+
// the first backend start event issue a stop with the real run id. An
|
|
11859
|
+
// empty-run stop request here races runtime allocation and can return
|
|
11860
|
+
// not_running before the prompt reaches the worker.
|
|
11861
|
+
if (window.renderInputStack) window.renderInputStack();
|
|
11862
|
+
return true;
|
|
11863
|
+
}
|
|
10986
11864
|
try {
|
|
10987
11865
|
var result;
|
|
10988
11866
|
// The target runtime supervisor owns the checkpoint + cooperative-stop
|
|
10989
11867
|
// transaction. A separate awaited checkpoint can itself be starved by a
|
|
10990
11868
|
// blocked worker and would prevent the supervisor from recording the first
|
|
10991
11869
|
// stop, making a second-click hard restart impossible.
|
|
11870
|
+
// A provisional renderer run has no backend run id yet. Omitting the
|
|
11871
|
+
// expected id lets a concurrently-created backend run be stopped, while
|
|
11872
|
+
// the pending marker above cancels a request that has not reached the
|
|
11873
|
+
// runtime at all.
|
|
10992
11874
|
if (api.stopConversation) result = await api.stopConversation({ target: target, runId: runId, force: force });
|
|
10993
11875
|
else if (api.abortConversation) result = await api.abortConversation(currentConversationTarget(conversationId));
|
|
10994
11876
|
var resultAction = String(result && result.action || '');
|
|
@@ -10999,6 +11881,9 @@ window.stopCurrentConversation = async function() {
|
|
|
10999
11881
|
await refreshConversationRuntimeAfterStopRace(target, runId, result);
|
|
11000
11882
|
return true;
|
|
11001
11883
|
}
|
|
11884
|
+
if (provisional && state.pendingProvisionalStops) {
|
|
11885
|
+
delete state.pendingProvisionalStops[runtimeKeyFor(target.workspaceId, target.conversationId)];
|
|
11886
|
+
}
|
|
11002
11887
|
var latestAfterStop = state.conversationRuntimeStates && state.conversationRuntimeStates[runtimeKeyFor(target.workspaceId, target.conversationId)];
|
|
11003
11888
|
if (!force && latestAfterStop && String(latestAfterStop.runId || '') === runId && String(latestAfterStop.status || '') !== 'stopping') {
|
|
11004
11889
|
// A second click or a terminal worker event won the race while the first
|
|
@@ -11027,7 +11912,7 @@ window.stopCurrentConversation = async function() {
|
|
|
11027
11912
|
return true;
|
|
11028
11913
|
};
|
|
11029
11914
|
|
|
11030
|
-
window.submitCurrentAction = function() {
|
|
11915
|
+
window.submitCurrentAction = function(source) {
|
|
11031
11916
|
if (currentFlowRunning() && flowTakeoverMatchesCurrent()) {
|
|
11032
11917
|
if (!promptHasText()) {
|
|
11033
11918
|
window.stopFlowRun();
|
|
@@ -11062,6 +11947,8 @@ window.submitCurrentAction = function() {
|
|
|
11062
11947
|
return;
|
|
11063
11948
|
}
|
|
11064
11949
|
if (isCurrentConversationRunning() && !promptHasText()) {
|
|
11950
|
+
// 回车:运行中空输入不操作(打断仅通过 Esc 或点击打断按钮)。
|
|
11951
|
+
if (source === 'enter') return;
|
|
11065
11952
|
window.stopCurrentConversation();
|
|
11066
11953
|
return;
|
|
11067
11954
|
}
|
|
@@ -11103,6 +11990,98 @@ window.renderContextWindow = function() {
|
|
|
11103
11990
|
ring.style.mask = 'radial-gradient(farthest-side, transparent 58%, #000 60%)';
|
|
11104
11991
|
var status = c.warning === 'over_limit' ? t('status.contextOverLimit') : (c.warning === 'near_limit' ? t('status.contextNearLimit') : t('status.contextTokens'));
|
|
11105
11992
|
ring.title = status + ': ' + used + ' / ' + max;
|
|
11993
|
+
if (window.renderContextInspector) window.renderContextInspector();
|
|
11994
|
+
};
|
|
11995
|
+
|
|
11996
|
+
function contextInspectorValue(value) {
|
|
11997
|
+
var number = Number(value);
|
|
11998
|
+
return Number.isFinite(number) ? Math.max(0, Math.round(number)) : 0;
|
|
11999
|
+
}
|
|
12000
|
+
|
|
12001
|
+
function contextInspectorCell(label, value) {
|
|
12002
|
+
return '<div class="context-inspector-cell"><span class="context-inspector-label">' + esc(label) + '</span><span class="context-inspector-value">' + esc(value) + '</span></div>';
|
|
12003
|
+
}
|
|
12004
|
+
|
|
12005
|
+
window.renderContextInspector = function() {
|
|
12006
|
+
var panel = document.getElementById('context-inspector');
|
|
12007
|
+
var ring = els['context-token-ring'] || document.getElementById('context-token-ring');
|
|
12008
|
+
if (!panel || !ring) return;
|
|
12009
|
+
ring.setAttribute('aria-expanded', state.contextInspectorOpen ? 'true' : 'false');
|
|
12010
|
+
panel.classList.toggle('open', state.contextInspectorOpen);
|
|
12011
|
+
if (!state.contextInspectorOpen) {
|
|
12012
|
+
panel.innerHTML = '';
|
|
12013
|
+
return;
|
|
12014
|
+
}
|
|
12015
|
+
var c = state.contextWindow || {};
|
|
12016
|
+
var max = Math.max(1, contextInspectorValue(c.maxTokens) || 1);
|
|
12017
|
+
var used = contextInspectorValue(c.estimatedTokens);
|
|
12018
|
+
var active = contextInspectorValue(c.buildBlockTokens);
|
|
12019
|
+
var history = contextInspectorValue(c.longHistoryTokens);
|
|
12020
|
+
var activeTrigger = contextInspectorValue(c.buildBlockTriggerTokens);
|
|
12021
|
+
var historyTrigger = contextInspectorValue(c.longHistoryTriggerTokens);
|
|
12022
|
+
var activeRetention = contextInspectorValue(c.buildBlockRetentionTokens);
|
|
12023
|
+
var historyRetention = contextInspectorValue(c.longHistoryRetentionTokens);
|
|
12024
|
+
var percent = Math.min(100, Math.round((used / max) * 100));
|
|
12025
|
+
var fillColor = c.warning === 'over_limit' ? 'var(--nm-state-danger)' : (c.warning === 'near_limit' ? 'var(--nm-state-warning)' : 'var(--accent)');
|
|
12026
|
+
var compression = state.contextCompression || null;
|
|
12027
|
+
var last = compression
|
|
12028
|
+
? ((compression.fallback ? t('status.contextModeFallback') : t('status.contextModeModel')) + ' · ' + String(compression.originalMessages || 0) + ' → ' + String(compression.compressedMessages || 0) + ' ' + t('status.messages'))
|
|
12029
|
+
: t('status.noCompressionShort');
|
|
12030
|
+
var busy = !!state.contextMutationPending;
|
|
12031
|
+
var running = typeof isCurrentConversationRunning === 'function' && isCurrentConversationRunning();
|
|
12032
|
+
panel.innerHTML = '<div class="context-inspector-head"><div><div class="context-inspector-title">' + esc(t('status.contextInspector')) + '</div><div class="context-inspector-subtitle">' + esc(t('status.contextInspectorHint')) + '</div></div>' +
|
|
12033
|
+
'<button type="button" class="context-inspector-close" onclick="window.closeContextInspector()" aria-label="' + esc(t('common.close') || 'Close') + '">×</button></div>' +
|
|
12034
|
+
'<div class="context-inspector-meter"><div class="context-inspector-meter-fill" style="width:' + percent + '%;background:' + fillColor + '"></div></div>' +
|
|
12035
|
+
'<div class="context-inspector-grid">' +
|
|
12036
|
+
contextInspectorCell(t('status.contextTokens'), used + ' / ' + max) +
|
|
12037
|
+
contextInspectorCell(t('status.activeBuild'), active + ' / ' + activeTrigger) +
|
|
12038
|
+
contextInspectorCell(t('status.longHistory'), history + ' / ' + historyTrigger) +
|
|
12039
|
+
contextInspectorCell(t('status.retention'), activeRetention + ' + ' + historyRetention) +
|
|
12040
|
+
contextInspectorCell(t('status.hotCache'), contextInspectorValue(c.cacheEntries) + ' entries') +
|
|
12041
|
+
contextInspectorCell(t('status.coldArchive'), contextInspectorValue(c.archiveEntries) + ' entries') +
|
|
12042
|
+
'</div>' +
|
|
12043
|
+
'<div class="context-inspector-section"><div class="context-inspector-section-title">' + esc(t('status.lastCompression')) + '</div><div class="context-inspector-meta">' + esc(last) + '</div>' +
|
|
12044
|
+
(compression && compression.model ? '<div class="context-inspector-meta">' + esc(compression.model) + '</div>' : '') + '</div>' +
|
|
12045
|
+
'<div class="context-inspector-actions"><button type="button" class="sec-btn primary" onclick="window.compressContextNow()"' + (busy || running ? ' disabled' : '') + '>' + esc(busy ? t('status.compressing') : t('status.compressNow')) + '</button></div>';
|
|
12046
|
+
};
|
|
12047
|
+
|
|
12048
|
+
window.closeContextInspector = function() {
|
|
12049
|
+
state.contextInspectorOpen = false;
|
|
12050
|
+
window.renderContextInspector();
|
|
12051
|
+
};
|
|
12052
|
+
|
|
12053
|
+
window.toggleContextInspector = function() {
|
|
12054
|
+
state.contextInspectorOpen = !state.contextInspectorOpen;
|
|
12055
|
+
window.hideContextWindowTooltip();
|
|
12056
|
+
window.renderContextInspector();
|
|
12057
|
+
};
|
|
12058
|
+
|
|
12059
|
+
window.compressContextNow = function() {
|
|
12060
|
+
if (state.contextMutationPending) return;
|
|
12061
|
+
if (typeof isCurrentConversationRunning === 'function' && isCurrentConversationRunning()) {
|
|
12062
|
+
showUiNotice(t('status.compressionBusy'), 'error', 'context-compress-busy');
|
|
12063
|
+
return;
|
|
12064
|
+
}
|
|
12065
|
+
if (!api.compressContext) {
|
|
12066
|
+
showUiNotice(t('status.compressionFailed'), 'error', 'context-compress-unavailable');
|
|
12067
|
+
return;
|
|
12068
|
+
}
|
|
12069
|
+
state.contextMutationPending = true;
|
|
12070
|
+
window.renderContextInspector();
|
|
12071
|
+
Promise.resolve(api.compressContext({ target: currentConversationTarget(), force: true })).then(function(result) {
|
|
12072
|
+
if (!result || result.ok === false) throw new Error((result && result.error) || t('status.compressionFailed'));
|
|
12073
|
+
if (result.contextWindow) state.contextWindow = result.contextWindow;
|
|
12074
|
+
if (result.contextCompression !== undefined) state.contextCompression = result.contextCompression;
|
|
12075
|
+
window.renderContextWindow();
|
|
12076
|
+
window.renderRightStatusPanel();
|
|
12077
|
+
showUiNotice(t('status.compressedNow'), 'success', 'context-compress-success');
|
|
12078
|
+
return result;
|
|
12079
|
+
}).catch(function(error) {
|
|
12080
|
+
showUiNotice(error && error.message ? error.message : t('status.compressionFailed'), 'error', 'context-compress-error');
|
|
12081
|
+
}).finally(function() {
|
|
12082
|
+
state.contextMutationPending = false;
|
|
12083
|
+
window.renderContextInspector();
|
|
12084
|
+
});
|
|
11106
12085
|
};
|
|
11107
12086
|
|
|
11108
12087
|
window.contextWindowTooltipHtml = function() {
|
|
@@ -11723,6 +12702,7 @@ window.renderQueuePanel = function() {
|
|
|
11723
12702
|
}
|
|
11724
12703
|
var toggle = panel.querySelector('#queue-expand-btn');
|
|
11725
12704
|
if (toggle) {
|
|
12705
|
+
toggle.setAttribute('aria-expanded', state.queueCollapsed ? 'false' : 'true');
|
|
11726
12706
|
toggle.title = state.queueCollapsed ? t('queue.expand') : t('queue.collapse');
|
|
11727
12707
|
toggle.innerHTML = iconSvg(state.queueCollapsed ? 'chevron-up' : 'chevron-down', toggle.title, 'tiny');
|
|
11728
12708
|
}
|
|
@@ -12012,7 +12992,14 @@ window.sendMessage = async function(modeOverride, queuedText, opts) {
|
|
|
12012
12992
|
var displayText = optimisticAttachments.length
|
|
12013
12993
|
? rawText + (rawText ? '\n\n' : '') + '[' + optimisticAttachments.length + ' image attachment' + (optimisticAttachments.length === 1 ? '' : 's') + ']'
|
|
12014
12994
|
: text;
|
|
12015
|
-
if (!text && !optimisticAttachments.length)
|
|
12995
|
+
if (!text && !optimisticAttachments.length) {
|
|
12996
|
+
// 空输入时发送默认句段「继续 / Continue」,按界面语言切换。
|
|
12997
|
+
var continuePhrase = t('input.continue');
|
|
12998
|
+
rawText = continuePhrase;
|
|
12999
|
+
text = continuePhrase;
|
|
13000
|
+
requestMessage = continuePhrase;
|
|
13001
|
+
displayText = continuePhrase;
|
|
13002
|
+
}
|
|
12016
13003
|
|
|
12017
13004
|
var lockedConversationId = activeConversationId();
|
|
12018
13005
|
var lockedTarget = currentConversationTarget(lockedConversationId);
|
|
@@ -12233,6 +13220,15 @@ window.sendMessage = async function(modeOverride, queuedText, opts) {
|
|
|
12233
13220
|
var executionMode = opts.goalDeclaration || requestedMode === 'goal' ? 'build'
|
|
12234
13221
|
: ((opts.forceBuild || idleBuildNextImmediate) && requestedMode === 'build' ? 'build' : requestedMode);
|
|
12235
13222
|
await syncConversationExecutionState(executionMode, effectiveInputMode);
|
|
13223
|
+
if (consumeProvisionalStop(lockedTarget, localRunId)) {
|
|
13224
|
+
// Stop/Escape won before the backend accepted the prompt. Do not send the
|
|
13225
|
+
// provider request after the user has already cancelled it.
|
|
13226
|
+
delete state.activeSendCallsByTarget[lockedRuntimeKey];
|
|
13227
|
+
setConversationRuntimeState(lockedTarget, 'interrupted', localRunId, { provisional: false });
|
|
13228
|
+
setWorking(!!runningConversationRecord(activeConversationId()));
|
|
13229
|
+
window.renderInputStack();
|
|
13230
|
+
return { status: 'interrupted', runId: localRunId, target: lockedTarget, cancelledBeforeStart: true };
|
|
13231
|
+
}
|
|
12236
13232
|
var renderOnViewedBranch = !queuedRuntimeBranch || queueBranchPathForTarget(lockedTarget, 'viewed') === queueBranchPathForTarget(lockedTarget, 'runtime');
|
|
12237
13233
|
if (isActiveConversationTarget(lockedTarget) && renderOnViewedBranch) {
|
|
12238
13234
|
if (opts.resumeGuideRunId && requestMessage.clientMessageId) {
|
|
@@ -12262,10 +13258,12 @@ window.sendMessage = async function(modeOverride, queuedText, opts) {
|
|
|
12262
13258
|
renderAutoRouteRatingControls();
|
|
12263
13259
|
}
|
|
12264
13260
|
var responseMsg = null;
|
|
13261
|
+
var sendFailure = '';
|
|
12265
13262
|
try {
|
|
12266
13263
|
var sendPromise = api.sendMessage(requestMessage, lockedTarget);
|
|
12267
13264
|
if (requestedMode === 'goal') activateSubmittedGoal(opts.goalObjective || rawText);
|
|
12268
13265
|
var r = await sendPromise;
|
|
13266
|
+
if (r && r.error) sendFailure = String(r.error);
|
|
12269
13267
|
if (isActiveConversationTarget(lockedTarget)) applyReturnedGoalState(r);
|
|
12270
13268
|
if (r && r.runId) {
|
|
12271
13269
|
var anchorStore = workRunAnchorIndexStore(lockedTarget);
|
|
@@ -12346,9 +13344,10 @@ window.sendMessage = async function(modeOverride, queuedText, opts) {
|
|
|
12346
13344
|
}
|
|
12347
13345
|
}
|
|
12348
13346
|
} catch(e) {
|
|
13347
|
+
sendFailure = e && e.message ? String(e.message) : String(e || 'Agent run failed.');
|
|
12349
13348
|
if (isActiveConversationTarget(lockedTarget)) {
|
|
12350
13349
|
responseMsg = conversationWorkUiState(lockedConversationId, lockedTarget.workspaceId).activeWorkflowMsg || addMsg('assistant', '', state.mode, state.model);
|
|
12351
|
-
updateMsg(responseMsg, formatChatError(
|
|
13350
|
+
updateMsg(responseMsg, formatChatError(sendFailure, 'Agent run failed.'), 'error', state.mode, state.model);
|
|
12352
13351
|
}
|
|
12353
13352
|
}
|
|
12354
13353
|
if (api.getState) {
|
|
@@ -12399,7 +13398,15 @@ window.sendMessage = async function(modeOverride, queuedText, opts) {
|
|
|
12399
13398
|
if (resumedModeResult != null) state._syncedMode = state.mode;
|
|
12400
13399
|
}
|
|
12401
13400
|
var finalRuntime = state.conversationRuntimeStates && state.conversationRuntimeStates[lockedRuntimeKey];
|
|
12402
|
-
|
|
13401
|
+
var finalRunMatches = !finalRuntime || !finalRuntime.runId || finalRuntime.runId === localRunId || (r && finalRuntime.runId === r.runId);
|
|
13402
|
+
if (sendFailure) {
|
|
13403
|
+
// The IPC contract returns terminal failures as { error } while the
|
|
13404
|
+
// target-scoped error work event may arrive on the next task. Never let
|
|
13405
|
+
// the renderer's provisional run fall through to completed in that gap.
|
|
13406
|
+
if (finalRunMatches) {
|
|
13407
|
+
setConversationRuntimeState(lockedTarget, 'error', (r && r.runId) || (finalRuntime && finalRuntime.runId) || localRunId, { provisional: false });
|
|
13408
|
+
}
|
|
13409
|
+
} else if (finalRunMatches) {
|
|
12403
13410
|
setConversationRuntimeState(lockedTarget, 'completed', (r && r.runId) || localRunId);
|
|
12404
13411
|
}
|
|
12405
13412
|
setWorking(!!runningConversationRecord(activeConversationId()));
|
|
@@ -12740,19 +13747,25 @@ window.toggleBottom = function() {
|
|
|
12740
13747
|
};
|
|
12741
13748
|
|
|
12742
13749
|
// === Right Sidebar Tabs ===
|
|
13750
|
+
function rightTabButtonHtml(tab, icon, label, active) {
|
|
13751
|
+
return '<button class="tab-btn' + (active ? ' active' : '') + '" id="right-tab-' + tab + '" role="tab" aria-selected="' + (active ? 'true' : 'false') + '" aria-controls="panel-' + tab + '" tabindex="' + (active ? '0' : '-1') + '" data-tab="' + tab + '" onclick="window.switchRightTab("' + tab + '")" onkeydown="window.handleRightTabKey(event)" title="' + escAttr(label) + '">' + iconOnly(icon, label) + '</button>';
|
|
13752
|
+
}
|
|
13753
|
+
|
|
12743
13754
|
window.upgradeRightSidebar = function() {
|
|
12744
13755
|
var rightTabs = els['right-tabs'] || document.getElementById('right-tabs');
|
|
12745
13756
|
var rightContent = els['right-content'] || document.getElementById('right-content');
|
|
12746
13757
|
if (!rightTabs || !rightContent || rightTabs.getAttribute('data-upgraded') === 'true') return;
|
|
12747
13758
|
rightTabs.setAttribute('data-upgraded', 'true');
|
|
13759
|
+
rightTabs.setAttribute('role', 'tablist');
|
|
13760
|
+
rightTabs.setAttribute('aria-label', t('right.files'));
|
|
12748
13761
|
rightTabs.innerHTML =
|
|
12749
|
-
'
|
|
12750
|
-
|
|
12751
|
-
|
|
12752
|
-
'
|
|
12753
|
-
|
|
12754
|
-
|
|
12755
|
-
|
|
13762
|
+
rightTabButtonHtml('file-tree', 'folder', t('right.files'), state.rightTab === 'file-tree') +
|
|
13763
|
+
rightTabButtonHtml('editor', 'square-pen', t('right.editor'), state.rightTab === 'editor') +
|
|
13764
|
+
rightTabButtonHtml('plan', 'list-checks', t('right.plan'), state.rightTab === 'plan') +
|
|
13765
|
+
rightTabButtonHtml('subagent', 'bot', t('right.subagents'), state.rightTab === 'subagent') +
|
|
13766
|
+
rightTabButtonHtml('browser', 'globe', t('right.browser'), state.rightTab === 'browser') +
|
|
13767
|
+
rightTabButtonHtml('status', 'activity', t('right.status'), state.rightTab === 'status') +
|
|
13768
|
+
rightTabButtonHtml('archives', 'archive', t('right.archives'), state.rightTab === 'archives') +
|
|
12756
13769
|
'<div class="tab-divider"></div>' +
|
|
12757
13770
|
'<button class="tab-btn" onclick="window.toggleRight()" title="' + escAttr(t('right.close')) + '">' + iconOnly('x', t('right.close')) + '</button>';
|
|
12758
13771
|
|
|
@@ -12760,7 +13773,7 @@ window.upgradeRightSidebar = function() {
|
|
|
12760
13773
|
if (filePanel && !filePanel.getAttribute('data-upgraded')) {
|
|
12761
13774
|
filePanel.setAttribute('data-upgraded', 'true');
|
|
12762
13775
|
var tree = document.getElementById('file-tree-container');
|
|
12763
|
-
filePanel.innerHTML = '<div class="right-section-head"><span class="right-section-title">' + esc(t('right.fileTree')) + '</span><button class="archive-action-btn" onclick="window.loadFileTree()">' + esc(t('right.refresh')) + '</button></div><div id="file-tree-container"></div>';
|
|
13776
|
+
filePanel.innerHTML = '<div class="right-section-head"><span class="right-section-title">' + esc(t('right.fileTree')) + '</span><button class="archive-action-btn" onclick="window.loadFileTree()">' + esc(t('right.refresh')) + '</button></div><div id="file-tree-container" role="tree"></div>';
|
|
12764
13777
|
if (tree) document.getElementById('file-tree-container').innerHTML = tree.innerHTML;
|
|
12765
13778
|
}
|
|
12766
13779
|
var subPanel = document.getElementById('panel-subagent');
|
|
@@ -12791,6 +13804,14 @@ window.upgradeRightSidebar = function() {
|
|
|
12791
13804
|
archivesPanel.innerHTML = '<div class="right-section-head"><span class="right-section-title">' + esc(t('right.archives')) + '</span><button class="archive-action-btn" onclick="window.refreshRightArchives()">' + esc(t('right.refresh')) + '</button></div><div style="display:flex;gap:6px;margin-bottom:8px;"><button class="sec-btn primary" style="flex:1;" onclick="window.archiveCurrent()">' + esc(t('archive.current')) + '</button></div><div id="right-archive-list"></div>';
|
|
12792
13805
|
rightContent.appendChild(archivesPanel);
|
|
12793
13806
|
}
|
|
13807
|
+
var upgradedPanels = rightContent.querySelectorAll('.tab-panel');
|
|
13808
|
+
for (var upgradedIndex = 0; upgradedIndex < upgradedPanels.length; upgradedIndex++) {
|
|
13809
|
+
var upgradedPanel = upgradedPanels[upgradedIndex];
|
|
13810
|
+
var upgradedTab = upgradedPanel.id.replace(/^panel-/, '');
|
|
13811
|
+
upgradedPanel.setAttribute('role', 'tabpanel');
|
|
13812
|
+
upgradedPanel.setAttribute('aria-labelledby', 'right-tab-' + upgradedTab);
|
|
13813
|
+
upgradedPanel.hidden = upgradedTab !== state.rightTab;
|
|
13814
|
+
}
|
|
12794
13815
|
};
|
|
12795
13816
|
|
|
12796
13817
|
window.switchRightTab = function(tab) {
|
|
@@ -12804,11 +13825,16 @@ window.switchRightTab = function(tab) {
|
|
|
12804
13825
|
if (!rightTabs || !rightContent) return;
|
|
12805
13826
|
var btns = rightTabs.querySelectorAll('.tab-btn[data-tab]');
|
|
12806
13827
|
for (var i = 0; i < btns.length; i++) {
|
|
12807
|
-
|
|
13828
|
+
var selected = btns[i].getAttribute('data-tab') === tab;
|
|
13829
|
+
btns[i].classList.toggle('active', selected);
|
|
13830
|
+
btns[i].setAttribute('aria-selected', selected ? 'true' : 'false');
|
|
13831
|
+
btns[i].tabIndex = selected ? 0 : -1;
|
|
12808
13832
|
}
|
|
12809
13833
|
var panels = rightContent.querySelectorAll('.tab-panel');
|
|
12810
13834
|
for (var j = 0; j < panels.length; j++) {
|
|
12811
|
-
|
|
13835
|
+
var panelActive = panels[j].id === 'panel-' + tab;
|
|
13836
|
+
panels[j].classList.toggle('active', panelActive);
|
|
13837
|
+
panels[j].hidden = !panelActive;
|
|
12812
13838
|
}
|
|
12813
13839
|
// Load content on first access
|
|
12814
13840
|
if (tab === 'file-tree') window.loadFileTree();
|
|
@@ -12900,7 +13926,7 @@ window.renderConversationPlan = function() {
|
|
|
12900
13926
|
var plan = normalizeConversationPlan(state.conversationPlan);
|
|
12901
13927
|
var items = plan.items || [];
|
|
12902
13928
|
var html = '<div class="plan-compose">' +
|
|
12903
|
-
'<input id="conversation-plan-input" class="plan-input" placeholder="' + escAttr(t('plan.placeholder')) + '" onkeydown="if(event.key==="Enter")window.addConversationPlanItem()">' +
|
|
13929
|
+
'<input id="conversation-plan-input" class="plan-input" placeholder="' + escAttr(t('plan.placeholder')) + '" onkeydown="if(event.key==="Enter"&&!event.isComposing&&event.key!=="Process"&&event.keyCode!==229)window.addConversationPlanItem()">' +
|
|
12904
13930
|
'<button class="sec-btn primary" onclick="window.addConversationPlanItem()">' + esc(t('plan.add')) + '</button>' +
|
|
12905
13931
|
'</div>';
|
|
12906
13932
|
if (!items.length) {
|
|
@@ -12968,7 +13994,7 @@ window.editConversationPlanItem = function(idx) {
|
|
|
12968
13994
|
var rows = target.querySelectorAll('.plan-row');
|
|
12969
13995
|
var row = rows[idx];
|
|
12970
13996
|
if (!row) return;
|
|
12971
|
-
row.querySelector('.right-row-body').innerHTML = '<input class="plan-edit-input" id="conversation-plan-edit-' + idx + '" value="' + escAttr(item.text) + '" onkeydown="if(event.key==="Enter")window.saveConversationPlanEdit(' + idx + ')">';
|
|
13997
|
+
row.querySelector('.right-row-body').innerHTML = '<input class="plan-edit-input" id="conversation-plan-edit-' + idx + '" value="' + escAttr(item.text) + '" onkeydown="if(event.key==="Enter"&&!event.isComposing&&event.key!=="Process"&&event.keyCode!==229)window.saveConversationPlanEdit(' + idx + ')">';
|
|
12972
13998
|
var actions = row.querySelector('.plan-actions');
|
|
12973
13999
|
if (actions) {
|
|
12974
14000
|
actions.innerHTML = '<button class="archive-action-btn" onclick="window.saveConversationPlanEdit(' + idx + ')">' + esc(t('common.save')) + '</button>' +
|
|
@@ -13119,6 +14145,8 @@ window.renderRightStatusPanel = function() {
|
|
|
13119
14145
|
if (contextWindow) {
|
|
13120
14146
|
html += '<div class="right-row"><div class="right-row-body"><span class="right-row-title">' + esc(t('status.contextTokens')) + '</span><span class="right-row-meta">' +
|
|
13121
14147
|
esc(String(contextWindow.estimatedTokens || 0) + ' / ' + String(contextWindow.maxTokens || 0) + ' | ' + String(contextWindow.warning || 'ok')) +
|
|
14148
|
+
(contextWindow.buildBlockTokens !== undefined ? '<br>' + esc(t('status.activeBuild')) + ': ' + esc(String(contextWindow.buildBlockTokens || 0) + ' / ' + String(contextWindow.buildBlockTriggerTokens || 0)) +
|
|
14149
|
+
' · ' + esc(t('status.longHistory')) + ': ' + esc(String(contextWindow.longHistoryTokens || 0) + ' / ' + String(contextWindow.longHistoryTriggerTokens || 0)) : '') +
|
|
13122
14150
|
'</span></div></div>';
|
|
13123
14151
|
}
|
|
13124
14152
|
if (compression) {
|
|
@@ -13302,7 +14330,7 @@ window.terminalSend = function() {
|
|
|
13302
14330
|
var startedPane = document.querySelector('.terminal-pane[data-session="' + resp.sessionId + '"]');
|
|
13303
14331
|
var startedInput = startedPane && startedPane.querySelector('.terminal-input');
|
|
13304
14332
|
if (startedInput && startedInput.value === cmd) startedInput.value = '';
|
|
13305
|
-
return api.terminalWrite(resp.sessionId, cmd + '\r
|
|
14333
|
+
return api.terminalWrite(resp.sessionId, cmd + '\r');
|
|
13306
14334
|
}).catch(function(err) {
|
|
13307
14335
|
input.disabled = false;
|
|
13308
14336
|
var currentPane = window.getActiveTerminalPane();
|
|
@@ -13311,7 +14339,7 @@ window.terminalSend = function() {
|
|
|
13311
14339
|
});
|
|
13312
14340
|
}
|
|
13313
14341
|
input.value = '';
|
|
13314
|
-
api.terminalWrite(sessionId, cmd + '\r
|
|
14342
|
+
api.terminalWrite(sessionId, cmd + '\r').catch(function(err) {
|
|
13315
14343
|
if (output) output.innerHTML += '\r\n<span style="color:#ff6666;">[' + esc(t('common.error')) + '] ' + esc(err.message) + '</span>';
|
|
13316
14344
|
});
|
|
13317
14345
|
};
|
|
@@ -13342,6 +14370,35 @@ window.spawnTerminal = function(shellId, options) {
|
|
|
13342
14370
|
return window.addTerminalTab(shellId, options);
|
|
13343
14371
|
};
|
|
13344
14372
|
|
|
14373
|
+
window.handleTerminalTabKey = function(event) {
|
|
14374
|
+
if (!event || event.defaultPrevented || event.isComposing || event.key === 'Process' || event.keyCode === 229 || event.target !== event.currentTarget) return false;
|
|
14375
|
+
var tabs = Array.prototype.slice.call(document.querySelectorAll('#terminal-tabs .terminal-tab'));
|
|
14376
|
+
var index = tabs.indexOf(event.currentTarget);
|
|
14377
|
+
if (index < 0 || !tabs.length) return false;
|
|
14378
|
+
var next = index;
|
|
14379
|
+
if (event.key === 'ArrowRight') next = (index + 1) % tabs.length;
|
|
14380
|
+
else if (event.key === 'ArrowLeft') next = (index - 1 + tabs.length) % tabs.length;
|
|
14381
|
+
else if (event.key === 'Home') next = 0;
|
|
14382
|
+
else if (event.key === 'End') next = tabs.length - 1;
|
|
14383
|
+
else if (event.key === 'Enter' || event.key === ' ') next = index;
|
|
14384
|
+
else if (event.key === 'Delete') {
|
|
14385
|
+
event.preventDefault();
|
|
14386
|
+
var closingId = parseInt(tabs[index].getAttribute('data-tab-id'), 10);
|
|
14387
|
+
window.closeTerminalTab(closingId);
|
|
14388
|
+
requestAnimationFrame(function() {
|
|
14389
|
+
var activeTab = document.querySelector('#terminal-tabs .terminal-tab.active') || document.querySelector('#terminal-tabs .terminal-tab');
|
|
14390
|
+
if (activeTab) activeTab.focus({ preventScroll:true });
|
|
14391
|
+
});
|
|
14392
|
+
return true;
|
|
14393
|
+
}
|
|
14394
|
+
else return false;
|
|
14395
|
+
event.preventDefault();
|
|
14396
|
+
var tabId = parseInt(tabs[next].getAttribute('data-tab-id'), 10);
|
|
14397
|
+
window.switchTerminalTab(tabId);
|
|
14398
|
+
tabs[next].focus({ preventScroll:true });
|
|
14399
|
+
return true;
|
|
14400
|
+
};
|
|
14401
|
+
|
|
13345
14402
|
window.addTerminalTab = function(shellId, options) {
|
|
13346
14403
|
options = options || {};
|
|
13347
14404
|
shellId = normalizeTerminalShell(shellId || state._terminalShell);
|
|
@@ -13359,13 +14416,23 @@ window.addTerminalTab = function(shellId, options) {
|
|
|
13359
14416
|
// Create tab button
|
|
13360
14417
|
var tab = document.createElement('div');
|
|
13361
14418
|
tab.className = 'terminal-tab active';
|
|
14419
|
+
tab.id = 'terminal-tab-' + tabId;
|
|
14420
|
+
tab.setAttribute('role', 'tab');
|
|
14421
|
+
tab.setAttribute('aria-selected', 'true');
|
|
14422
|
+
tab.setAttribute('aria-controls', 'terminal-pane-' + tabId);
|
|
14423
|
+
tab.tabIndex = 0;
|
|
13362
14424
|
tab.setAttribute('data-tab-id', tabId);
|
|
13363
|
-
tab.innerHTML = name + '<button class="close-tab" onclick="event.stopPropagation();window.closeTerminalTab(' + tabId + ')" title="' + escAttr(t('common.closeTab')) + '">' + iconSvg('x', t('common.closeTab'), 'tiny') + '</button>';
|
|
14425
|
+
tab.innerHTML = name + '<button type="button" class="close-tab" onclick="event.stopPropagation();window.closeTerminalTab(' + tabId + ')" title="' + escAttr(t('common.closeTab')) + '">' + iconSvg('x', t('common.closeTab'), 'tiny') + '</button>';
|
|
13364
14426
|
tab.onclick = function() { window.switchTerminalTab(tabId); };
|
|
14427
|
+
tab.addEventListener('keydown', window.handleTerminalTabKey);
|
|
13365
14428
|
|
|
13366
14429
|
// Deactivate all other tabs
|
|
13367
14430
|
var allTabs = tabsContainer.querySelectorAll('.terminal-tab');
|
|
13368
|
-
for (var i = 0; i < allTabs.length; i++)
|
|
14431
|
+
for (var i = 0; i < allTabs.length; i++) {
|
|
14432
|
+
allTabs[i].classList.remove('active');
|
|
14433
|
+
allTabs[i].setAttribute('aria-selected', 'false');
|
|
14434
|
+
allTabs[i].tabIndex = -1;
|
|
14435
|
+
}
|
|
13369
14436
|
|
|
13370
14437
|
tabsContainer.appendChild(tab);
|
|
13371
14438
|
|
|
@@ -13373,18 +14440,20 @@ window.addTerminalTab = function(shellId, options) {
|
|
|
13373
14440
|
var pane = document.createElement('div');
|
|
13374
14441
|
pane.className = 'terminal-pane active';
|
|
13375
14442
|
pane.id = 'terminal-pane-' + tabId;
|
|
14443
|
+
pane.setAttribute('role', 'tabpanel');
|
|
14444
|
+
pane.setAttribute('aria-labelledby', tab.id);
|
|
13376
14445
|
pane.setAttribute('data-tab-id', tabId);
|
|
13377
14446
|
pane.setAttribute('data-session', '');
|
|
13378
14447
|
pane.innerHTML =
|
|
13379
14448
|
'<div class="terminal-output"><span style="color:var(--accent2);">Connecting ' + shellId + '...</span>\r\n</div>' +
|
|
13380
14449
|
'<div class="terminal-input-row">' +
|
|
13381
14450
|
'<span class="terminal-prompt">' + shellLabel + '></span>' +
|
|
13382
|
-
'<input class="terminal-input" type="text" placeholder="Enter command..." onkeydown="if(event.key===\'Enter\')window.terminalSend()">' +
|
|
14451
|
+
'<input class="terminal-input" type="text" placeholder="Enter command..." onkeydown="if(event.key===\'Enter\'&&!event.isComposing&&event.key!==\'Process\'&&event.keyCode!==229)window.terminalSend()">' +
|
|
13383
14452
|
'</div>';
|
|
13384
14453
|
|
|
13385
14454
|
// Deactivate all other panes
|
|
13386
14455
|
var allPanes = body.querySelectorAll('.terminal-pane');
|
|
13387
|
-
for (var j = 0; j < allPanes.length; j++) allPanes[j].classList.remove('active');
|
|
14456
|
+
for (var j = 0; j < allPanes.length; j++) { allPanes[j].classList.remove('active'); allPanes[j].hidden = true; }
|
|
13388
14457
|
|
|
13389
14458
|
body.appendChild(pane);
|
|
13390
14459
|
|
|
@@ -13435,21 +14504,33 @@ window.ensureTerminalTakeoverPane = function(session) {
|
|
|
13435
14504
|
|
|
13436
14505
|
var tab = document.createElement('div');
|
|
13437
14506
|
tab.className = 'terminal-tab agent-takeover marquee-border';
|
|
14507
|
+
tab.id = 'terminal-tab-' + tabId;
|
|
14508
|
+
tab.setAttribute('role', 'tab');
|
|
14509
|
+
tab.setAttribute('aria-selected', 'true');
|
|
14510
|
+
tab.setAttribute('aria-controls', 'terminal-pane-' + tabId);
|
|
14511
|
+
tab.tabIndex = 0;
|
|
13438
14512
|
tab.setAttribute('data-tab-id', tabId);
|
|
13439
14513
|
tab.setAttribute('data-takeover-session', key);
|
|
13440
14514
|
tab.setAttribute('data-takeover-workspace-id', session.workspaceId || '');
|
|
13441
14515
|
tab.setAttribute('data-takeover-conversation', session.conversationId || 'default');
|
|
13442
|
-
tab.innerHTML = 'Agent:' + esc(session.name || key) + '<button class="close-tab" onclick="event.stopPropagation();window.closeTerminalTab(' + tabId + ')" title="' + escAttr(t('common.closeTab')) + '">' + iconSvg('x', t('common.closeTab'), 'tiny') + '</button>';
|
|
14516
|
+
tab.innerHTML = 'Agent:' + esc(session.name || key) + '<button type="button" class="close-tab" onclick="event.stopPropagation();window.closeTerminalTab(' + tabId + ')" title="' + escAttr(t('common.closeTab')) + '">' + iconSvg('x', t('common.closeTab'), 'tiny') + '</button>';
|
|
13443
14517
|
tab.onclick = function() { window.switchTerminalTab(tabId); };
|
|
14518
|
+
tab.addEventListener('keydown', window.handleTerminalTabKey);
|
|
13444
14519
|
|
|
13445
14520
|
var allTabs = tabsContainer.querySelectorAll('.terminal-tab');
|
|
13446
|
-
for (var i = 0; i < allTabs.length; i++)
|
|
14521
|
+
for (var i = 0; i < allTabs.length; i++) {
|
|
14522
|
+
allTabs[i].classList.remove('active');
|
|
14523
|
+
allTabs[i].setAttribute('aria-selected', 'false');
|
|
14524
|
+
allTabs[i].tabIndex = -1;
|
|
14525
|
+
}
|
|
13447
14526
|
tab.classList.add('active');
|
|
13448
14527
|
tabsContainer.appendChild(tab);
|
|
13449
14528
|
|
|
13450
14529
|
var pane = document.createElement('div');
|
|
13451
14530
|
pane.className = 'terminal-pane active agent-takeover marquee-border';
|
|
13452
14531
|
pane.id = 'terminal-pane-' + tabId;
|
|
14532
|
+
pane.setAttribute('role', 'tabpanel');
|
|
14533
|
+
pane.setAttribute('aria-labelledby', tab.id);
|
|
13453
14534
|
pane.setAttribute('data-tab-id', tabId);
|
|
13454
14535
|
pane.setAttribute('data-session', '');
|
|
13455
14536
|
pane.setAttribute('data-takeover-session', key);
|
|
@@ -13461,11 +14542,11 @@ window.ensureTerminalTakeoverPane = function(session) {
|
|
|
13461
14542
|
'<div class="terminal-output"></div>' +
|
|
13462
14543
|
'<div class="terminal-input-row">' +
|
|
13463
14544
|
'<span class="terminal-prompt">Agent></span>' +
|
|
13464
|
-
'<input class="terminal-input" type="text" placeholder="Enter command..." onkeydown="if(event.key===\'Enter\')window.terminalSend()">' +
|
|
14545
|
+
'<input class="terminal-input" type="text" placeholder="Enter command..." onkeydown="if(event.key===\'Enter\'&&!event.isComposing&&event.key!==\'Process\'&&event.keyCode!==229)window.terminalSend()">' +
|
|
13465
14546
|
'</div>';
|
|
13466
14547
|
|
|
13467
14548
|
var allPanes = body.querySelectorAll('.terminal-pane');
|
|
13468
|
-
for (var j = 0; j < allPanes.length; j++) allPanes[j].classList.remove('active');
|
|
14549
|
+
for (var j = 0; j < allPanes.length; j++) { allPanes[j].classList.remove('active'); allPanes[j].hidden = true; }
|
|
13469
14550
|
body.appendChild(pane);
|
|
13470
14551
|
tabsContainer.scrollLeft = tabsContainer.scrollWidth;
|
|
13471
14552
|
window.switchTerminalTab(tabId);
|
|
@@ -13560,12 +14641,17 @@ window.switchTerminalTab = function(tabId) {
|
|
|
13560
14641
|
// Update tabs
|
|
13561
14642
|
var allTabs = document.querySelectorAll('.terminal-tab');
|
|
13562
14643
|
for (var i = 0; i < allTabs.length; i++) {
|
|
13563
|
-
|
|
14644
|
+
var selected = parseInt(allTabs[i].getAttribute('data-tab-id')) === tabId;
|
|
14645
|
+
allTabs[i].classList.toggle('active', selected);
|
|
14646
|
+
allTabs[i].setAttribute('aria-selected', selected ? 'true' : 'false');
|
|
14647
|
+
allTabs[i].tabIndex = selected ? 0 : -1;
|
|
13564
14648
|
}
|
|
13565
14649
|
// Update panes
|
|
13566
14650
|
var allPanes = document.querySelectorAll('.terminal-pane');
|
|
13567
14651
|
for (var j = 0; j < allPanes.length; j++) {
|
|
13568
|
-
|
|
14652
|
+
var active = parseInt(allPanes[j].getAttribute('data-tab-id')) === tabId;
|
|
14653
|
+
allPanes[j].classList.toggle('active', active);
|
|
14654
|
+
allPanes[j].hidden = !active;
|
|
13569
14655
|
}
|
|
13570
14656
|
// Update active session
|
|
13571
14657
|
var activePane = document.querySelector('.terminal-pane.active');
|
|
@@ -13751,6 +14837,7 @@ function renderTodo() {
|
|
|
13751
14837
|
label.textContent = t('goal.list') + (items.length ? ' ' + items.length : '');
|
|
13752
14838
|
var toggle = wrap.querySelector('#todo-header .stack-icon-btn');
|
|
13753
14839
|
if (toggle) {
|
|
14840
|
+
toggle.setAttribute('aria-expanded', state.todoCollapsed ? 'false' : 'true');
|
|
13754
14841
|
var title = state.todoCollapsed ? t('queue.expand') : t('queue.collapse');
|
|
13755
14842
|
toggle.title = title;
|
|
13756
14843
|
toggle.innerHTML = iconSvg(state.todoCollapsed ? 'chevron-up' : 'chevron-down', title, 'tiny');
|
|
@@ -13763,10 +14850,10 @@ function renderTodo() {
|
|
|
13763
14850
|
for (var i = 0; i < items.length; i++) {
|
|
13764
14851
|
var item = items[i];
|
|
13765
14852
|
var done = item.status === 'done';
|
|
13766
|
-
html += '<
|
|
14853
|
+
html += '<button type="button" class="todo-item ' + (done ? 'done' : '') + '" onclick="window.checkTodo(' + i + ')" title="' + escAttr(item.text) + '" aria-pressed="' + (done ? 'true' : 'false') + '">' +
|
|
13767
14854
|
'<span class="todo-check">' + (done ? iconSvg('check', 'done', 'tiny') : '') + '</span>' +
|
|
13768
14855
|
'<span class="todo-text">' + esc(item.text) + '</span>' +
|
|
13769
|
-
'</
|
|
14856
|
+
'</button>';
|
|
13770
14857
|
}
|
|
13771
14858
|
list.innerHTML = html;
|
|
13772
14859
|
}
|
|
@@ -13867,8 +14954,61 @@ window.setInputMode = function(mode, persist) {
|
|
|
13867
14954
|
};
|
|
13868
14955
|
|
|
13869
14956
|
// === Sub-Window System ===
|
|
14957
|
+
var subWindowOriginFocus = null;
|
|
14958
|
+
function newmarkFocusableElements(container) {
|
|
14959
|
+
if (!container || !container.querySelectorAll) return [];
|
|
14960
|
+
return Array.prototype.slice.call(container.querySelectorAll('button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [contenteditable="true"], [tabindex]:not([tabindex="-1"])')).filter(function(element) {
|
|
14961
|
+
return !element.hidden && element.getAttribute('aria-hidden') !== 'true' && element.getClientRects().length > 0;
|
|
14962
|
+
});
|
|
14963
|
+
}
|
|
14964
|
+
|
|
14965
|
+
function focusSubWindowInitial() {
|
|
14966
|
+
var dialog = els['sub-win'];
|
|
14967
|
+
if (!dialog || !els['sub-win-overlay'].classList.contains('open')) return;
|
|
14968
|
+
var body = els['sub-win-body'];
|
|
14969
|
+
var target = body && (body.querySelector('[autofocus]') || newmarkFocusableElements(body)[0]);
|
|
14970
|
+
if (!target) target = dialog.querySelector('.sub-win-close') || dialog;
|
|
14971
|
+
if (target && typeof target.focus === 'function') target.focus({ preventScroll: true });
|
|
14972
|
+
}
|
|
14973
|
+
|
|
14974
|
+
function updateApplicationInertState() {
|
|
14975
|
+
var commandOpen = !!(document.getElementById('command-surface-overlay') && document.getElementById('command-surface-overlay').classList.contains('open'));
|
|
14976
|
+
var subWindowOpen = !!(els['sub-win-overlay'] && els['sub-win-overlay'].classList.contains('open'));
|
|
14977
|
+
var topbar = document.getElementById('topbar');
|
|
14978
|
+
var main = document.getElementById('main');
|
|
14979
|
+
if (topbar) topbar.inert = commandOpen || subWindowOpen;
|
|
14980
|
+
if (main) main.inert = commandOpen || subWindowOpen;
|
|
14981
|
+
if (els['sub-win-overlay']) els['sub-win-overlay'].inert = commandOpen;
|
|
14982
|
+
}
|
|
14983
|
+
window.updateApplicationInertState = updateApplicationInertState;
|
|
14984
|
+
|
|
14985
|
+
function trapNewmarkDialogFocus(event, container) {
|
|
14986
|
+
if (!event || event.key !== 'Tab' || !container) return false;
|
|
14987
|
+
var items = newmarkFocusableElements(container);
|
|
14988
|
+
if (!items.length) {
|
|
14989
|
+
event.preventDefault();
|
|
14990
|
+
if (typeof container.focus === 'function') container.focus();
|
|
14991
|
+
return true;
|
|
14992
|
+
}
|
|
14993
|
+
var first = items[0];
|
|
14994
|
+
var last = items[items.length - 1];
|
|
14995
|
+
var active = document.activeElement;
|
|
14996
|
+
if (event.shiftKey && (active === first || !container.contains(active))) {
|
|
14997
|
+
event.preventDefault();
|
|
14998
|
+
last.focus();
|
|
14999
|
+
return true;
|
|
15000
|
+
}
|
|
15001
|
+
if (!event.shiftKey && (active === last || !container.contains(active))) {
|
|
15002
|
+
event.preventDefault();
|
|
15003
|
+
first.focus();
|
|
15004
|
+
return true;
|
|
15005
|
+
}
|
|
15006
|
+
return false;
|
|
15007
|
+
}
|
|
15008
|
+
|
|
13870
15009
|
window.openSubWin = function(title, html) {
|
|
13871
15010
|
var overlayOpen = els['sub-win-overlay'].classList.contains('open');
|
|
15011
|
+
if (!overlayOpen && document.activeElement && typeof document.activeElement.focus === 'function') subWindowOriginFocus = document.activeElement;
|
|
13872
15012
|
if (overlayOpen && !state.restoringSubWindow && state.activeSubWindowView) {
|
|
13873
15013
|
if (!state.subWindowStack) state.subWindowStack = [];
|
|
13874
15014
|
state.subWindowStack.push({
|
|
@@ -13882,6 +15022,25 @@ window.openSubWin = function(title, html) {
|
|
|
13882
15022
|
els['sub-win-body'].innerHTML = html;
|
|
13883
15023
|
els['sub-win'].classList.toggle('memory-lab-window', !!(state.activeSubWindowView && state.activeSubWindowView.name === 'memoryLab'));
|
|
13884
15024
|
els['sub-win-overlay'].classList.add('open');
|
|
15025
|
+
updateApplicationInertState();
|
|
15026
|
+
requestAnimationFrame(focusSubWindowInitial);
|
|
15027
|
+
};
|
|
15028
|
+
|
|
15029
|
+
window.handleRightTabKey = function(event) {
|
|
15030
|
+
if (!event) return;
|
|
15031
|
+
var tabs = Array.prototype.slice.call((els['right-tabs'] || document).querySelectorAll('.tab-btn[data-tab]'));
|
|
15032
|
+
var index = tabs.indexOf(event.currentTarget);
|
|
15033
|
+
if (index < 0) return;
|
|
15034
|
+
var next = index;
|
|
15035
|
+
if (event.key === 'ArrowRight') next = (index + 1) % tabs.length;
|
|
15036
|
+
else if (event.key === 'ArrowLeft') next = (index - 1 + tabs.length) % tabs.length;
|
|
15037
|
+
else if (event.key === 'Home') next = 0;
|
|
15038
|
+
else if (event.key === 'End') next = tabs.length - 1;
|
|
15039
|
+
else return;
|
|
15040
|
+
event.preventDefault();
|
|
15041
|
+
var tab = tabs[next].getAttribute('data-tab');
|
|
15042
|
+
window.switchRightTab(tab);
|
|
15043
|
+
tabs[next].focus();
|
|
13885
15044
|
};
|
|
13886
15045
|
|
|
13887
15046
|
window.closeSubWin = function() {
|
|
@@ -13895,6 +15054,7 @@ window.closeSubWin = function() {
|
|
|
13895
15054
|
requestAnimationFrame(function() {
|
|
13896
15055
|
els['sub-win-body'].scrollTop = previous.scrollTop || 0;
|
|
13897
15056
|
state.restoringSubWindow = false;
|
|
15057
|
+
focusSubWindowInitial();
|
|
13898
15058
|
});
|
|
13899
15059
|
return;
|
|
13900
15060
|
}
|
|
@@ -13902,6 +15062,12 @@ window.closeSubWin = function() {
|
|
|
13902
15062
|
state.activeSubWindowView = null;
|
|
13903
15063
|
var win = els['sub-win'];
|
|
13904
15064
|
if (win) { win.classList.remove('memory-lab-window'); win.style.left = ''; win.style.top = ''; win.style.margin = ''; }
|
|
15065
|
+
var restoreFocus = subWindowOriginFocus;
|
|
15066
|
+
subWindowOriginFocus = null;
|
|
15067
|
+
updateApplicationInertState();
|
|
15068
|
+
requestAnimationFrame(function() {
|
|
15069
|
+
if (restoreFocus && restoreFocus.isConnected && typeof restoreFocus.focus === 'function') restoreFocus.focus({ preventScroll: true });
|
|
15070
|
+
});
|
|
13905
15071
|
};
|
|
13906
15072
|
|
|
13907
15073
|
function rerenderActiveSubWindowForLanguage() {
|
|
@@ -13950,19 +15116,19 @@ window.openSettings = function(tab) {
|
|
|
13950
15116
|
var activeTab = tab || state.settingsActiveTab || 'general';
|
|
13951
15117
|
var refreshingSettings = els['sub-win-overlay'].classList.contains('open') && state.activeSubWindowView && state.activeSubWindowView.name === 'settings';
|
|
13952
15118
|
window._settingsTabCache = window._settingsTabCache || {};
|
|
13953
|
-
var html = '<div class="settings-tabs">' +
|
|
13954
|
-
'<button class="stab-btn" data-stab="general" onclick="window.settingsTab(\'general\')">' + esc(t('settings.general')) + '</button>' +
|
|
13955
|
-
'<button class="stab-btn" data-stab="models" onclick="window.settingsTab(\'models\')">' + esc(t('settings.models')) + '</button>' +
|
|
13956
|
-
'<button class="stab-btn" data-stab="tools" onclick="window.settingsTab(\'tools\')">' + esc(t('settings.tools')) + '</button>' +
|
|
13957
|
-
'<button class="stab-btn" data-stab="archive" onclick="window.settingsTab(\'archive\')">' + esc(t('settings.archive')) + '</button>' +
|
|
13958
|
-
'<button class="stab-btn" data-stab="updates" onclick="window.settingsTab(\'updates\')">' + esc(t('settings.updates')) + '</button>' +
|
|
15119
|
+
var html = '<div class="settings-tabs" role="tablist" aria-label="' + escAttr(t('settings.title')) + '">' +
|
|
15120
|
+
'<button class="stab-btn" id="settings-tab-general" role="tab" aria-controls="stab-general" data-stab="general" onclick="window.settingsTab(\'general\')" onkeydown="window.handleSettingsTabKey(event)">' + esc(t('settings.general')) + '</button>' +
|
|
15121
|
+
'<button class="stab-btn" id="settings-tab-models" role="tab" aria-controls="stab-models" data-stab="models" onclick="window.settingsTab(\'models\')" onkeydown="window.handleSettingsTabKey(event)">' + esc(t('settings.models')) + '</button>' +
|
|
15122
|
+
'<button class="stab-btn" id="settings-tab-tools" role="tab" aria-controls="stab-tools" data-stab="tools" onclick="window.settingsTab(\'tools\')" onkeydown="window.handleSettingsTabKey(event)">' + esc(t('settings.tools')) + '</button>' +
|
|
15123
|
+
'<button class="stab-btn" id="settings-tab-archive" role="tab" aria-controls="stab-archive" data-stab="archive" onclick="window.settingsTab(\'archive\')" onkeydown="window.handleSettingsTabKey(event)">' + esc(t('settings.archive')) + '</button>' +
|
|
15124
|
+
'<button class="stab-btn" id="settings-tab-updates" role="tab" aria-controls="stab-updates" data-stab="updates" onclick="window.settingsTab(\'updates\')" onkeydown="window.handleSettingsTabKey(event)">' + esc(t('settings.updates')) + '</button>' +
|
|
13959
15125
|
'</div>' +
|
|
13960
|
-
'<div class="stab-panel" id="stab-general" data-lazy="1"></div>' +
|
|
15126
|
+
'<div class="stab-panel" id="stab-general" role="tabpanel" aria-labelledby="settings-tab-general" data-lazy="1"></div>' +
|
|
13961
15127
|
// Lazy: only render active tab on open; others render on first click
|
|
13962
|
-
(activeTab === 'models' ? '<div class="stab-panel" id="stab-models">' + renderModelSettings() + '</div>' : '<div class="stab-panel" id="stab-models" data-lazy="1"></div>') +
|
|
13963
|
-
(activeTab === 'tools' ? '<div class="stab-panel" id="stab-tools">' + renderToolSettings() + '</div>' : '<div class="stab-panel" id="stab-tools" data-lazy="1"></div>') +
|
|
13964
|
-
(activeTab === 'archive' ? '<div class="stab-panel" id="stab-archive">' + renderArchiveSettings() + '</div>' : '<div class="stab-panel" id="stab-archive" data-lazy="1"></div>') +
|
|
13965
|
-
(activeTab === 'updates' ? '<div class="stab-panel" id="stab-updates">' + renderUpdateSettings() + '</div>' : '<div class="stab-panel" id="stab-updates" data-lazy="1"></div>');
|
|
15128
|
+
(activeTab === 'models' ? '<div class="stab-panel" id="stab-models" role="tabpanel" aria-labelledby="settings-tab-models">' + renderModelSettings() + '</div>' : '<div class="stab-panel" id="stab-models" role="tabpanel" aria-labelledby="settings-tab-models" data-lazy="1"></div>') +
|
|
15129
|
+
(activeTab === 'tools' ? '<div class="stab-panel" id="stab-tools" role="tabpanel" aria-labelledby="settings-tab-tools">' + renderToolSettings() + '</div>' : '<div class="stab-panel" id="stab-tools" role="tabpanel" aria-labelledby="settings-tab-tools" data-lazy="1"></div>') +
|
|
15130
|
+
(activeTab === 'archive' ? '<div class="stab-panel" id="stab-archive" role="tabpanel" aria-labelledby="settings-tab-archive">' + renderArchiveSettings() + '</div>' : '<div class="stab-panel" id="stab-archive" role="tabpanel" aria-labelledby="settings-tab-archive" data-lazy="1"></div>') +
|
|
15131
|
+
(activeTab === 'updates' ? '<div class="stab-panel" id="stab-updates" role="tabpanel" aria-labelledby="settings-tab-updates">' + renderUpdateSettings() + '</div>' : '<div class="stab-panel" id="stab-updates" role="tabpanel" aria-labelledby="settings-tab-updates" data-lazy="1"></div>');
|
|
13966
15132
|
state.activeSubWindowView = { name: 'settings', tab: activeTab };
|
|
13967
15133
|
if (refreshingSettings) state.restoringSubWindow = true;
|
|
13968
15134
|
window.openSubWin(t('settings.title'), html);
|
|
@@ -14329,7 +15495,12 @@ window.settingsTab = function(name) {
|
|
|
14329
15495
|
state.settingsActiveTab = name || 'general';
|
|
14330
15496
|
var btns = document.querySelectorAll('.stab-btn');
|
|
14331
15497
|
for (var i = 0; i < btns.length; i++) {
|
|
14332
|
-
|
|
15498
|
+
var selected = btns[i].getAttribute('data-stab') === name;
|
|
15499
|
+
btns[i].classList.toggle('active', selected);
|
|
15500
|
+
if (btns[i].closest('.settings-tabs:not(.plugin-tabs)')) {
|
|
15501
|
+
btns[i].setAttribute('aria-selected', selected ? 'true' : 'false');
|
|
15502
|
+
btns[i].tabIndex = selected ? 0 : -1;
|
|
15503
|
+
}
|
|
14333
15504
|
}
|
|
14334
15505
|
// Render lazy panels on first access for faster initial open
|
|
14335
15506
|
var panelId = 'stab-' + name;
|
|
@@ -14355,6 +15526,7 @@ window.settingsTab = function(name) {
|
|
|
14355
15526
|
var panels = document.querySelectorAll('.stab-panel');
|
|
14356
15527
|
for (var j = 0; j < panels.length; j++) {
|
|
14357
15528
|
panels[j].classList.toggle('active', panels[j].id === panelId);
|
|
15529
|
+
panels[j].hidden = panels[j].id !== panelId;
|
|
14358
15530
|
}
|
|
14359
15531
|
if (name === 'models' && panel && panel.getAttribute('data-lazy') !== '1') window.loadGlobalAgentPrompt();
|
|
14360
15532
|
};
|
|
@@ -15154,36 +16326,29 @@ renderArchiveSettings = function() {
|
|
|
15154
16326
|
};
|
|
15155
16327
|
|
|
15156
16328
|
window.archiveCurrent = function() {
|
|
15157
|
-
if (!api.archive) return;
|
|
15158
16329
|
var currentId = activeConversationId();
|
|
15159
|
-
if (currentId
|
|
15160
|
-
|
|
15161
|
-
|
|
15162
|
-
|
|
15163
|
-
|
|
15164
|
-
|
|
15165
|
-
|
|
15166
|
-
|
|
15167
|
-
|
|
15168
|
-
|
|
15169
|
-
|
|
15170
|
-
|
|
15171
|
-
|
|
15172
|
-
|
|
15173
|
-
|
|
15174
|
-
|
|
15175
|
-
|
|
15176
|
-
|
|
15177
|
-
|
|
15178
|
-
|
|
15179
|
-
|
|
15180
|
-
|
|
15181
|
-
var stab = document.getElementById('stab-archive');
|
|
15182
|
-
if (stab) stab.innerHTML = renderArchiveSettings();
|
|
15183
|
-
if (state.settingsActiveTab === 'archive') window.settingsTab('archive');
|
|
15184
|
-
}).catch(function(err) {
|
|
15185
|
-
addMsg('assistant', '[Archive] ' + t('workspace.saveFailed') + ': ' + (err.message || String(err)), 'error', '');
|
|
15186
|
-
});
|
|
16330
|
+
if (!currentId || !window.archiveConv) return;
|
|
16331
|
+
// Use the same optimistic path as the conversation-row action. This keeps
|
|
16332
|
+
// the active conversation immediately gone even while a running/queued
|
|
16333
|
+
// runtime is being hard-stopped by the main process.
|
|
16334
|
+
return window.archiveConv(currentId);
|
|
16335
|
+
};
|
|
16336
|
+
|
|
16337
|
+
window.handleSettingsTabKey = function(event) {
|
|
16338
|
+
if (!event) return;
|
|
16339
|
+
var tabs = Array.prototype.slice.call(document.querySelectorAll('.settings-tabs:not(.plugin-tabs) [role="tab"]'));
|
|
16340
|
+
var index = tabs.indexOf(event.currentTarget);
|
|
16341
|
+
if (index < 0) return;
|
|
16342
|
+
var next = index;
|
|
16343
|
+
if (event.key === 'ArrowRight') next = (index + 1) % tabs.length;
|
|
16344
|
+
else if (event.key === 'ArrowLeft') next = (index - 1 + tabs.length) % tabs.length;
|
|
16345
|
+
else if (event.key === 'Home') next = 0;
|
|
16346
|
+
else if (event.key === 'End') next = tabs.length - 1;
|
|
16347
|
+
else return;
|
|
16348
|
+
event.preventDefault();
|
|
16349
|
+
var name = tabs[next].getAttribute('data-stab');
|
|
16350
|
+
window.settingsTab(name);
|
|
16351
|
+
tabs[next].focus();
|
|
15187
16352
|
};
|
|
15188
16353
|
|
|
15189
16354
|
window.loadArchive = function(idx, scope) {
|
|
@@ -15520,10 +16685,10 @@ function renderFlowItem(work, idx, expanded) {
|
|
|
15520
16685
|
componentsHtml += '</div>';
|
|
15521
16686
|
}
|
|
15522
16687
|
return '<div class="flow-item">' +
|
|
15523
|
-
'<
|
|
16688
|
+
'<button type="button" class="flow-item-header' + (expanded ? '' : ' collapsed') + '" aria-expanded="' + (expanded ? 'true' : 'false') + '" onclick="this.classList.toggle(\'collapsed\');this.setAttribute(\'aria-expanded\',this.classList.contains(\'collapsed\')?\'false\':\'true\')">' +
|
|
15524
16689
|
'<span class="arrow">></span><span class="flow-item-name">' + esc(work.name || t('flow.untitled')) + '</span>' +
|
|
15525
16690
|
'<span class="flow-item-type">' + (work.components ? work.components.length : 0) + ' ' + esc(t('flow.components')) + '</span>' +
|
|
15526
|
-
'</
|
|
16691
|
+
'</button>' +
|
|
15527
16692
|
'<div class="flow-item-children" style="margin-bottom:4px;">' +
|
|
15528
16693
|
'<div style="display:flex;gap:4px;padding:4px 0;">' +
|
|
15529
16694
|
'<button class="sec-btn" style="flex:1;font-size:10px;" onclick="window.addFlowComp(' + idx + ',\'dialog\')">+ ' + esc(t('flow.dialog')) + '</button>' +
|
|
@@ -15538,7 +16703,7 @@ function renderFlowItem(work, idx, expanded) {
|
|
|
15538
16703
|
window.newFlowWork = function() {
|
|
15539
16704
|
var html = '<div style="padding:10px;">' +
|
|
15540
16705
|
'<label style="display:block;font-size:12px;color:var(--text-dim);margin-bottom:6px;">' + esc(t('flow.workflowName')) + '</label>' +
|
|
15541
|
-
'<input id="new-flow-input" style="width:100%;padding:8px 10px;border:1px solid var(--glass-border-2);border-radius:var(--radius-sm);background:var(--glass-bg-1);color:var(--text);font-size:13px;outline:none;box-sizing:border-box;" placeholder="' + escAttr(t('flow.enterName')) + '" onkeydown="if(event.key===\'Enter\')window.doNewFlowWork()">' +
|
|
16706
|
+
'<input id="new-flow-input" style="width:100%;padding:8px 10px;border:1px solid var(--glass-border-2);border-radius:var(--radius-sm);background:var(--glass-bg-1);color:var(--text);font-size:13px;outline:none;box-sizing:border-box;" placeholder="' + escAttr(t('flow.enterName')) + '" onkeydown="if(event.key===\'Enter\'&&!event.isComposing&&event.key!==\'Process\'&&event.keyCode!==229)window.doNewFlowWork()">' +
|
|
15542
16707
|
'<div style="margin-top:12px;display:flex;gap:8px;">' +
|
|
15543
16708
|
'<button class="sec-btn primary" style="flex:1;" onclick="window.doNewFlowWork()">' + esc(t('common.create')) + '</button>' +
|
|
15544
16709
|
'<button class="sec-btn" onclick="window.showFlowEditor()">' + esc(t('common.cancel')) + '</button>' +
|
|
@@ -16223,11 +17388,17 @@ window.loadFileTree = async function(options) {
|
|
|
16223
17388
|
};
|
|
16224
17389
|
|
|
16225
17390
|
window.submitSelectedFlow = function() {
|
|
17391
|
+
if (!state._flowsLoaded && window.ensureFlowsLoaded) {
|
|
17392
|
+
return window.ensureFlowsLoaded().then(function() { return window.submitSelectedFlow(); });
|
|
17393
|
+
}
|
|
16226
17394
|
var selected = String(state.defaultFlow || (document.getElementById('flow-select') && document.getElementById('flow-select').value) || '');
|
|
16227
17395
|
var workIdx = state.flowWorks.findIndex(function(work) { return String(work && work.name || '') === selected; });
|
|
16228
17396
|
if (workIdx < 0) {
|
|
16229
|
-
|
|
16230
|
-
|
|
17397
|
+
var message = state.flowWorks.length
|
|
17398
|
+
? (currentLang() === 'zh' ? '请先选择一个 Flow。' : 'Select a Flow first.')
|
|
17399
|
+
: t('flow.noAvailable');
|
|
17400
|
+
showUiNotice(message, 'error', 'flow-select-required');
|
|
17401
|
+
return { ok: false, error: message };
|
|
16231
17402
|
}
|
|
16232
17403
|
return window.runFlowWork(workIdx);
|
|
16233
17404
|
};
|
|
@@ -16241,14 +17412,25 @@ function renderTreeNodes(nodes, parent, depth) {
|
|
|
16241
17412
|
var n = nodes[i];
|
|
16242
17413
|
var div = document.createElement('div');
|
|
16243
17414
|
div.className = 'ft-item';
|
|
17415
|
+
div.setAttribute('role', 'treeitem');
|
|
17416
|
+
var treeRoot = parent.closest ? (parent.closest('[role="tree"]') || parent) : parent;
|
|
17417
|
+
div.tabIndex = treeRoot.querySelector && treeRoot.querySelector('[role="treeitem"][tabindex="0"]') ? -1 : 0;
|
|
17418
|
+
div.addEventListener('keydown', window.handleFileTreeKey);
|
|
17419
|
+
div.addEventListener('focus', function() {
|
|
17420
|
+
var root = this.closest('[role="tree"]');
|
|
17421
|
+
if (!root) return;
|
|
17422
|
+
Array.prototype.forEach.call(root.querySelectorAll('[role="treeitem"]'), function(item) { item.tabIndex = item === document.activeElement ? 0 : -1; });
|
|
17423
|
+
});
|
|
16244
17424
|
div.style.paddingLeft = (8 + depth * 14) + 'px';
|
|
16245
17425
|
var icon = n.type === 'directory' ? iconSvg('folder', 'Folder', 'small') : iconSvg('file', 'File', 'small');
|
|
16246
17426
|
if (n.type === 'directory') {
|
|
17427
|
+
div.setAttribute('aria-expanded', 'false');
|
|
16247
17428
|
div.innerHTML = '<span class="ft-toggle collapsed">' + iconSvg('chevron-right', t('fileTree.toggleFolder'), 'tiny') + '</span>' +
|
|
16248
17429
|
'<span class="ft-icon">' + icon + '</span><span class="ft-name">' + esc(n.name) + '</span>';
|
|
16249
17430
|
parent.appendChild(div);
|
|
16250
17431
|
var childContainer = document.createElement('div');
|
|
16251
17432
|
childContainer.className = 'ft-children';
|
|
17433
|
+
childContainer.setAttribute('role', 'group');
|
|
16252
17434
|
childContainer.style.display = 'none';
|
|
16253
17435
|
parent.appendChild(childContainer);
|
|
16254
17436
|
div.onclick = function(node, toggle, children, childDepth) {
|
|
@@ -16257,6 +17439,7 @@ function renderTreeNodes(nodes, parent, depth) {
|
|
|
16257
17439
|
var opening = children.style.display === 'none';
|
|
16258
17440
|
children.style.display = opening ? 'block' : 'none';
|
|
16259
17441
|
toggle.classList.toggle('collapsed', !opening);
|
|
17442
|
+
this.setAttribute('aria-expanded', opening ? 'true' : 'false');
|
|
16260
17443
|
if (!opening || children.getAttribute('data-loaded') === 'true') return;
|
|
16261
17444
|
children.setAttribute('data-loading', 'true');
|
|
16262
17445
|
try {
|
|
@@ -16364,8 +17547,7 @@ window.renderNativeEditor = function() {
|
|
|
16364
17547
|
}
|
|
16365
17548
|
window.renderEditorGutter(code);
|
|
16366
17549
|
if (els['editor-language']) els['editor-language'].textContent = language;
|
|
16367
|
-
|
|
16368
|
-
if (els['editor-position']) els['editor-position'].textContent = before.length + ':' + (before[before.length - 1].length + 1);
|
|
17550
|
+
window.renderEditorCaretStatus();
|
|
16369
17551
|
if (els['editor-dirty']) els['editor-dirty'].textContent = code !== state.editorOriginal ? 'modified' : '';
|
|
16370
17552
|
if (els['editor-vim-mode']) els['editor-vim-mode'].textContent = state.editorVimEnabled ? state.editorVimMode.toUpperCase() : 'INSERT';
|
|
16371
17553
|
if (state.editorPreview && els['editor-md-preview']) els['editor-md-preview'].innerHTML = renderMessageContent(code);
|
|
@@ -16407,6 +17589,7 @@ window.editorSetValue = function(value, preserveUndo) {
|
|
|
16407
17589
|
if (!ta) return;
|
|
16408
17590
|
if (!preserveUndo && ta.value !== value) { state.editorUndo.push(ta.value); if (state.editorUndo.length > 100) state.editorUndo.shift(); state.editorRedo = []; }
|
|
16409
17591
|
ta.value = value;
|
|
17592
|
+
state.editorCompletionCache = [];
|
|
16410
17593
|
window.renderNativeEditor();
|
|
16411
17594
|
};
|
|
16412
17595
|
|
|
@@ -16435,23 +17618,100 @@ window.editorReplaceSelection = function(text) {
|
|
|
16435
17618
|
window.renderNativeEditor();
|
|
16436
17619
|
};
|
|
16437
17620
|
|
|
16438
|
-
window.
|
|
17621
|
+
window.applyEditorCompletionDelta = function(payload) {
|
|
17622
|
+
payload = payload || {};
|
|
17623
|
+
if (String(payload.requestId || '') !== String(state.editorCompletionRequest || '')) return;
|
|
17624
|
+
var delta = String(payload.text || '');
|
|
17625
|
+
if (!delta || !state.editorCompletionAnchor) return;
|
|
17626
|
+
state.editorCompletionStreamText = (state.editorCompletionStreamText || '') + delta;
|
|
17627
|
+
state.editorCompletionText = state.editorCompletionStreamText.slice(0, 1200);
|
|
17628
|
+
window.renderEditorGhostText();
|
|
17629
|
+
if (els['editor-completion']) { els['editor-completion'].textContent = ''; els['editor-completion'].classList.remove('open'); }
|
|
17630
|
+
};
|
|
17631
|
+
|
|
17632
|
+
function editorCompletionValueKey(value) {
|
|
17633
|
+
var text = String(value || '');
|
|
17634
|
+
var hash = 2166136261;
|
|
17635
|
+
for (var i = 0; i < text.length; i++) hash = Math.imul(hash ^ text.charCodeAt(i), 16777619);
|
|
17636
|
+
return text.length + ':' + (hash >>> 0);
|
|
17637
|
+
}
|
|
17638
|
+
|
|
17639
|
+
function editorCompletionAnchorKey(anchor) {
|
|
17640
|
+
return [anchor.path, anchor.start, anchor.end, editorCompletionValueKey(anchor.value)].join('\u0000');
|
|
17641
|
+
}
|
|
17642
|
+
|
|
17643
|
+
function editorCompletionCacheFind(anchor) {
|
|
17644
|
+
var cache = Array.isArray(state.editorCompletionCache) ? state.editorCompletionCache : [];
|
|
17645
|
+
state.editorCompletionCache = cache;
|
|
17646
|
+
var now = Date.now();
|
|
17647
|
+
var key = editorCompletionAnchorKey(anchor);
|
|
17648
|
+
for (var i = cache.length - 1; i >= 0; i--) {
|
|
17649
|
+
var item = cache[i];
|
|
17650
|
+
if (!item || item.expiresAt <= now) { cache.splice(i, 1); continue; }
|
|
17651
|
+
if (item.key === key) {
|
|
17652
|
+
cache.splice(i, 1);
|
|
17653
|
+
cache.unshift(item);
|
|
17654
|
+
return item;
|
|
17655
|
+
}
|
|
17656
|
+
}
|
|
17657
|
+
return null;
|
|
17658
|
+
}
|
|
17659
|
+
|
|
17660
|
+
function editorCompletionCachePut(anchor, text, ttl) {
|
|
17661
|
+
var cache = Array.isArray(state.editorCompletionCache) ? state.editorCompletionCache : [];
|
|
17662
|
+
var key = editorCompletionAnchorKey(anchor);
|
|
17663
|
+
state.editorCompletionCache = cache.filter(function(item) { return !item || item.key !== key; });
|
|
17664
|
+
state.editorCompletionCache.unshift({ key: key, text: text, expiresAt: Date.now() + ttl });
|
|
17665
|
+
if (state.editorCompletionCache.length > 16) state.editorCompletionCache.length = 16;
|
|
17666
|
+
}
|
|
17667
|
+
|
|
17668
|
+
window.requestEditorCompletion = async function(options) {
|
|
17669
|
+
options = options || {};
|
|
17670
|
+
var force = options.force === true;
|
|
16439
17671
|
var ta = els['editor-textarea']; if (!ta || !state.editorPath || !api.editorComplete) return;
|
|
16440
17672
|
var requestId = ++state.editorCompletionRequest;
|
|
16441
17673
|
var pos = ta.selectionStart;
|
|
16442
17674
|
var anchor = { path: state.editorPath, value: ta.value, start: pos, end: ta.selectionEnd };
|
|
16443
17675
|
state.editorCompletionAnchor = anchor;
|
|
17676
|
+
var cached = force ? null : editorCompletionCacheFind(anchor);
|
|
17677
|
+
if (cached) {
|
|
17678
|
+
state.editorCompletionInFlight = false;
|
|
17679
|
+
state.editorCompletionStreamText = '';
|
|
17680
|
+
state.editorCompletionText = cached.text || '';
|
|
17681
|
+
state.editorCompletionAnchor = state.editorCompletionText ? anchor : null;
|
|
17682
|
+
window.renderEditorGhostText();
|
|
17683
|
+
if (els['editor-completion']) { els['editor-completion'].textContent = ''; els['editor-completion'].classList.remove('open'); }
|
|
17684
|
+
return;
|
|
17685
|
+
}
|
|
16444
17686
|
if (els['editor-completion']) { els['editor-completion'].textContent = 'Predicting...'; els['editor-completion'].classList.add('open'); }
|
|
16445
|
-
|
|
16446
|
-
|
|
16447
|
-
var
|
|
17687
|
+
state.editorCompletionInFlight = true;
|
|
17688
|
+
state.editorCompletionStreamText = '';
|
|
17689
|
+
var beforeStart = Math.max(0, pos - 3200);
|
|
17690
|
+
var afterEnd = Math.min(ta.value.length, pos + 800);
|
|
17691
|
+
var result;
|
|
17692
|
+
try {
|
|
17693
|
+
result = await api.editorComplete({ requestId: String(requestId), path: state.editorPath, before: ta.value.slice(beforeStart, pos), after: ta.value.slice(pos, afterEnd) });
|
|
17694
|
+
} catch (error) {
|
|
17695
|
+
result = { ok: false, text: '', error: error && error.message ? error.message : String(error) };
|
|
17696
|
+
} finally {
|
|
17697
|
+
if (requestId === state.editorCompletionRequest) state.editorCompletionInFlight = false;
|
|
17698
|
+
}
|
|
16448
17699
|
if (requestId !== state.editorCompletionRequest) return;
|
|
16449
|
-
|
|
16450
|
-
|
|
17700
|
+
// Input/caret handlers already schedule the replacement request. Do not
|
|
17701
|
+
// recursively schedule here: that doubled provider traffic on fast edits.
|
|
17702
|
+
if (!window.editorAnchorMatches(anchor)) return;
|
|
17703
|
+
var suggestion = result && result.ok ? String(result.text || '').slice(0, 1200) : '';
|
|
17704
|
+
if (!suggestion.trim()) suggestion = '';
|
|
17705
|
+
state.editorCompletionText = suggestion;
|
|
17706
|
+
state.editorCompletionStreamText = '';
|
|
17707
|
+
state.editorCompletionAnchor = suggestion ? anchor : null;
|
|
17708
|
+
editorCompletionCachePut(anchor, suggestion, suggestion ? 15000 : 2000);
|
|
16451
17709
|
window.renderEditorGhostText();
|
|
16452
17710
|
if (els['editor-completion']) {
|
|
16453
|
-
|
|
16454
|
-
|
|
17711
|
+
// Empty/aborted/timeout responses are normal for an inline predictor. The
|
|
17712
|
+
// editor should stay quiet instead of flashing an error on every keystroke.
|
|
17713
|
+
els['editor-completion'].textContent = '';
|
|
17714
|
+
els['editor-completion'].classList.remove('open');
|
|
16455
17715
|
}
|
|
16456
17716
|
};
|
|
16457
17717
|
|
|
@@ -16480,7 +17740,7 @@ window.scheduleEditorCompletion = function() {
|
|
|
16480
17740
|
state.editorCompletionTimer = setTimeout(function() {
|
|
16481
17741
|
state.editorCompletionTimer = null;
|
|
16482
17742
|
window.requestEditorCompletion();
|
|
16483
|
-
},
|
|
17743
|
+
}, 300);
|
|
16484
17744
|
};
|
|
16485
17745
|
|
|
16486
17746
|
window.editorCaretSignature = function() {
|
|
@@ -16499,7 +17759,8 @@ window.handleEditorCaretChange = function() {
|
|
|
16499
17759
|
var signature = window.editorCaretSignature();
|
|
16500
17760
|
if (signature === state.editorCaretSignature) return;
|
|
16501
17761
|
state.editorCaretSignature = signature;
|
|
16502
|
-
window.
|
|
17762
|
+
window.renderEditorCaretStatus();
|
|
17763
|
+
window.renderEditorGhostText();
|
|
16503
17764
|
window.scheduleEditorCompletion();
|
|
16504
17765
|
};
|
|
16505
17766
|
|
|
@@ -16507,7 +17768,24 @@ window.acceptEditorCompletion = function() {
|
|
|
16507
17768
|
if (state.editorCompletionText && window.editorCompletionAnchorIsCurrent()) window.editorReplaceSelection(state.editorCompletionText);
|
|
16508
17769
|
window.dismissEditorCompletion();
|
|
16509
17770
|
};
|
|
16510
|
-
window.dismissEditorCompletion = function() {
|
|
17771
|
+
window.dismissEditorCompletion = function() {
|
|
17772
|
+
state.editorCompletionText = '';
|
|
17773
|
+
state.editorCompletionStreamText = '';
|
|
17774
|
+
state.editorCompletionAnchor = null;
|
|
17775
|
+
state.editorCompletionRequest++;
|
|
17776
|
+
if (state.editorCompletionInFlight && api.editorCompleteCancel) {
|
|
17777
|
+
try { Promise.resolve(api.editorCompleteCancel()).catch(function() {}); } catch (_) {}
|
|
17778
|
+
}
|
|
17779
|
+
if (els['editor-completion']) { els['editor-completion'].textContent = ''; els['editor-completion'].classList.remove('open'); }
|
|
17780
|
+
window.renderEditorGhostText();
|
|
17781
|
+
};
|
|
17782
|
+
|
|
17783
|
+
window.renderEditorCaretStatus = function() {
|
|
17784
|
+
var ta = els['editor-textarea'];
|
|
17785
|
+
if (!ta) return;
|
|
17786
|
+
var before = String(ta.value || '').slice(0, ta.selectionStart || 0).split('\n');
|
|
17787
|
+
if (els['editor-position']) els['editor-position'].textContent = before.length + ':' + (before[before.length - 1].length + 1);
|
|
17788
|
+
};
|
|
16511
17789
|
|
|
16512
17790
|
window.requestEditorAssist = async function() {
|
|
16513
17791
|
var ta = els['editor-textarea']; if (!ta || !state.editorPath || !api.editorAssist) return;
|
|
@@ -17113,6 +18391,42 @@ function rememberBrowserUrl(url, force, target) {
|
|
|
17113
18391
|
}
|
|
17114
18392
|
}
|
|
17115
18393
|
|
|
18394
|
+
window.handleFileTreeKey = function(event) {
|
|
18395
|
+
if (!event || event.defaultPrevented || event.isComposing || event.key === 'Process' || event.keyCode === 229 || event.target !== event.currentTarget) return false;
|
|
18396
|
+
var item = event.currentTarget;
|
|
18397
|
+
var root = item.closest('[role="tree"]');
|
|
18398
|
+
if (!root) return false;
|
|
18399
|
+
if (event.key === 'Enter' || event.key === ' ') return window.activateButtonLike(event);
|
|
18400
|
+
if (event.key === 'ArrowRight') {
|
|
18401
|
+
if (item.hasAttribute('aria-expanded') && item.getAttribute('aria-expanded') !== 'true') {
|
|
18402
|
+
event.preventDefault(); item.click(); return true;
|
|
18403
|
+
}
|
|
18404
|
+
var group = item.nextElementSibling;
|
|
18405
|
+
var child = group && group.matches('[role="group"]') ? group.querySelector('[role="treeitem"]') : null;
|
|
18406
|
+
if (child) { event.preventDefault(); child.focus({ preventScroll:true }); return true; }
|
|
18407
|
+
return false;
|
|
18408
|
+
}
|
|
18409
|
+
if (event.key === 'ArrowLeft') {
|
|
18410
|
+
if (item.getAttribute('aria-expanded') === 'true') { event.preventDefault(); item.click(); return true; }
|
|
18411
|
+
var ownerGroup = item.parentElement && item.parentElement.matches('[role="group"]') ? item.parentElement : null;
|
|
18412
|
+
var parentItem = ownerGroup && ownerGroup.previousElementSibling && ownerGroup.previousElementSibling.matches('[role="treeitem"]') ? ownerGroup.previousElementSibling : null;
|
|
18413
|
+
if (parentItem) { event.preventDefault(); parentItem.focus({ preventScroll:true }); return true; }
|
|
18414
|
+
return false;
|
|
18415
|
+
}
|
|
18416
|
+
var visible = Array.prototype.slice.call(root.querySelectorAll('[role="treeitem"]')).filter(function(node) { return node.getClientRects().length > 0; });
|
|
18417
|
+
var index = visible.indexOf(item);
|
|
18418
|
+
var next = index;
|
|
18419
|
+
if (event.key === 'ArrowDown') next = Math.min(visible.length - 1, index + 1);
|
|
18420
|
+
else if (event.key === 'ArrowUp') next = Math.max(0, index - 1);
|
|
18421
|
+
else if (event.key === 'Home') next = 0;
|
|
18422
|
+
else if (event.key === 'End') next = visible.length - 1;
|
|
18423
|
+
else return false;
|
|
18424
|
+
if (next < 0 || !visible[next]) return false;
|
|
18425
|
+
event.preventDefault();
|
|
18426
|
+
visible[next].focus({ preventScroll:true });
|
|
18427
|
+
return true;
|
|
18428
|
+
};
|
|
18429
|
+
|
|
17116
18430
|
function waitForBrowserCreationFloor() {
|
|
17117
18431
|
var remaining = NEWMARK_BROWSER_MIN_CREATE_DELAY_MS - (Date.now() - newmarkRendererStartedAt);
|
|
17118
18432
|
if (remaining <= 0) return Promise.resolve();
|
|
@@ -17332,7 +18646,14 @@ window.ensureBrowserPanel = function(options) {
|
|
|
17332
18646
|
var targetKey = browserTargetKey(target);
|
|
17333
18647
|
cancelBrowserGuestIdleDestroy();
|
|
17334
18648
|
if (!browserGuestCreatePromises[targetKey]) {
|
|
17335
|
-
|
|
18649
|
+
// Keep background Browser-Use demand off the startup hot path, but never
|
|
18650
|
+
// make a deliberate visible-tab click wait behind that memory guard. A
|
|
18651
|
+
// user explicitly opening Browser is an interaction deadline, not a
|
|
18652
|
+
// background prewarm request.
|
|
18653
|
+
var creationWait = options.activate === true
|
|
18654
|
+
? Promise.resolve()
|
|
18655
|
+
: waitForBrowserCreationFloor();
|
|
18656
|
+
browserGuestCreatePromises[targetKey] = creationWait.then(function() {
|
|
17336
18657
|
return initializeBrowserGuest(createBrowserGuestElement(target), target);
|
|
17337
18658
|
}).catch(function(error) {
|
|
17338
18659
|
delete browserGuestCreatePromises[targetKey];
|
|
@@ -17438,7 +18759,8 @@ function applyBackendConversations(items, activeId, workspaceId) {
|
|
|
17438
18759
|
updatedAt: item.updatedAt || '',
|
|
17439
18760
|
pinned: !!item.pinned,
|
|
17440
18761
|
pinnedAt: item.pinnedAt || '',
|
|
17441
|
-
order: Number(item.order || 0)
|
|
18762
|
+
order: Number(item.order || 0),
|
|
18763
|
+
branchCommunication: !!item.branchCommunication
|
|
17442
18764
|
});
|
|
17443
18765
|
}
|
|
17444
18766
|
// A stale list response can arrive between creating a conversation locally
|
|
@@ -17565,16 +18887,22 @@ function renderConversations() {
|
|
|
17565
18887
|
}
|
|
17566
18888
|
var div = document.createElement('div');
|
|
17567
18889
|
div.className = 'conv-item' + (conv.active ? ' active' : '');
|
|
18890
|
+
div.setAttribute('role', 'listitem');
|
|
18891
|
+
div.setAttribute('tabindex', conv.active ? '0' : '-1');
|
|
18892
|
+
div.setAttribute('aria-current', conv.active ? 'true' : 'false');
|
|
17568
18893
|
div.setAttribute('draggable', 'true');
|
|
17569
18894
|
div.setAttribute('data-conversation-id', String(conv.id || ''));
|
|
17570
18895
|
if (runtimeState && ['running', 'stopping', 'force_restarting'].indexOf(String(runtimeState.status || '')) >= 0) div.classList.add('marquee-border');
|
|
17571
18896
|
var runtimeBadge = runtimeState && runtimeState.status && runtimeState.status !== 'idle'
|
|
17572
18897
|
? '<span class="conv-runtime-badge ' + escAttr(String(runtimeState.status)) + '">' + esc(String(runtimeState.status)) + '</span>' : '';
|
|
17573
|
-
|
|
18898
|
+
var branchCommBadge = conv.branchCommunication
|
|
18899
|
+
? '<span class="conv-branch-comm-badge" title="' + escAttr(t('conversation.branchCommunicationBadge')) + '">' + esc(t('conversation.branchCommunicationBadge')) + '</span>' : '';
|
|
18900
|
+
div.innerHTML = '<span class="conv-summary" title="' + escAttr(String(conv.id || '')) + '">' + esc(displaySummary) + (conv.messageCount ? ' (' + esc(String(conv.messageCount)) + ')' : '') + '</span>' + branchCommBadge + runtimeBadge +
|
|
17574
18901
|
'<button class="conv-rename-btn" onclick="event.stopPropagation();window.editConversationName(' + i + ')" title="' + escAttr(t('conversation.rename')) + '">' + iconOnly('pencil', t('conversation.rename')) + '</button>' +
|
|
17575
|
-
'<button class="conv-archive-btn"
|
|
18902
|
+
'<button class="conv-archive-btn" onclick="event.stopPropagation();window.archiveConv(this.closest(".conv-item").getAttribute("data-conversation-id"))" title="' + escAttr(t('conversation.archive')) + '">' + iconOnly('archive', t('conversation.archive')) + '</button>' +
|
|
17576
18903
|
'<button class="conv-pin-btn' + (conv.pinned ? ' active' : '') + '" onclick="event.stopPropagation();window.toggleConversationPinned(' + i + ')" title="' + escAttr(conv.pinned ? t('conversation.unpin') : t('conversation.pin')) + '">' + iconOnly('pin', conv.pinned ? t('conversation.unpin') : t('conversation.pin')) + '</button>';
|
|
17577
18904
|
div.onclick = function(idx) { return function() { window.switchConversation(idx); }; }(i);
|
|
18905
|
+
div.addEventListener('keydown', window.handleConversationKey);
|
|
17578
18906
|
div.addEventListener('dragstart', function(event) {
|
|
17579
18907
|
this.classList.add('dragging');
|
|
17580
18908
|
if (event.dataTransfer) { event.dataTransfer.effectAllowed = 'move'; event.dataTransfer.setData('text/plain', this.getAttribute('data-conversation-id') || ''); }
|
|
@@ -17604,6 +18932,30 @@ function renderConversations() {
|
|
|
17604
18932
|
updateWorkspaceGate();
|
|
17605
18933
|
}
|
|
17606
18934
|
|
|
18935
|
+
window.handleConversationKey = function(event) {
|
|
18936
|
+
if (!event || event.defaultPrevented || event.isComposing || event.key === 'Process' || event.keyCode === 229 || event.target !== event.currentTarget) return false;
|
|
18937
|
+
if (event.key === 'Enter' || event.key === ' ') return window.activateButtonLike(event);
|
|
18938
|
+
var items = Array.prototype.slice.call(document.querySelectorAll('#conversation-list .conv-item'));
|
|
18939
|
+
var index = items.indexOf(event.currentTarget);
|
|
18940
|
+
if (index < 0 || !items.length) return false;
|
|
18941
|
+
var next = index;
|
|
18942
|
+
if (event.key === 'ArrowDown') next = (index + 1) % items.length;
|
|
18943
|
+
else if (event.key === 'ArrowUp') next = (index - 1 + items.length) % items.length;
|
|
18944
|
+
else if (event.key === 'Home') next = 0;
|
|
18945
|
+
else if (event.key === 'End') next = items.length - 1;
|
|
18946
|
+
else return false;
|
|
18947
|
+
event.preventDefault();
|
|
18948
|
+
var nextId = items[next].getAttribute('data-conversation-id');
|
|
18949
|
+
items[next].click();
|
|
18950
|
+
requestAnimationFrame(function() {
|
|
18951
|
+
var replacement = Array.prototype.slice.call(document.querySelectorAll('#conversation-list .conv-item')).find(function(item) {
|
|
18952
|
+
return item.getAttribute('data-conversation-id') === nextId;
|
|
18953
|
+
});
|
|
18954
|
+
if (replacement) replacement.focus({ preventScroll:true });
|
|
18955
|
+
});
|
|
18956
|
+
return true;
|
|
18957
|
+
};
|
|
18958
|
+
|
|
17607
18959
|
window.newConversationOld = function() {
|
|
17608
18960
|
var id = 'conv-' + Date.now();
|
|
17609
18961
|
var summary = t('left.newChat') + ' ' + (state.conversations.length + 1);
|
|
@@ -17637,7 +18989,7 @@ window.archiveConvOld = function(idx) {
|
|
|
17637
18989
|
}
|
|
17638
18990
|
};
|
|
17639
18991
|
|
|
17640
|
-
window.newConversation = function(workspaceReference) {
|
|
18992
|
+
window.newConversation = function(workspaceReference, branchCommunication) {
|
|
17641
18993
|
if (workspaceReference && workspaceReference !== state.currentWorkspaceId) {
|
|
17642
18994
|
window.selectWorkspace(workspaceReference);
|
|
17643
18995
|
}
|
|
@@ -17667,6 +19019,13 @@ window.newConversation = function(workspaceReference) {
|
|
|
17667
19019
|
if (createdWorkspaceKey !== currentWorkspaceKey() || id !== String(activeConversationId() || 'default')) return;
|
|
17668
19020
|
state.activeBackendConversationId = String((s && s.conversationId) || id);
|
|
17669
19021
|
if (s) applyConversationSnapshot(s, id);
|
|
19022
|
+
if (branchCommunication && api.setConversationBranchCommunication) {
|
|
19023
|
+
api.setConversationBranchCommunication(target, true).then(function() {
|
|
19024
|
+
var convsNow = currentWorkspaceConversations();
|
|
19025
|
+
var created = convsNow.find(function(item){ return String(item && item.id) === id; });
|
|
19026
|
+
if (created) { created.branchCommunication = true; renderConversations(); }
|
|
19027
|
+
}).catch(function(){});
|
|
19028
|
+
}
|
|
17670
19029
|
}).then(function() {
|
|
17671
19030
|
if (createdWorkspaceKey !== currentWorkspaceKey() || id !== String(activeConversationId() || 'default')) return;
|
|
17672
19031
|
state.foregroundConversationHoldId = '';
|
|
@@ -17693,6 +19052,7 @@ window.showNewConversationPage = function() {
|
|
|
17693
19052
|
var html = '<div style="display:flex;flex-direction:column;gap:12px;padding:4px 2px;">' +
|
|
17694
19053
|
'<div style="font-size:12px;color:var(--text-dim);line-height:1.5;">' + esc(t('workspace.newConversationDesc')) + '</div>' +
|
|
17695
19054
|
'<div class="auto-input-group"><label>' + esc(t('status.workspace')) + '</label><select id="new-conv-ws">' + options + '</select></div>' +
|
|
19055
|
+
'<div class="auto-input-group" style="flex-direction:row;align-items:center;gap:8px;"><label style="display:flex;align-items:center;gap:6px;cursor:pointer;font-size:12px;"><input type="checkbox" id="new-conv-branch-comm" style="accent-color:var(--accent);">' + esc(t('conversation.branchCommunication')) + '</label></div>' +
|
|
17696
19056
|
'<div style="display:flex;gap:8px;">' +
|
|
17697
19057
|
'<button class="sec-btn primary" style="flex:1;" onclick="window.doNewConversationFromPage()">' + esc(t('workspace.createConversation')) + '</button>' +
|
|
17698
19058
|
'<button class="sec-btn" style="flex:1;" onclick="window.showNewWorkspaceDialog()">' + esc(t('workspace.createAction')) + '</button>' +
|
|
@@ -17709,11 +19069,13 @@ window.doNewConversationFromPage = function() {
|
|
|
17709
19069
|
window.showNewWorkspaceDialog();
|
|
17710
19070
|
return;
|
|
17711
19071
|
}
|
|
19072
|
+
var branchComm = document.getElementById('new-conv-branch-comm');
|
|
19073
|
+
var branchCommunication = !!(branchComm && branchComm.checked);
|
|
17712
19074
|
window.switchToWorkspace(identity).then(function(ws) {
|
|
17713
19075
|
state.currentWorkspace = (ws && ws.name) || state.currentWorkspace;
|
|
17714
19076
|
state.currentWorkspaceId = workspaceIdentity(ws) || state.currentWorkspaceId || identity;
|
|
17715
19077
|
window.closeSubWin();
|
|
17716
|
-
window.newConversation(state.currentWorkspaceId);
|
|
19078
|
+
window.newConversation(state.currentWorkspaceId, branchCommunication);
|
|
17717
19079
|
}).catch(function(err) {
|
|
17718
19080
|
showUiNotice(t('workspace.selectAction') + ': ' + err.message, 'error', 'workspace-new-conversation-' + identity);
|
|
17719
19081
|
});
|
|
@@ -17774,8 +19136,13 @@ function refreshConversationArchivesAfterBatch() {
|
|
|
17774
19136
|
state.workspaceArchives = (items || []).map(function(a) {
|
|
17775
19137
|
return { id: a.id || a.name || String(a), name: a.name || String(a), firstLine: a.firstLine || '', date: a.date || '', scope: a.scope || 'workspace', workspace: a.workspace || state.currentWorkspace || '', restorable: !!a.restorable, conversationId: a.conversationId || '' };
|
|
17776
19138
|
});
|
|
17777
|
-
|
|
19139
|
+
var archiveSettingsOpen = typeof document !== 'undefined'
|
|
19140
|
+
&& state.settingsActiveTab === 'archive'
|
|
19141
|
+
&& !!document.getElementById('stab-archive');
|
|
19142
|
+
if (!archiveSettingsOpen) state.allArchives = [];
|
|
17778
19143
|
window.renderRightArchives();
|
|
19144
|
+
var stab = typeof document !== 'undefined' ? document.getElementById('stab-archive') : null;
|
|
19145
|
+
if (stab && archiveSettingsOpen) stab.innerHTML = renderArchiveSettings();
|
|
17779
19146
|
return items || [];
|
|
17780
19147
|
});
|
|
17781
19148
|
}
|
|
@@ -17810,10 +19177,6 @@ window.archiveConv = function(conversationId) {
|
|
|
17810
19177
|
var targetRuntime = currentConversationTarget(targetId);
|
|
17811
19178
|
var workspaceKey = currentWorkspaceKey();
|
|
17812
19179
|
var pendingKey = workspaceKey + '::' + targetId;
|
|
17813
|
-
if (runningConversationRecord(targetId)) {
|
|
17814
|
-
showUiNotice(currentLang() === 'zh' ? '运行中的对话不能归档。' : 'A running conversation cannot be archived.', 'error', 'archive-running-' + currentRuntimeKey(targetId));
|
|
17815
|
-
return;
|
|
17816
|
-
}
|
|
17817
19180
|
if (state.conversationArchivePending[pendingKey]) return;
|
|
17818
19181
|
var priorActiveId = String(((convs.find(function(item) { return item && item.active; }) || {}).id) || '');
|
|
17819
19182
|
var rollbackOrder = convs.map(function(item) { return String(item && item.id || 'default'); });
|
|
@@ -17845,6 +19208,25 @@ window.archiveConv = function(conversationId) {
|
|
|
17845
19208
|
state.activeBackendConversationId = nextActiveId;
|
|
17846
19209
|
if (els['chat-area']) els['chat-area'].innerHTML = '';
|
|
17847
19210
|
}
|
|
19211
|
+
// Archiving is a destructive handoff: remove the target's Flow takeover
|
|
19212
|
+
// locally at click time as well as removing its conversation row. The
|
|
19213
|
+
// backend cancellation/manifest write is asynchronous; a late Flow
|
|
19214
|
+
// promise must not leave a visible running bubble over the replacement
|
|
19215
|
+
// conversation while the archive is already in flight.
|
|
19216
|
+
if (state.flowTakeovers) {
|
|
19217
|
+
var archivedFlowKey = runtimeKeyFor(targetRuntime.workspaceId, targetRuntime.conversationId);
|
|
19218
|
+
var archivedFlowRecord = state.flowTakeovers[archivedFlowKey];
|
|
19219
|
+
if (archivedFlowRecord) {
|
|
19220
|
+
archivedFlowRecord.running = false;
|
|
19221
|
+
archivedFlowRecord.paused = false;
|
|
19222
|
+
archivedFlowRecord.runtimeLease = null;
|
|
19223
|
+
archivedFlowRecord.queueLease = null;
|
|
19224
|
+
delete state.flowTakeovers[archivedFlowKey];
|
|
19225
|
+
}
|
|
19226
|
+
if (priorActiveId === targetId && window.renderFlowTakeover) {
|
|
19227
|
+
window.renderFlowTakeover(false, '', { target: targetRuntime });
|
|
19228
|
+
}
|
|
19229
|
+
}
|
|
17848
19230
|
setConversationRuntimeState(targetRuntime, 'idle', '');
|
|
17849
19231
|
setWorking(!!runningConversationRecord(activeConversationId()));
|
|
17850
19232
|
renderConversations();
|
|
@@ -17853,39 +19235,37 @@ window.archiveConv = function(conversationId) {
|
|
|
17853
19235
|
archivePromise.then(function(receipt) {
|
|
17854
19236
|
if (!receipt || receipt.ok !== true) throw new Error((receipt && receipt.error) || 'Archive failed');
|
|
17855
19237
|
delete state.conversationArchivePending[pendingKey];
|
|
19238
|
+
var optimisticArchive = {
|
|
19239
|
+
id: receipt.fileName,
|
|
19240
|
+
name: receipt.fileName,
|
|
19241
|
+
firstLine: target.summary || '',
|
|
19242
|
+
date: new Date().toISOString(),
|
|
19243
|
+
scope: 'workspace',
|
|
19244
|
+
workspace: state.currentWorkspace || '',
|
|
19245
|
+
restorable: true,
|
|
19246
|
+
conversationId: receipt.conversationId || targetId,
|
|
19247
|
+
};
|
|
19248
|
+
state.workspaceArchives = (state.workspaceArchives || []).filter(function(item) {
|
|
19249
|
+
return String(item && item.id || item && item.name || '') !== String(optimisticArchive.id);
|
|
19250
|
+
});
|
|
19251
|
+
state.workspaceArchives.unshift(optimisticArchive);
|
|
19252
|
+
if (Array.isArray(state.allArchives) && state.allArchives.length) {
|
|
19253
|
+
state.allArchives = state.allArchives.filter(function(item) {
|
|
19254
|
+
return String(item && item.id || item && item.name || '') !== String(optimisticArchive.id);
|
|
19255
|
+
});
|
|
19256
|
+
state.allArchives.unshift(optimisticArchive);
|
|
19257
|
+
}
|
|
19258
|
+
window.renderRightArchives();
|
|
19259
|
+
var archiveSettings = typeof document !== 'undefined' ? document.getElementById('stab-archive') : null;
|
|
19260
|
+
if (archiveSettings && state.settingsActiveTab === 'archive') archiveSettings.innerHTML = renderArchiveSettings();
|
|
17856
19261
|
showUiNotice('[Archive] ' + t('archive.saved') + ': ' + receipt.fileName, 'success', 'archive-saved-' + targetId);
|
|
17857
19262
|
scheduleConversationArchiveRefresh(workspaceKey);
|
|
17858
19263
|
}).catch(function(err) {
|
|
17859
|
-
var pending = state.conversationArchivePending[pendingKey];
|
|
17860
19264
|
delete state.conversationArchivePending[pendingKey];
|
|
17861
|
-
|
|
17862
|
-
|
|
17863
|
-
|
|
17864
|
-
|
|
17865
|
-
var targetOrderIndex = orderIds.indexOf(targetId);
|
|
17866
|
-
for (var beforeIndex = targetOrderIndex - 1; beforeIndex >= 0 && restoreAt < 0; beforeIndex--) {
|
|
17867
|
-
var precedingIndex = workspaceConversations.findIndex(function(item) { return String(item && item.id || '') === orderIds[beforeIndex]; });
|
|
17868
|
-
if (precedingIndex >= 0) restoreAt = precedingIndex + 1;
|
|
17869
|
-
}
|
|
17870
|
-
for (var afterIndex = targetOrderIndex + 1; afterIndex < orderIds.length && restoreAt < 0; afterIndex++) {
|
|
17871
|
-
var followingIndex = workspaceConversations.findIndex(function(item) { return String(item && item.id || '') === orderIds[afterIndex]; });
|
|
17872
|
-
if (followingIndex >= 0) restoreAt = followingIndex;
|
|
17873
|
-
}
|
|
17874
|
-
if (restoreAt < 0) restoreAt = Math.min(Number(pending.index || 0), workspaceConversations.length);
|
|
17875
|
-
workspaceConversations.splice(restoreAt, 0, pending.target);
|
|
17876
|
-
if (pending.wasActive) {
|
|
17877
|
-
for (var j = 0; j < workspaceConversations.length; j++) workspaceConversations[j].active = String(workspaceConversations[j].id || '') === targetId;
|
|
17878
|
-
}
|
|
17879
|
-
}
|
|
17880
|
-
if (workspaceKey === currentWorkspaceKey()) {
|
|
17881
|
-
state.conversations = workspaceConversations;
|
|
17882
|
-
state.activeConversation = Math.max(0, workspaceConversations.findIndex(function(item) { return item && item.active; }));
|
|
17883
|
-
if (pending && pending.wasActive) {
|
|
17884
|
-
state.activeBackendConversationId = targetId;
|
|
17885
|
-
if (els['chat-area']) els['chat-area'].innerHTML = pending.chatHtml || '';
|
|
17886
|
-
}
|
|
17887
|
-
renderConversations();
|
|
17888
|
-
}
|
|
19265
|
+
// Keep the optimistic removal authoritative for this renderer session.
|
|
19266
|
+
// A failed IPC receipt is surfaced, but never resurrects the row under
|
|
19267
|
+
// the user's pointer; the next explicit workspace refresh is the only
|
|
19268
|
+
// path allowed to reconcile a failed destructive operation.
|
|
17889
19269
|
showUiNotice('[Archive] ' + t('workspace.saveFailed') + ': ' + (err.message || String(err)), 'error', 'archive-failed-' + targetId);
|
|
17890
19270
|
});
|
|
17891
19271
|
}
|
|
@@ -18693,37 +20073,117 @@ window.reindexMemoryLab = function() {
|
|
|
18693
20073
|
});
|
|
18694
20074
|
};
|
|
18695
20075
|
|
|
18696
|
-
// === Plugin
|
|
18697
|
-
|
|
18698
|
-
|
|
20076
|
+
// === Plugin / Skills Market ===
|
|
20077
|
+
var PLUGIN_TABS = ['mcp', 'dsh', 'installed', 'market', 'github'];
|
|
20078
|
+
|
|
20079
|
+
function pluginText(key, values) {
|
|
20080
|
+
var output = t(key);
|
|
20081
|
+
Object.keys(values || {}).forEach(function(name) {
|
|
20082
|
+
output = output.replace(new RegExp('\\{' + name + '\\}', 'g'), function() { return String(values[name]); });
|
|
20083
|
+
});
|
|
20084
|
+
return output;
|
|
20085
|
+
}
|
|
20086
|
+
|
|
20087
|
+
function pluginRequestActive(tab, generation) {
|
|
20088
|
+
return generation === state.pluginPanelGeneration
|
|
20089
|
+
&& state.pluginActiveTab === tab
|
|
20090
|
+
&& !!(state.activeSubWindowView && state.activeSubWindowView.name === 'plugins')
|
|
20091
|
+
&& !!(els['sub-win-overlay'] && els['sub-win-overlay'].classList.contains('open'))
|
|
20092
|
+
&& !!document.getElementById('plugin-panel');
|
|
20093
|
+
}
|
|
20094
|
+
|
|
20095
|
+
function pluginPanelState(message, kind, retryCall) {
|
|
20096
|
+
return '<div class="plugin-panel-state' + (kind === 'error' ? ' error' : '') + '" role="' + (kind === 'error' ? 'alert' : 'status') + '"' + (kind === 'loading' ? ' aria-live="polite" aria-busy="true"' : '') + '>' +
|
|
20097
|
+
'<span>' + esc(message) + '</span>' +
|
|
20098
|
+
(retryCall ? '<button type="button" class="sec-btn" onclick="' + retryCall + '">' + esc(t('plugins.retry')) + '</button>' : '') +
|
|
20099
|
+
'</div>';
|
|
20100
|
+
}
|
|
20101
|
+
|
|
20102
|
+
function pluginTabMarkup(tab, label) {
|
|
20103
|
+
var selected = state.pluginActiveTab === tab;
|
|
20104
|
+
return '<button type="button" class="stab-btn' + (selected ? ' active' : '') + '" id="plugin-tab-' + tab + '" role="tab" aria-selected="' + (selected ? 'true' : 'false') + '" aria-controls="plugin-panel" tabindex="' + (selected ? '0' : '-1') + '" data-plugin-tab="' + tab + '" onclick="window.selectPluginTab(\'' + tab + '\')" onkeydown="window.handlePluginTabKey(event)">' + esc(label) + '</button>';
|
|
20105
|
+
}
|
|
20106
|
+
|
|
20107
|
+
window.syncPluginTabs = function(focusTab) {
|
|
20108
|
+
var labels = { mcp: t('plugins.tabMcp'), dsh: t('plugins.tabDsh'), installed: t('plugins.tabSkills'), market: t('plugins.tabMarket'), github: t('plugins.tabGithub') };
|
|
20109
|
+
PLUGIN_TABS.forEach(function(tab) {
|
|
20110
|
+
var button = document.getElementById('plugin-tab-' + tab);
|
|
20111
|
+
if (!button) return;
|
|
20112
|
+
var selected = tab === state.pluginActiveTab;
|
|
20113
|
+
button.classList.toggle('active', selected);
|
|
20114
|
+
button.setAttribute('aria-selected', selected ? 'true' : 'false');
|
|
20115
|
+
button.tabIndex = selected ? 0 : -1;
|
|
20116
|
+
button.textContent = labels[tab];
|
|
20117
|
+
});
|
|
20118
|
+
var tablist = document.querySelector('.plugin-tabs[role="tablist"]');
|
|
20119
|
+
if (tablist) tablist.setAttribute('aria-label', t('plugins.title'));
|
|
20120
|
+
if (els['sub-win-title']) els['sub-win-title'].textContent = t('plugins.title');
|
|
20121
|
+
var panel = document.getElementById('plugin-panel');
|
|
20122
|
+
if (panel) panel.setAttribute('aria-labelledby', 'plugin-tab-' + state.pluginActiveTab);
|
|
20123
|
+
if (focusTab) {
|
|
20124
|
+
var activeButton = document.getElementById('plugin-tab-' + state.pluginActiveTab);
|
|
20125
|
+
if (activeButton) activeButton.focus({ preventScroll: true });
|
|
20126
|
+
}
|
|
18699
20127
|
};
|
|
18700
20128
|
|
|
18701
|
-
|
|
18702
|
-
|
|
18703
|
-
var
|
|
18704
|
-
|
|
18705
|
-
|
|
18706
|
-
|
|
18707
|
-
|
|
18708
|
-
|
|
18709
|
-
|
|
18710
|
-
|
|
18711
|
-
|
|
18712
|
-
|
|
18713
|
-
|
|
18714
|
-
window.
|
|
18715
|
-
|
|
18716
|
-
|
|
18717
|
-
|
|
18718
|
-
|
|
20129
|
+
window.handlePluginTabKey = function(event) {
|
|
20130
|
+
if (!event || PLUGIN_TABS.indexOf(state.pluginActiveTab) < 0) return;
|
|
20131
|
+
var index = PLUGIN_TABS.indexOf(state.pluginActiveTab);
|
|
20132
|
+
if (event.key === 'ArrowRight') index = (index + 1) % PLUGIN_TABS.length;
|
|
20133
|
+
else if (event.key === 'ArrowLeft') index = (index - 1 + PLUGIN_TABS.length) % PLUGIN_TABS.length;
|
|
20134
|
+
else if (event.key === 'Home') index = 0;
|
|
20135
|
+
else if (event.key === 'End') index = PLUGIN_TABS.length - 1;
|
|
20136
|
+
else return;
|
|
20137
|
+
event.preventDefault();
|
|
20138
|
+
window.showPluginList(PLUGIN_TABS[index], { focusTab: true });
|
|
20139
|
+
};
|
|
20140
|
+
|
|
20141
|
+
window.selectPluginTab = function(tab) {
|
|
20142
|
+
window.showPluginList(tab, { focusTab: false });
|
|
20143
|
+
};
|
|
20144
|
+
|
|
20145
|
+
window.showPluginList = function(tab, options) {
|
|
20146
|
+
var requested = PLUGIN_TABS.indexOf(tab) >= 0 ? tab : (PLUGIN_TABS.indexOf(state.pluginActiveTab) >= 0 ? state.pluginActiveTab : 'mcp');
|
|
20147
|
+
var overlayOpen = !!(els['sub-win-overlay'] && els['sub-win-overlay'].classList.contains('open'));
|
|
20148
|
+
var pluginOpen = overlayOpen && state.activeSubWindowView && state.activeSubWindowView.name === 'plugins' && !!document.getElementById('plugin-panel');
|
|
20149
|
+
state.pluginActiveTab = requested;
|
|
20150
|
+
state.pluginPanelGeneration++;
|
|
20151
|
+
if (!pluginOpen) {
|
|
20152
|
+
var html = '<div class="settings-tabs plugin-tabs" role="tablist" aria-label="' + escAttr(t('plugins.title')) + '">' +
|
|
20153
|
+
pluginTabMarkup('mcp', t('plugins.tabMcp')) +
|
|
20154
|
+
pluginTabMarkup('dsh', t('plugins.tabDsh')) +
|
|
20155
|
+
pluginTabMarkup('installed', t('plugins.tabSkills')) +
|
|
20156
|
+
pluginTabMarkup('market', t('plugins.tabMarket')) +
|
|
20157
|
+
pluginTabMarkup('github', t('plugins.tabGithub')) +
|
|
20158
|
+
'</div><div id="plugin-panel" class="plugin-panel" role="tabpanel" tabindex="0" aria-labelledby="plugin-tab-' + requested + '"></div>';
|
|
20159
|
+
if (overlayOpen && state.activeSubWindowView) {
|
|
20160
|
+
window.openSubWin(t('plugins.title'), html);
|
|
20161
|
+
state.activeSubWindowView = { name: 'plugins', tab: requested };
|
|
20162
|
+
} else {
|
|
20163
|
+
state.activeSubWindowView = { name: 'plugins', tab: requested };
|
|
20164
|
+
window.openSubWin(t('plugins.title'), html);
|
|
20165
|
+
}
|
|
20166
|
+
if (els['sub-win']) els['sub-win'].classList.remove('memory-lab-window');
|
|
20167
|
+
} else {
|
|
20168
|
+
state.activeSubWindowView = { name: 'plugins', tab: requested };
|
|
20169
|
+
}
|
|
20170
|
+
window.syncPluginTabs(!pluginOpen || !!(options && options.focusTab));
|
|
20171
|
+
var panel = document.getElementById('plugin-panel');
|
|
20172
|
+
if (panel) panel.replaceChildren();
|
|
20173
|
+
if (requested === 'mcp') window.renderMcpManager();
|
|
20174
|
+
else if (requested === 'dsh') window.renderDshPlugin();
|
|
20175
|
+
else if (requested === 'market') window.renderSkillsMarket();
|
|
20176
|
+
else if (requested === 'github') window.renderGithubCliPanel();
|
|
18719
20177
|
else window.renderInstalledSkills();
|
|
18720
20178
|
};
|
|
18721
20179
|
|
|
18722
20180
|
window.renderInstalledSkills = function() {
|
|
18723
20181
|
var panel = document.getElementById('plugin-panel');
|
|
18724
|
-
if (!panel) return;
|
|
20182
|
+
if (!panel || state.pluginActiveTab !== 'installed') return;
|
|
20183
|
+
var generation = ++state.pluginPanelGeneration;
|
|
18725
20184
|
var render = function(items) {
|
|
18726
20185
|
state.skills = items || [];
|
|
20186
|
+
if (!pluginRequestActive('installed', generation)) return;
|
|
18727
20187
|
if (!items || !items.length) {
|
|
18728
20188
|
panel.innerHTML = '<div style="font-size:12px;color:var(--text-dim);padding:18px;text-align:center;">' + esc(t('plugins.noInstalled')) + '</div>';
|
|
18729
20189
|
return;
|
|
@@ -18764,14 +20224,15 @@ window.refreshSkillsRuntime = function(next) {
|
|
|
18764
20224
|
|
|
18765
20225
|
window.renderSkillsMarket = function() {
|
|
18766
20226
|
var panel = document.getElementById('plugin-panel');
|
|
18767
|
-
if (!panel) return;
|
|
20227
|
+
if (!panel || state.pluginActiveTab !== 'market') return;
|
|
20228
|
+
var generation = ++state.pluginPanelGeneration;
|
|
18768
20229
|
panel.innerHTML = '<div class="provider-card marquee-border">' + esc(t('plugins.discovering')) + '</div>';
|
|
18769
20230
|
state._skillMarketAll = [];
|
|
18770
20231
|
state._skillMarketSources = [];
|
|
18771
20232
|
var done = 0;
|
|
18772
20233
|
var finish = function() {
|
|
18773
20234
|
done++;
|
|
18774
|
-
if (done >= 2) window.renderSkillsMarketList();
|
|
20235
|
+
if (done >= 2 && pluginRequestActive('market', generation)) window.renderSkillsMarketList();
|
|
18775
20236
|
};
|
|
18776
20237
|
if (api.marketSkillSources) api.marketSkillSources().then(function(sources) {
|
|
18777
20238
|
state._skillMarketSources = sources || [];
|
|
@@ -18785,88 +20246,466 @@ window.renderSkillsMarket = function() {
|
|
|
18785
20246
|
else finish();
|
|
18786
20247
|
};
|
|
18787
20248
|
|
|
20249
|
+
var DSH_OFFICIAL_URLS = {
|
|
20250
|
+
repo: 'https://github.com/deepseek-ai/deepseek-harness',
|
|
20251
|
+
docs: 'https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/user/develop/basic/publish.md',
|
|
20252
|
+
npm: 'https://www.npmjs.com/package/@deepseek-ai/dsh'
|
|
20253
|
+
};
|
|
20254
|
+
|
|
20255
|
+
function dshCollection(value) {
|
|
20256
|
+
if (Array.isArray(value)) return value;
|
|
20257
|
+
if (value && typeof value === 'object') return Object.keys(value).map(function(key) {
|
|
20258
|
+
var item = value[key];
|
|
20259
|
+
if (item && typeof item === 'object' && !Array.isArray(item)) return Object.assign({ name: key }, item);
|
|
20260
|
+
return { name: key, value: item };
|
|
20261
|
+
});
|
|
20262
|
+
return [];
|
|
20263
|
+
}
|
|
20264
|
+
|
|
20265
|
+
function dshDisplayValue(value) {
|
|
20266
|
+
if (value === undefined || value === null || value === '') return t('plugins.dshNotAvailable');
|
|
20267
|
+
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') return String(value);
|
|
20268
|
+
try { return JSON.stringify(value); } catch (_) { return String(value); }
|
|
20269
|
+
}
|
|
20270
|
+
|
|
20271
|
+
function dshUniqueStrings(values) {
|
|
20272
|
+
var seen = Object.create(null);
|
|
20273
|
+
return dshCollection(values).map(function(value) {
|
|
20274
|
+
return typeof value === 'string' ? value : dshDisplayValue(value);
|
|
20275
|
+
}).filter(function(value) {
|
|
20276
|
+
var key = String(value || '');
|
|
20277
|
+
if (!key || seen[key]) return false;
|
|
20278
|
+
seen[key] = true;
|
|
20279
|
+
return true;
|
|
20280
|
+
});
|
|
20281
|
+
}
|
|
20282
|
+
|
|
20283
|
+
function dshListMarkup(items, emptyText, warning) {
|
|
20284
|
+
var values = dshCollection(items);
|
|
20285
|
+
if (!values.length) return '<div class="plugin-empty">' + esc(emptyText || t('plugins.dshNone')) + '</div>';
|
|
20286
|
+
return '<div class="dsh-list">' + values.map(function(item) {
|
|
20287
|
+
var label = item && typeof item === 'object'
|
|
20288
|
+
? (item.name || item.id || item.path || item.file || item.key || dshDisplayValue(item))
|
|
20289
|
+
: item;
|
|
20290
|
+
var detail = item && typeof item === 'object' ? (item.version || item.source || item.value || item.reason || '') : '';
|
|
20291
|
+
return '<div class="dsh-list-item' + (warning ? ' warning' : '') + '"><strong>' + esc(redactSensitiveText(dshDisplayValue(label))) + '</strong>' + (detail && String(detail) !== String(label) ? '<div class="provider-meta">' + esc(redactSensitiveText(dshDisplayValue(detail))) + '</div>' : '') + '</div>';
|
|
20292
|
+
}).join('') + '</div>';
|
|
20293
|
+
}
|
|
20294
|
+
|
|
20295
|
+
function dshLayerMarkup(profile) {
|
|
20296
|
+
var layers = dshCollection(profile && profile.layers);
|
|
20297
|
+
if (!layers.length) return '<div class="plugin-empty">' + esc(t('plugins.dshNone')) + '</div>';
|
|
20298
|
+
return '<div class="dsh-list">' + layers.map(function(layer, index) {
|
|
20299
|
+
var kind = layer && layer.kind ? String(layer.kind) : 'layer';
|
|
20300
|
+
var order = Number.isFinite(Number(layer && layer.order)) ? Number(layer.order) + 1 : index + 1;
|
|
20301
|
+
var file = layer && (layer.path || layer.file) || '';
|
|
20302
|
+
return '<div class="dsh-list-item"><strong>' + esc(order + '. ' + kind + (layer && layer.name ? ' · ' + layer.name : '')) + '</strong>' +
|
|
20303
|
+
(file ? '<div class="provider-meta">' + esc(redactSensitiveText(file)) + '</div>' : '') + '</div>';
|
|
20304
|
+
}).join('') + '</div>';
|
|
20305
|
+
}
|
|
20306
|
+
|
|
20307
|
+
window.openDshOfficial = function(kind) {
|
|
20308
|
+
var url = DSH_OFFICIAL_URLS[kind];
|
|
20309
|
+
if (!url || !api.openWebUrl) {
|
|
20310
|
+
showUiNotice(t('plugins.dshUnavailable'), 'error', 'dsh-web-url');
|
|
20311
|
+
return;
|
|
20312
|
+
}
|
|
20313
|
+
var generation = state.pluginPanelGeneration;
|
|
20314
|
+
Promise.resolve(api.openWebUrl(url)).then(function(result) {
|
|
20315
|
+
if (result && (result.ok === false || result.success === false || result.error)) throw new Error(result.error || t('plugins.dshUnavailable'));
|
|
20316
|
+
}).catch(function(error) {
|
|
20317
|
+
if (pluginRequestActive('dsh', generation)) showUiNotice(error && error.message ? error.message : String(error), 'error', 'dsh-web-url');
|
|
20318
|
+
});
|
|
20319
|
+
};
|
|
20320
|
+
|
|
20321
|
+
window.renderDshPlugin = function() {
|
|
20322
|
+
var panel = document.getElementById('plugin-panel');
|
|
20323
|
+
if (!panel || state.pluginActiveTab !== 'dsh') return;
|
|
20324
|
+
var generation = ++state.pluginPanelGeneration;
|
|
20325
|
+
panel.innerHTML = pluginPanelState(t('plugins.dshScanning'), 'loading');
|
|
20326
|
+
if (!api.discoverDshCompatibility) {
|
|
20327
|
+
panel.innerHTML = pluginPanelState(t('plugins.dshUnavailable'), 'error');
|
|
20328
|
+
return;
|
|
20329
|
+
}
|
|
20330
|
+
Promise.resolve(api.discoverDshCompatibility()).then(function(snapshot) {
|
|
20331
|
+
if (!pluginRequestActive('dsh', generation)) return;
|
|
20332
|
+
state.dshCompatibility = snapshot && typeof snapshot === 'object' ? snapshot : {};
|
|
20333
|
+
window.renderDshPluginContent();
|
|
20334
|
+
}).catch(function(error) {
|
|
20335
|
+
if (!pluginRequestActive('dsh', generation)) return;
|
|
20336
|
+
var message = t('plugins.dshLoadError') + (error && error.message ? ' ' + error.message : '');
|
|
20337
|
+
panel.innerHTML = pluginPanelState(message, 'error', 'window.renderDshPlugin()');
|
|
20338
|
+
});
|
|
20339
|
+
};
|
|
20340
|
+
|
|
20341
|
+
window.renderDshPluginContent = function() {
|
|
20342
|
+
var panel = document.getElementById('plugin-panel');
|
|
20343
|
+
if (!panel || state.pluginActiveTab !== 'dsh') return;
|
|
20344
|
+
var dsh = state.dshCompatibility || {};
|
|
20345
|
+
var cli = dsh.cli && typeof dsh.cli === 'object' ? dsh.cli : {};
|
|
20346
|
+
var pkg = dsh.package && typeof dsh.package === 'object' ? dsh.package : {};
|
|
20347
|
+
var update = dsh.update && typeof dsh.update === 'object' ? dsh.update : {};
|
|
20348
|
+
var cliPath = cli.path || cli.executable || cli.commandPath || dsh.cliPath || '';
|
|
20349
|
+
var cliVersion = cli.version || dsh.cliVersion || '';
|
|
20350
|
+
var packageVersion = pkg.version || (cli.package && cli.package.version) || cli.packageVersion || dsh.packageVersion || '';
|
|
20351
|
+
var updateChannel = update.channel || update.tag || dsh.updateChannel || '';
|
|
20352
|
+
var updateLocked = update.locked === true || update.versionLocked === true || update.isLocked === true;
|
|
20353
|
+
if (String(updateChannel).toLowerCase() === 'latest' && !updateLocked) updateChannel = t('plugins.dshLatestChannel');
|
|
20354
|
+
var candidates = dshCollection(dsh.mcpCandidates);
|
|
20355
|
+
var configFiles = dshCollection(dsh.configFiles);
|
|
20356
|
+
dshCollection(dsh.profiles).forEach(function(profile) {
|
|
20357
|
+
if (profile && typeof profile === 'object') configFiles = configFiles.concat(dshCollection(profile.configFiles));
|
|
20358
|
+
});
|
|
20359
|
+
configFiles = dshUniqueStrings(configFiles);
|
|
20360
|
+
var html = '<section class="dsh-hero" id="dsh-hero" aria-labelledby="dsh-title">' +
|
|
20361
|
+
'<div class="dsh-hero-head"><div class="dsh-hero-copy"><div class="dsh-title" id="dsh-title">' + esc(t('plugins.dshTitle')) + '</div>' +
|
|
20362
|
+
'<div class="dsh-description">' + esc(t('plugins.dshHelp')) + '</div></div><span class="plugin-status-badge preview">' + esc(t('plugins.dshPreview')) + '</span></div>' +
|
|
20363
|
+
'<div class="dsh-actions"><button type="button" class="sec-btn primary" id="dsh-rescan" onclick="window.renderDshPlugin()">' + esc(t('plugins.dshRescan')) + '</button>' +
|
|
20364
|
+
'<button type="button" class="sec-btn" id="dsh-official-repo" onclick="window.openDshOfficial(\'repo\')">' + esc(t('plugins.dshOfficialRepo')) + '</button>' +
|
|
20365
|
+
'<button type="button" class="sec-btn" id="dsh-official-docs" onclick="window.openDshOfficial(\'docs\')">' + esc(t('plugins.dshOfficialDocs')) + '</button>' +
|
|
20366
|
+
'<button type="button" class="sec-btn" id="dsh-official-npm" onclick="window.openDshOfficial(\'npm\')">' + esc(t('plugins.dshOfficialNpm')) + '</button></div></section>';
|
|
20367
|
+
html += '<div class="dsh-grid">' +
|
|
20368
|
+
'<section class="dsh-card" id="dsh-cli-card"><div class="dsh-card-title">' + esc(t('plugins.dshCli')) + '</div><dl class="dsh-kv">' +
|
|
20369
|
+
'<dt>' + esc(t('plugins.dshCliPath')) + '</dt><dd id="dsh-cli-path">' + esc(redactSensitiveText(dshDisplayValue(cliPath))) + '</dd>' +
|
|
20370
|
+
'<dt>' + esc(t('plugins.dshCliVersion')) + '</dt><dd id="dsh-cli-version">' + esc(dshDisplayValue(cliVersion)) + '</dd>' +
|
|
20371
|
+
'<dt>' + esc(t('plugins.dshPackageVersion')) + '</dt><dd id="dsh-package-version">' + esc(dshDisplayValue(packageVersion)) + '</dd></dl></section>' +
|
|
20372
|
+
'<section class="dsh-card" id="dsh-runtime-card"><div class="dsh-card-title">' + esc(t('plugins.dshReadonly')) + '</div><dl class="dsh-kv">' +
|
|
20373
|
+
'<dt>' + esc(t('plugins.dshHome')) + '</dt><dd id="dsh-home">' + esc(redactSensitiveText(dshDisplayValue(dsh.dshHome || dsh.home))) + '</dd>' +
|
|
20374
|
+
'<dt>' + esc(t('plugins.dshHomeSource')) + '</dt><dd id="dsh-home-source">' + esc(redactSensitiveText(dshDisplayValue(dsh.dshHomeSource || dsh.homeSource || (dsh.home && dsh.home.source)))) + '</dd>' +
|
|
20375
|
+
'<dt>' + esc(t('plugins.dshUpdateChannel')) + '</dt><dd id="dsh-update-channel">' + esc(dshDisplayValue(updateChannel)) + '</dd></dl>' +
|
|
20376
|
+
'<div class="dsh-description">' + esc(t('plugins.dshReadonlyDetail')) + '</div></section>' +
|
|
20377
|
+
'<section class="dsh-card" id="dsh-profiles-card"><div class="dsh-card-title">' + esc(t('plugins.dshProfiles')) + '</div>' + dshListMarkup(dsh.profiles) + '</section>' +
|
|
20378
|
+
'<section class="dsh-card" id="dsh-bundles-card"><div class="dsh-card-title">' + esc(t('plugins.dshBundles')) + '</div>' + dshListMarkup(dsh.bundles) + '</section>' +
|
|
20379
|
+
'<section class="dsh-card" id="dsh-warnings-card"><div class="dsh-card-title">' + esc(t('plugins.dshWarnings')) + '</div>' + dshListMarkup(dsh.warnings, t('plugins.dshNone'), true) + '</section>' +
|
|
20380
|
+
'<section class="dsh-card" id="dsh-unknown-keys-card"><div class="dsh-card-title">' + esc(t('plugins.dshUnknownKeys')) + '</div>' + dshListMarkup(dsh.unknownKeys) + '</section></div>';
|
|
20381
|
+
html += '<section class="plugin-section" id="dsh-config-files"><div class="plugin-section-head"><div class="plugin-section-title">' + esc(t('plugins.dshConfigFiles')) + '</div><span class="plugin-count-badge">' + configFiles.length + '</span></div>' + dshListMarkup(configFiles) + '</section>';
|
|
20382
|
+
html += '<section class="plugin-section" id="dsh-layers"><div class="plugin-section-head"><div class="plugin-section-title">' + esc(t('plugins.dshLayers')) + '</div></div><div class="mcp-field-help">' + esc(t('plugins.dshLayerOrder')) + '</div>';
|
|
20383
|
+
dshCollection(dsh.profiles).forEach(function(profile) {
|
|
20384
|
+
html += '<div class="dsh-layer-profile"><div class="plugin-section-title">' + esc(profile && (profile.name || profile.source) || t('plugins.dshNotAvailable')) + '</div>' + dshLayerMarkup(profile) + '</div>';
|
|
20385
|
+
});
|
|
20386
|
+
var homeFiles = dshCollection(dsh.homeConfigFiles);
|
|
20387
|
+
if (homeFiles.length) html += '<div class="dsh-layer-profile"><div class="plugin-section-title">' + esc(t('plugins.dshHomePatches')) + '</div>' + dshListMarkup(homeFiles) + '</div>';
|
|
20388
|
+
html += '<div class="mcp-field-help">' + esc(t('plugins.dshUpdateability')) + '</div></section>';
|
|
20389
|
+
html += '<section class="plugin-section" id="dsh-mcp-candidates"><div class="plugin-section-head"><div class="plugin-section-title">' + esc(t('plugins.dshMcpCandidates')) + '</div><span class="plugin-count-badge">' + candidates.length + '</span></div>' +
|
|
20390
|
+
'<div class="mcp-field-help">' + esc(t('plugins.mcpCandidateHelp')) + '</div>';
|
|
20391
|
+
if (!candidates.length) html += '<div class="plugin-empty">' + esc(t('plugins.dshNone')) + '</div>';
|
|
20392
|
+
candidates.forEach(function(candidate, index) {
|
|
20393
|
+
var name = candidate && (candidate.name || candidate.id) || ('MCP ' + (index + 1));
|
|
20394
|
+
var source = candidate && (candidate.source || candidate.path) || '';
|
|
20395
|
+
var reason = candidate && candidate.reason || '';
|
|
20396
|
+
var importable = !!(candidate && candidate.importable && candidate.template);
|
|
20397
|
+
html += '<div class="mcp-server-row" id="dsh-candidate-' + index + '" data-dsh-candidate-index="' + index + '"><div class="mcp-server-copy"><div class="mcp-server-title">' + esc(name) +
|
|
20398
|
+
'<span class="plugin-status-badge">' + esc(importable ? t('plugins.mcpReviewImport') : t('plugins.mcpReadonly')) + '</span></div>' +
|
|
20399
|
+
'<div class="mcp-server-meta">' + esc(redactSensitiveText(dshDisplayValue(source))) + '</div>' +
|
|
20400
|
+
(reason ? '<div class="mcp-server-meta">' + esc(redactSensitiveText(dshDisplayValue(reason))) + '</div>' : '') + '</div>' +
|
|
20401
|
+
(importable ? '<div class="mcp-row-actions"><button type="button" class="sec-btn" id="dsh-candidate-review-' + index + '" onclick="window.reviewDshMcpCandidate(' + index + ')">' + esc(t('plugins.mcpReviewImport')) + '</button></div>' : '') + '</div>';
|
|
20402
|
+
});
|
|
20403
|
+
html += '</section>';
|
|
20404
|
+
panel.innerHTML = html;
|
|
20405
|
+
};
|
|
20406
|
+
|
|
20407
|
+
function newMcpDraft(input, source) {
|
|
20408
|
+
input = input && typeof input === 'object' ? input : {};
|
|
20409
|
+
var transport = input.transport === 'http' ? 'http' : 'stdio';
|
|
20410
|
+
return {
|
|
20411
|
+
id: input.id || '',
|
|
20412
|
+
source: source || 'add',
|
|
20413
|
+
name: String(input.name || ''),
|
|
20414
|
+
transport: transport,
|
|
20415
|
+
command: String(input.command || ''),
|
|
20416
|
+
url: String(input.url || ''),
|
|
20417
|
+
argsText: JSON.stringify(Array.isArray(input.args) ? input.args : [], null, 2),
|
|
20418
|
+
cwd: String(input.cwd || ''),
|
|
20419
|
+
envText: input.env && typeof input.env === 'object' ? JSON.stringify(input.env, null, 2) : '',
|
|
20420
|
+
headersText: input.headers && typeof input.headers === 'object' ? JSON.stringify(input.headers, null, 2) : '',
|
|
20421
|
+
enabled: source === 'candidate' ? false : input.enabled !== false,
|
|
20422
|
+
envKeys: Array.isArray(input.envKeys) ? input.envKeys.slice() : [],
|
|
20423
|
+
headerKeys: Array.isArray(input.headerKeys) ? input.headerKeys.slice() : []
|
|
20424
|
+
};
|
|
20425
|
+
}
|
|
20426
|
+
|
|
20427
|
+
window.reviewDshMcpCandidate = function(index) {
|
|
20428
|
+
var candidates = dshCollection(state.dshCompatibility && state.dshCompatibility.mcpCandidates);
|
|
20429
|
+
var candidate = candidates[index];
|
|
20430
|
+
if (!candidate || !candidate.importable || !candidate.template) return;
|
|
20431
|
+
state.mcpEditingId = '';
|
|
20432
|
+
state.mcpDraft = newMcpDraft(Object.assign({}, candidate.template, {
|
|
20433
|
+
enabled: false,
|
|
20434
|
+
envKeys: Array.isArray(candidate.envKeys) ? candidate.envKeys : [],
|
|
20435
|
+
headerKeys: Array.isArray(candidate.headerKeys) ? candidate.headerKeys : []
|
|
20436
|
+
}), 'candidate');
|
|
20437
|
+
state.mcpFormFocusRequested = true;
|
|
20438
|
+
window.showPluginList('mcp');
|
|
20439
|
+
};
|
|
20440
|
+
|
|
18788
20441
|
window.renderMcpManager = function() {
|
|
18789
20442
|
var panel = document.getElementById('plugin-panel');
|
|
18790
|
-
if (!panel) return;
|
|
18791
|
-
|
|
20443
|
+
if (!panel || state.pluginActiveTab !== 'mcp') return;
|
|
20444
|
+
var generation = ++state.pluginPanelGeneration;
|
|
20445
|
+
panel.innerHTML = pluginPanelState(t('plugins.mcpRefreshing'), 'loading');
|
|
18792
20446
|
if (!api.listMcpServers) {
|
|
18793
|
-
panel.innerHTML =
|
|
20447
|
+
panel.innerHTML = pluginPanelState(t('plugins.mcpUnavailable'), 'error');
|
|
18794
20448
|
return;
|
|
18795
20449
|
}
|
|
18796
|
-
api.listMcpServers().then(function(result) {
|
|
20450
|
+
Promise.resolve(api.listMcpServers()).then(function(result) {
|
|
20451
|
+
if (!pluginRequestActive('mcp', generation)) return;
|
|
18797
20452
|
state.mcpServers = Array.isArray(result && result.servers) ? result.servers : [];
|
|
18798
20453
|
state.mcpDiscovered = Array.isArray(result && result.discovered) ? result.discovered : [];
|
|
18799
20454
|
window.renderMcpManagerContent();
|
|
18800
20455
|
}).catch(function(error) {
|
|
18801
|
-
|
|
20456
|
+
if (!pluginRequestActive('mcp', generation)) return;
|
|
20457
|
+
var message = t('plugins.mcpLoadError') + (error && error.message ? ' ' + error.message : '');
|
|
20458
|
+
panel.innerHTML = pluginPanelState(message, 'error', 'window.renderMcpManager()');
|
|
18802
20459
|
});
|
|
18803
20460
|
};
|
|
18804
20461
|
|
|
20462
|
+
function mcpSearchMatch(server, query) {
|
|
20463
|
+
server = server || {};
|
|
20464
|
+
if (!query) return true;
|
|
20465
|
+
var text = [server.name, server.transport, server.command, server.url, server.plugin, server.ecosystem, server.root]
|
|
20466
|
+
.concat(server.args || []).join(' ').toLowerCase();
|
|
20467
|
+
return text.indexOf(query) >= 0;
|
|
20468
|
+
}
|
|
20469
|
+
|
|
20470
|
+
function mcpSecretHelp(keys, keyName) {
|
|
20471
|
+
return keys && keys.length
|
|
20472
|
+
? pluginText(keyName, { keys: keys.join(', ') })
|
|
20473
|
+
: t('plugins.mcpNoSavedKeys');
|
|
20474
|
+
}
|
|
20475
|
+
|
|
20476
|
+
function renderMcpForm() {
|
|
20477
|
+
var draft = state.mcpDraft;
|
|
20478
|
+
if (!draft) return '';
|
|
20479
|
+
var pending = !!state.mcpMutationPending;
|
|
20480
|
+
var titleKey = draft.source === 'candidate' ? 'plugins.mcpReviewTitle' : (draft.id ? 'plugins.mcpEditTitle' : 'plugins.mcpAddTitle');
|
|
20481
|
+
var stdio = draft.transport !== 'http';
|
|
20482
|
+
return '<section class="mcp-form-card" id="mcp-form" aria-labelledby="mcp-form-title" aria-busy="' + (pending ? 'true' : 'false') + '">' +
|
|
20483
|
+
'<div class="mcp-form-head"><div class="mcp-form-copy"><div class="mcp-form-title" id="mcp-form-title">' + esc(t(titleKey)) + '</div><div class="mcp-form-subtitle">' + esc(t('plugins.mcpFormHelp')) + '</div></div></div>' +
|
|
20484
|
+
'<div class="mcp-field-grid"><div class="mcp-field"><label for="mcp-name">' + esc(t('plugins.mcpName')) + '</label><input class="mcp-input" id="mcp-name" value="' + escAttr(draft.name) + '" autocomplete="off"></div>' +
|
|
20485
|
+
'<div class="mcp-field"><label for="mcp-transport">' + esc(t('plugins.mcpTransport')) + '</label><select class="mcp-input" id="mcp-transport" onchange="window.updateMcpTransportForm()"><option value="stdio"' + (stdio ? ' selected' : '') + '>stdio</option><option value="http"' + (!stdio ? ' selected' : '') + '>http</option></select></div></div>' +
|
|
20486
|
+
'<div id="mcp-stdio-fields"' + (stdio ? '' : ' hidden') + '><div class="mcp-field"><label for="mcp-command">' + esc(t('plugins.mcpEndpointStdio')) + '</label><input class="mcp-input" id="mcp-command" value="' + escAttr(draft.command) + '" autocomplete="off"></div>' +
|
|
20487
|
+
'<div class="mcp-field"><label for="mcp-args">' + esc(t('plugins.mcpArgs')) + '</label><textarea class="mcp-input" id="mcp-args" spellcheck="false">' + esc(draft.argsText) + '</textarea></div>' +
|
|
20488
|
+
'<div class="mcp-field"><label for="mcp-cwd">' + esc(t('plugins.mcpCwd')) + '</label><input class="mcp-input" id="mcp-cwd" value="' + escAttr(draft.cwd) + '" autocomplete="off"></div>' +
|
|
20489
|
+
'<div class="mcp-field"><label for="mcp-env">' + esc(t('plugins.mcpEnv')) + '</label><textarea class="mcp-input" id="mcp-env" spellcheck="false" placeholder="{}">' + esc(draft.envText) + '</textarea><div class="mcp-field-help">' + esc(mcpSecretHelp(draft.envKeys, 'plugins.mcpSavedEnvKeys')) + ' ' + esc(t('plugins.mcpSecretsHelp')) + '</div></div></div>' +
|
|
20490
|
+
'<div id="mcp-http-fields"' + (!stdio ? '' : ' hidden') + '><div class="mcp-field"><label for="mcp-url">' + esc(t('plugins.mcpEndpointHttp')) + '</label><input class="mcp-input" id="mcp-url" value="' + escAttr(draft.url) + '" inputmode="url" autocomplete="url"></div>' +
|
|
20491
|
+
'<div class="mcp-field"><label for="mcp-headers">' + esc(t('plugins.mcpHeaders')) + '</label><textarea class="mcp-input" id="mcp-headers" spellcheck="false" placeholder="{}">' + esc(draft.headersText) + '</textarea><div class="mcp-field-help">' + esc(mcpSecretHelp(draft.headerKeys, 'plugins.mcpSavedHeaderKeys')) + ' ' + esc(t('plugins.mcpSecretsHelp')) + '</div></div></div>' +
|
|
20492
|
+
'<label class="mcp-enabled-check" for="mcp-enabled"><input id="mcp-enabled" type="checkbox"' + (draft.enabled ? ' checked' : '') + (pending ? ' disabled' : '') + '> ' + esc(t('plugins.mcpEnabled')) + '</label>' +
|
|
20493
|
+
'<div class="mcp-form-actions"><button type="button" class="sec-btn" id="mcp-cancel" onclick="window.cancelMcpForm()"' + (pending ? ' disabled' : '') + '>' + esc(t('common.cancel')) + '</button>' +
|
|
20494
|
+
'<button type="button" class="sec-btn primary" id="mcp-save" onclick="window.saveMcpServer()"' + (pending ? ' disabled' : '') + '>' + esc(pending ? t('plugins.mcpSaving') : t('plugins.mcpSave')) + '</button></div></section>';
|
|
20495
|
+
}
|
|
20496
|
+
|
|
18805
20497
|
window.renderMcpManagerContent = function() {
|
|
18806
20498
|
var panel = document.getElementById('plugin-panel');
|
|
18807
|
-
if (!panel) return;
|
|
18808
|
-
var
|
|
18809
|
-
var
|
|
18810
|
-
var
|
|
18811
|
-
var
|
|
18812
|
-
var
|
|
18813
|
-
|
|
18814
|
-
|
|
18815
|
-
'<input id="mcp-
|
|
18816
|
-
'<
|
|
18817
|
-
'<
|
|
18818
|
-
|
|
18819
|
-
|
|
18820
|
-
|
|
18821
|
-
|
|
18822
|
-
if (!servers.length) html += '<div class="settings-empty">' + esc(t('plugins.mcpNoServers')) + '</div>';
|
|
20499
|
+
if (!panel || state.pluginActiveTab !== 'mcp') return;
|
|
20500
|
+
var allServers = state.mcpServers || [];
|
|
20501
|
+
var allDiscovered = state.mcpDiscovered || [];
|
|
20502
|
+
var query = String(state.mcpSearchQuery || '').trim().toLowerCase();
|
|
20503
|
+
var servers = allServers.filter(function(server) { return mcpSearchMatch(server, query); });
|
|
20504
|
+
var discovered = allDiscovered.filter(function(server) { return mcpSearchMatch(server, query); });
|
|
20505
|
+
var pending = !!state.mcpMutationPending;
|
|
20506
|
+
var html = '<div class="plugin-toolbar"><div class="plugin-toolbar-copy"><div class="plugin-toolbar-title">' + esc(t('plugins.mcp')) + '</div><div class="plugin-toolbar-meta">' + esc(t('plugins.mcpHelp')) + '</div></div>' +
|
|
20507
|
+
'<input class="plugin-search" id="mcp-search" type="search" value="' + escAttr(state.mcpSearchQuery || '') + '" placeholder="' + escAttr(t('plugins.mcpSearch')) + '" aria-label="' + escAttr(t('plugins.mcpSearch')) + '" oninput="window.updateMcpSearch(this.value)">' +
|
|
20508
|
+
'<button type="button" class="sec-btn" id="mcp-refresh" onclick="window.renderMcpManager()"' + (pending ? ' disabled' : '') + '>' + esc(t('plugins.mcpRefresh')) + '</button>' +
|
|
20509
|
+
'<button type="button" class="sec-btn primary" id="mcp-add" onclick="window.openMcpAddForm()"' + (pending ? ' disabled' : '') + '>' + esc(t('plugins.mcpAdd')) + '</button></div>';
|
|
20510
|
+
html += renderMcpForm();
|
|
20511
|
+
html += '<section class="plugin-section" id="mcp-stored-section"><div class="plugin-section-head"><div class="plugin-section-title">' + esc(t('plugins.mcpStored')) + '</div><span class="plugin-count-badge">' + esc(pluginText('plugins.mcpConfiguredCount', { count: allServers.length })) + '</span></div>';
|
|
20512
|
+
if (!allServers.length) html += '<div class="plugin-empty">' + esc(t('plugins.mcpStoredEmpty')) + '</div>';
|
|
20513
|
+
else if (!servers.length) html += '<div class="plugin-empty">' + esc(t('plugins.mcpNoMatch')) + '</div>';
|
|
18823
20514
|
servers.forEach(function(server) {
|
|
18824
|
-
var
|
|
18825
|
-
|
|
18826
|
-
|
|
18827
|
-
'<
|
|
18828
|
-
'<
|
|
20515
|
+
var index = allServers.indexOf(server);
|
|
20516
|
+
var endpoint = server.transport === 'http' ? server.url : [server.command].concat(server.args || []).filter(Boolean).join(' ');
|
|
20517
|
+
html += '<div class="mcp-server-row" data-mcp-index="' + index + '"><div class="mcp-server-copy"><div class="mcp-server-title">' + esc(server.name || '') +
|
|
20518
|
+
'<span class="plugin-status-badge">' + esc(server.transport || 'stdio') + '</span><span class="plugin-status-badge' + (server.enabled ? ' enabled' : '') + '">' + esc(server.enabled ? t('plugins.mcpEnabledStatus') : t('plugins.mcpDisabledStatus')) + '</span></div>' +
|
|
20519
|
+
'<div class="mcp-server-meta">' + esc(endpoint || '') + '</div></div><div class="mcp-row-actions">' +
|
|
20520
|
+
'<button type="button" class="sec-btn" onclick="window.editMcpServerAt(' + index + ')"' + (pending ? ' disabled' : '') + '>' + esc(t('common.edit')) + '</button>' +
|
|
20521
|
+
'<button type="button" class="sec-btn" onclick="window.toggleMcpServerAt(' + index + ',' + (!server.enabled) + ')"' + (pending ? ' disabled' : '') + '>' + esc(server.enabled ? t('common.disable') : t('common.enable')) + '</button>' +
|
|
20522
|
+
'<button type="button" class="sec-btn" onclick="window.removeMcpServerAt(' + index + ')"' + (pending ? ' disabled' : '') + '>' + esc(t('common.remove')) + '</button></div></div>';
|
|
18829
20523
|
});
|
|
18830
|
-
html += '
|
|
18831
|
-
if (!
|
|
20524
|
+
html += '</section><section class="plugin-section" id="mcp-discovered-section"><div class="plugin-section-head"><div class="plugin-section-title">' + esc(t('plugins.mcpDiscovered')) + '</div><span class="plugin-count-badge">' + allDiscovered.length + '</span></div>';
|
|
20525
|
+
if (!allDiscovered.length) html += '<div class="plugin-empty">' + esc(t('plugins.mcpDiscoveredEmpty')) + '</div>';
|
|
20526
|
+
else if (!discovered.length) html += '<div class="plugin-empty">' + esc(t('plugins.mcpNoMatch')) + '</div>';
|
|
18832
20527
|
discovered.forEach(function(server) {
|
|
18833
|
-
html += '<div class="
|
|
20528
|
+
html += '<div class="mcp-server-row"><div class="mcp-server-copy"><div class="mcp-server-title">' + esc(server.name || '') +
|
|
20529
|
+
'<span class="plugin-status-badge">' + esc(server.ecosystem || t('plugins.mcpReadonly')) + '</span>' +
|
|
20530
|
+
'<span class="plugin-status-badge' + (server.enabled ? ' enabled' : '') + '">' + esc(server.enabled ? t('plugins.mcpEnabledStatus') : t('plugins.mcpDisabledStatus')) + '</span></div><div class="mcp-server-meta">' +
|
|
20531
|
+
esc([server.plugin, server.root].filter(Boolean).join(' · ')) + '</div></div><span class="plugin-status-badge">' + esc(t('plugins.mcpReadonly')) + '</span></div>';
|
|
18834
20532
|
});
|
|
20533
|
+
html += '</section>';
|
|
18835
20534
|
panel.innerHTML = html;
|
|
20535
|
+
window.updateMcpTransportForm(false);
|
|
20536
|
+
if (state.mcpFormFocusRequested) {
|
|
20537
|
+
state.mcpFormFocusRequested = false;
|
|
20538
|
+
requestAnimationFrame(function() {
|
|
20539
|
+
var form = document.getElementById('mcp-form');
|
|
20540
|
+
var input = document.getElementById('mcp-name');
|
|
20541
|
+
if (form) form.scrollIntoView({ block: 'nearest' });
|
|
20542
|
+
if (input) input.focus({ preventScroll: true });
|
|
20543
|
+
});
|
|
20544
|
+
}
|
|
20545
|
+
};
|
|
20546
|
+
|
|
20547
|
+
window.captureMcpDraftFromForm = function() {
|
|
20548
|
+
if (!state.mcpDraft || !document.getElementById('mcp-form')) return state.mcpDraft;
|
|
20549
|
+
var value = function(id) { var element = document.getElementById(id); return element ? element.value : ''; };
|
|
20550
|
+
state.mcpDraft.name = value('mcp-name');
|
|
20551
|
+
state.mcpDraft.transport = value('mcp-transport') === 'http' ? 'http' : 'stdio';
|
|
20552
|
+
state.mcpDraft.command = value('mcp-command');
|
|
20553
|
+
state.mcpDraft.url = value('mcp-url');
|
|
20554
|
+
state.mcpDraft.argsText = value('mcp-args');
|
|
20555
|
+
state.mcpDraft.cwd = value('mcp-cwd');
|
|
20556
|
+
state.mcpDraft.envText = value('mcp-env');
|
|
20557
|
+
state.mcpDraft.headersText = value('mcp-headers');
|
|
20558
|
+
var enabled = document.getElementById('mcp-enabled');
|
|
20559
|
+
state.mcpDraft.enabled = !!(enabled && enabled.checked);
|
|
20560
|
+
return state.mcpDraft;
|
|
20561
|
+
};
|
|
20562
|
+
|
|
20563
|
+
window.updateMcpTransportForm = function(capture) {
|
|
20564
|
+
if (capture !== false) window.captureMcpDraftFromForm();
|
|
20565
|
+
var transport = document.getElementById('mcp-transport');
|
|
20566
|
+
var stdio = document.getElementById('mcp-stdio-fields');
|
|
20567
|
+
var http = document.getElementById('mcp-http-fields');
|
|
20568
|
+
var isHttp = !!(transport && transport.value === 'http');
|
|
20569
|
+
if (state.mcpDraft) state.mcpDraft.transport = isHttp ? 'http' : 'stdio';
|
|
20570
|
+
if (stdio) stdio.hidden = isHttp;
|
|
20571
|
+
if (http) http.hidden = !isHttp;
|
|
18836
20572
|
};
|
|
18837
20573
|
|
|
18838
|
-
window.
|
|
18839
|
-
|
|
18840
|
-
|
|
18841
|
-
|
|
18842
|
-
|
|
18843
|
-
|
|
20574
|
+
window.openMcpAddForm = function() {
|
|
20575
|
+
if (state.mcpMutationPending) return;
|
|
20576
|
+
state.mcpEditingId = '';
|
|
20577
|
+
state.mcpDraft = newMcpDraft({ enabled: false, transport: 'stdio', args: [] }, 'add');
|
|
20578
|
+
state.mcpFormFocusRequested = true;
|
|
20579
|
+
window.renderMcpManagerContent();
|
|
18844
20580
|
};
|
|
18845
|
-
|
|
18846
|
-
window.
|
|
20581
|
+
|
|
20582
|
+
window.editMcpServerAt = function(index) {
|
|
20583
|
+
if (state.mcpMutationPending) return;
|
|
20584
|
+
var server = (state.mcpServers || [])[index];
|
|
20585
|
+
if (!server) return;
|
|
20586
|
+
state.mcpEditingId = server.id || '';
|
|
20587
|
+
state.mcpDraft = newMcpDraft(server, 'edit');
|
|
20588
|
+
state.mcpFormFocusRequested = true;
|
|
20589
|
+
window.renderMcpManagerContent();
|
|
20590
|
+
};
|
|
20591
|
+
|
|
20592
|
+
window.cancelMcpForm = function() {
|
|
20593
|
+
if (state.mcpMutationPending) return;
|
|
20594
|
+
state.mcpEditingId = '';
|
|
20595
|
+
state.mcpDraft = null;
|
|
20596
|
+
window.renderMcpManagerContent();
|
|
20597
|
+
var addButton = document.getElementById('mcp-add');
|
|
20598
|
+
if (addButton) addButton.focus({ preventScroll: true });
|
|
20599
|
+
};
|
|
20600
|
+
|
|
20601
|
+
window.updateMcpSearch = function(value) {
|
|
20602
|
+
window.captureMcpDraftFromForm();
|
|
20603
|
+
state.mcpSearchQuery = String(value || '');
|
|
20604
|
+
window.renderMcpManagerContent();
|
|
20605
|
+
var search = document.getElementById('mcp-search');
|
|
20606
|
+
if (search) {
|
|
20607
|
+
search.focus({ preventScroll: true });
|
|
20608
|
+
search.setSelectionRange(search.value.length, search.value.length);
|
|
20609
|
+
}
|
|
20610
|
+
};
|
|
20611
|
+
|
|
20612
|
+
function parseMcpObject(text, fieldLabel) {
|
|
20613
|
+
if (!String(text || '').trim()) return undefined;
|
|
20614
|
+
var parsed = JSON.parse(text);
|
|
20615
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error(pluginText('plugins.mcpInvalidObject', { field: fieldLabel }));
|
|
20616
|
+
return parsed;
|
|
20617
|
+
}
|
|
20618
|
+
|
|
20619
|
+
function mcpMutationUiActive(generation) {
|
|
20620
|
+
return generation === state.mcpMutationGeneration
|
|
20621
|
+
&& state.pluginActiveTab === 'mcp'
|
|
20622
|
+
&& !!(state.activeSubWindowView && state.activeSubWindowView.name === 'plugins')
|
|
20623
|
+
&& !!document.getElementById('plugin-panel');
|
|
20624
|
+
}
|
|
20625
|
+
|
|
18847
20626
|
window.saveMcpServer = function() {
|
|
18848
|
-
if (!api.upsertMcpServer) return;
|
|
18849
|
-
var
|
|
18850
|
-
|
|
18851
|
-
var
|
|
18852
|
-
var
|
|
18853
|
-
|
|
18854
|
-
var input = { id: state.mcpEditingId || undefined, name: name, transport: transport };
|
|
20627
|
+
if (!api.upsertMcpServer || state.mcpMutationPending) return;
|
|
20628
|
+
var draft = window.captureMcpDraftFromForm();
|
|
20629
|
+
if (!draft) return;
|
|
20630
|
+
var name = String(draft.name || '').trim();
|
|
20631
|
+
var transport = draft.transport === 'http' ? 'http' : 'stdio';
|
|
20632
|
+
if (!name) { showUiNotice(t('plugins.mcpRequiredName'), 'error', 'mcp-save'); return; }
|
|
20633
|
+
var input = { id: draft.id || state.mcpEditingId || undefined, name: name, transport: transport, enabled: !!draft.enabled };
|
|
18855
20634
|
try {
|
|
18856
|
-
if (transport === 'http') {
|
|
18857
|
-
|
|
20635
|
+
if (transport === 'http') {
|
|
20636
|
+
var url = String(draft.url || '').trim();
|
|
20637
|
+
if (!/^https?:\/\//i.test(url)) throw new Error(t('plugins.mcpRequiredUrl'));
|
|
20638
|
+
input.url = url;
|
|
20639
|
+
var headers = parseMcpObject(draft.headersText, t('plugins.mcpHeaders'));
|
|
20640
|
+
if (headers !== undefined) input.headers = headers;
|
|
20641
|
+
} else {
|
|
20642
|
+
var command = String(draft.command || '').trim();
|
|
20643
|
+
if (!command) throw new Error(t('plugins.mcpRequiredCommand'));
|
|
20644
|
+
var args = String(draft.argsText || '').trim() ? JSON.parse(draft.argsText) : [];
|
|
20645
|
+
if (!Array.isArray(args)) throw new Error(t('plugins.mcpInvalidArgs'));
|
|
20646
|
+
input.command = command;
|
|
20647
|
+
input.args = args;
|
|
20648
|
+
input.cwd = String(draft.cwd || '').trim() || undefined;
|
|
20649
|
+
var env = parseMcpObject(draft.envText, t('plugins.mcpEnv'));
|
|
20650
|
+
if (env !== undefined) input.env = env;
|
|
20651
|
+
}
|
|
18858
20652
|
} catch (error) {
|
|
18859
|
-
showUiNotice(error.message
|
|
20653
|
+
showUiNotice(error && error.message ? error.message : String(error), 'error', 'mcp-save');
|
|
18860
20654
|
return;
|
|
18861
20655
|
}
|
|
18862
|
-
|
|
18863
|
-
|
|
20656
|
+
var generation = ++state.mcpMutationGeneration;
|
|
20657
|
+
state.mcpMutationPending = true;
|
|
20658
|
+
window.renderMcpManagerContent();
|
|
20659
|
+
Promise.resolve(api.upsertMcpServer(input)).then(function(result) {
|
|
20660
|
+
if (!result || result.ok !== true) throw new Error(result && result.error || t('plugins.mcpMutationFailed'));
|
|
20661
|
+
if (Array.isArray(result.servers)) state.mcpServers = result.servers;
|
|
18864
20662
|
state.mcpEditingId = '';
|
|
18865
|
-
|
|
18866
|
-
|
|
20663
|
+
state.mcpDraft = null;
|
|
20664
|
+
if (mcpMutationUiActive(generation)) showUiNotice(t('plugins.mcpSaved'), 'success', 'mcp-save');
|
|
20665
|
+
}).catch(function(error) {
|
|
20666
|
+
if (mcpMutationUiActive(generation)) showUiNotice(error && error.message ? error.message : String(error), 'error', 'mcp-save');
|
|
20667
|
+
}).finally(function() {
|
|
20668
|
+
state.mcpMutationPending = false;
|
|
20669
|
+
if (mcpMutationUiActive(generation)) window.renderMcpManager();
|
|
20670
|
+
});
|
|
20671
|
+
};
|
|
20672
|
+
|
|
20673
|
+
window.toggleMcpServerAt = function(index, enabled) {
|
|
20674
|
+
if (!api.setMcpServerEnabled || state.mcpMutationPending) return;
|
|
20675
|
+
var server = (state.mcpServers || [])[index];
|
|
20676
|
+
if (!server) return;
|
|
20677
|
+
var generation = ++state.mcpMutationGeneration;
|
|
20678
|
+
state.mcpMutationPending = true;
|
|
20679
|
+
window.renderMcpManagerContent();
|
|
20680
|
+
Promise.resolve(api.setMcpServerEnabled(server.id, !!enabled)).then(function(result) {
|
|
20681
|
+
if (!result || result.ok !== true) throw new Error(result && result.error || t('plugins.mcpMutationFailed'));
|
|
20682
|
+
if (Array.isArray(result.servers)) state.mcpServers = result.servers;
|
|
20683
|
+
}).catch(function(error) {
|
|
20684
|
+
if (mcpMutationUiActive(generation)) showUiNotice(error && error.message ? error.message : String(error), 'error', 'mcp-toggle');
|
|
20685
|
+
}).finally(function() {
|
|
20686
|
+
state.mcpMutationPending = false;
|
|
20687
|
+
if (mcpMutationUiActive(generation)) window.renderMcpManager();
|
|
20688
|
+
});
|
|
20689
|
+
};
|
|
20690
|
+
|
|
20691
|
+
window.removeMcpServerAt = function(index) {
|
|
20692
|
+
if (!api.removeMcpServer || state.mcpMutationPending) return;
|
|
20693
|
+
var server = (state.mcpServers || [])[index];
|
|
20694
|
+
if (!server || !confirm(pluginText('plugins.mcpRemoveConfirm', { name: server.name || '' }))) return;
|
|
20695
|
+
var generation = ++state.mcpMutationGeneration;
|
|
20696
|
+
state.mcpMutationPending = true;
|
|
20697
|
+
window.renderMcpManagerContent();
|
|
20698
|
+
Promise.resolve(api.removeMcpServer(server.id)).then(function(result) {
|
|
20699
|
+
if (!result || result.ok !== true) throw new Error(result && result.error || t('plugins.mcpMutationFailed'));
|
|
20700
|
+
if (Array.isArray(result.servers)) state.mcpServers = result.servers;
|
|
20701
|
+
if (state.mcpEditingId === server.id) { state.mcpEditingId = ''; state.mcpDraft = null; }
|
|
20702
|
+
}).catch(function(error) {
|
|
20703
|
+
if (mcpMutationUiActive(generation)) showUiNotice(error && error.message ? error.message : String(error), 'error', 'mcp-remove');
|
|
20704
|
+
}).finally(function() {
|
|
20705
|
+
state.mcpMutationPending = false;
|
|
20706
|
+
if (mcpMutationUiActive(generation)) window.renderMcpManager();
|
|
20707
|
+
});
|
|
18867
20708
|
};
|
|
18868
|
-
window.toggleMcpServer = function(id, enabled) { if (api.setMcpServerEnabled) api.setMcpServerEnabled(id, enabled).then(window.renderMcpManager); };
|
|
18869
|
-
window.removeMcpServerFromUi = function(id) { if (api.removeMcpServer) api.removeMcpServer(id).then(window.renderMcpManager); };
|
|
18870
20709
|
|
|
18871
20710
|
window.filteredSkillMarket = function() {
|
|
18872
20711
|
var market = state._skillMarketAll || [];
|
|
@@ -18887,7 +20726,7 @@ window.filteredSkillMarket = function() {
|
|
|
18887
20726
|
|
|
18888
20727
|
window.renderSkillsMarketList = function() {
|
|
18889
20728
|
var panel = document.getElementById('plugin-panel');
|
|
18890
|
-
if (!panel) return;
|
|
20729
|
+
if (!panel || state.pluginActiveTab !== 'market' || !state.activeSubWindowView || state.activeSubWindowView.name !== 'plugins') return;
|
|
18891
20730
|
var market = window.filteredSkillMarket();
|
|
18892
20731
|
var total = (state._skillMarketAll || []).length;
|
|
18893
20732
|
var query = state.skillMarketQuery || '';
|
|
@@ -19156,13 +20995,14 @@ window.renderLeftWsList = function() {
|
|
|
19156
20995
|
var container = document.getElementById('left-ws-list');
|
|
19157
20996
|
if (!container) return;
|
|
19158
20997
|
var workspaces = state.workspaces || [];
|
|
20998
|
+
var hasActiveWorkspace = workspaces.some(function(item) { return workspaceIdentity(item) === String(state.currentWorkspaceId || ''); });
|
|
19159
20999
|
var html = '';
|
|
19160
21000
|
for (var i = 0; i < workspaces.length; i++) {
|
|
19161
21001
|
var ws = workspaces[i];
|
|
19162
21002
|
var identity = workspaceIdentity(ws);
|
|
19163
21003
|
var active = identity === String(state.currentWorkspaceId || '');
|
|
19164
21004
|
var runtimeStatus = workspaceRuntimeStatus(ws);
|
|
19165
|
-
html += '<div class="left-ws-item' + (active ? ' active' : '') + '" onclick="window.switchToWorkspace(\'' + escAttr(identity) + '\')">' +
|
|
21005
|
+
html += '<div class="left-ws-item' + (active ? ' active' : '') + '" role="listitem" tabindex="' + (active || (!hasActiveWorkspace && i === 0) ? '0' : '-1') + '" aria-current="' + (active ? 'true' : 'false') + '" onclick="window.switchToWorkspace(\'' + escAttr(identity) + '\')" onkeydown="window.handleWorkspaceKey(event)">' +
|
|
19166
21006
|
'<span class="ws-icon">' + esc((ws.name || '?')[0].toUpperCase()) + '</span>' +
|
|
19167
21007
|
'<span class="ws-label">' + esc(ws.name || t('workspace.untitled')) + '</span>' +
|
|
19168
21008
|
(runtimeStatus ? '<span class="ws-runtime-dot ' + escAttr(runtimeStatus) + '" title="' + escAttr(runtimeStatus) + '"></span>' : '') +
|
|
@@ -19175,6 +21015,24 @@ window.renderLeftWsList = function() {
|
|
|
19175
21015
|
appendDomNodesInBatches(container, Array.from(holder.children), 'workspace-list', 24);
|
|
19176
21016
|
};
|
|
19177
21017
|
|
|
21018
|
+
window.handleWorkspaceKey = function(event) {
|
|
21019
|
+
if (!event || event.defaultPrevented || event.isComposing || event.key === 'Process' || event.keyCode === 229 || event.target !== event.currentTarget) return false;
|
|
21020
|
+
if (event.key === 'Enter' || event.key === ' ') return window.activateButtonLike(event);
|
|
21021
|
+
var items = Array.prototype.slice.call(document.querySelectorAll('#left-ws-list .left-ws-item'));
|
|
21022
|
+
var index = items.indexOf(event.currentTarget);
|
|
21023
|
+
if (index < 0 || !items.length) return false;
|
|
21024
|
+
var next = index;
|
|
21025
|
+
if (event.key === 'ArrowDown' || event.key === 'ArrowRight') next = (index + 1) % items.length;
|
|
21026
|
+
else if (event.key === 'ArrowUp' || event.key === 'ArrowLeft') next = (index - 1 + items.length) % items.length;
|
|
21027
|
+
else if (event.key === 'Home') next = 0;
|
|
21028
|
+
else if (event.key === 'End') next = items.length - 1;
|
|
21029
|
+
else return false;
|
|
21030
|
+
event.preventDefault();
|
|
21031
|
+
items[next].focus({ preventScroll:true });
|
|
21032
|
+
items[next].click();
|
|
21033
|
+
return true;
|
|
21034
|
+
};
|
|
21035
|
+
|
|
19178
21036
|
window.toggleWorkspacePinned = function(identity) {
|
|
19179
21037
|
if (!identity || !api.setWorkspacePinned) return;
|
|
19180
21038
|
var nextPinned = false;
|
|
@@ -19279,7 +21137,7 @@ window.showNewWorkspaceDialog = function() {
|
|
|
19279
21137
|
'<label style="display:flex;align-items:center;gap:4px;font-size:12px;cursor:pointer;"><input type="radio" name="ws-type" value="ssh" onchange="window.toggleWsType()"> ' + esc(t('workspace.ssh')) + '</label>' +
|
|
19280
21138
|
'</div>' +
|
|
19281
21139
|
'<label id="ws-name-label-dlg" style="display:block;font-size:12px;color:var(--text-dim);margin-bottom:8px;">' + esc(t('workspace.name')) + '</label>' +
|
|
19282
|
-
'<input id="new-ws-input" style="width:100%;padding:8px 10px;border:1px solid var(--glass-border-2);border-radius:var(--radius-sm);background:var(--glass-bg-1);color:var(--text);font-size:13px;outline:none;box-sizing:border-box;" placeholder="' + escAttr(t('workspace.enterName')) + '" onkeydown="if(event.key===\'Enter\')window.doCreateWorkspace()">' +
|
|
21140
|
+
'<input id="new-ws-input" style="width:100%;padding:8px 10px;border:1px solid var(--glass-border-2);border-radius:var(--radius-sm);background:var(--glass-bg-1);color:var(--text);font-size:13px;outline:none;box-sizing:border-box;" placeholder="' + escAttr(t('workspace.enterName')) + '" onkeydown="if(event.key===\'Enter\'&&!event.isComposing&&event.key!==\'Process\'&&event.keyCode!==229)window.doCreateWorkspace()">' +
|
|
19283
21141
|
'<div id="ws-ext-path" style="display:none;margin-top:8px;">' +
|
|
19284
21142
|
'<label style="display:block;font-size:12px;color:var(--text-dim);margin-bottom:6px;">' + esc(t('workspace.folderPath')) + '</label>' +
|
|
19285
21143
|
'<div style="display:flex;gap:6px;">' +
|
|
@@ -19535,7 +21393,7 @@ window.openWorkspaceManager = async function() {
|
|
|
19535
21393
|
var ws = workspaces[i];
|
|
19536
21394
|
var identity = workspaceIdentity(ws);
|
|
19537
21395
|
var isActive = identity === String(state.currentWorkspaceId || '');
|
|
19538
|
-
listHtml += '<div style="display:flex;align-items:center;gap:8px;padding:8px 10px;margin:2px 0;border-radius:var(--radius-sm);background:' + (isActive ? 'var(--accent-glow)' : 'var(--glass-bg-1)') + ';cursor:pointer;" onclick="window.switchToWorkspace(\'' + escAttr(identity) + '\')">' +
|
|
21396
|
+
listHtml += '<div role="button" tabindex="0" style="display:flex;align-items:center;gap:8px;padding:8px 10px;margin:2px 0;border-radius:var(--radius-sm);background:' + (isActive ? 'var(--accent-glow)' : 'var(--glass-bg-1)') + ';cursor:pointer;" onclick="window.switchToWorkspace(\'' + escAttr(identity) + '\')" onkeydown="window.activateButtonLike(event)">' +
|
|
19539
21397
|
'<span style="width:24px;height:24px;border-radius:var(--radius-sm);background:linear-gradient(135deg,var(--accent),#7b93ff);color:#fff;font-size:11px;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0;">' + esc((ws.name || '?')[0].toUpperCase()) + '</span>' +
|
|
19540
21398
|
'<span style="flex:1;font-size:12px;color:var(--text);">' + esc(ws.name || t('workspace.untitled')) + '</span>' +
|
|
19541
21399
|
(isActive ? '<span style="font-size:10px;color:var(--accent2);">' + esc(t('workspace.current')) + '</span>' : '') +
|
|
@@ -19660,18 +21518,26 @@ window.saveWsSetting = function(key, value) {
|
|
|
19660
21518
|
window.renderFlowSelector = function() {
|
|
19661
21519
|
var flowSel = document.getElementById('flow-select');
|
|
19662
21520
|
if (!flowSel) return;
|
|
21521
|
+
var flows = Array.isArray(state.flowWorks) ? state.flowWorks : [];
|
|
19663
21522
|
var defaultFlow = state.defaultFlow || '';
|
|
21523
|
+
if (flows.length === 0) {
|
|
21524
|
+
state.defaultFlow = '';
|
|
21525
|
+
flowSel.disabled = true;
|
|
21526
|
+
flowSel.innerHTML = '<option value="">' + esc(t('flow.noAvailable')) + '</option>';
|
|
21527
|
+
if (window.syncNewmarkSelect) window.syncNewmarkSelect(flowSel);
|
|
21528
|
+
return;
|
|
21529
|
+
}
|
|
21530
|
+
flowSel.disabled = false;
|
|
19664
21531
|
var html = '';
|
|
19665
|
-
for (var fi = 0; fi <
|
|
19666
|
-
var selected =
|
|
19667
|
-
html += '<option value="' + esc(
|
|
21532
|
+
for (var fi = 0; fi < flows.length; fi++) {
|
|
21533
|
+
var selected = flows[fi].name === defaultFlow ? ' selected' : '';
|
|
21534
|
+
html += '<option value="' + esc(flows[fi].name) + '"' + selected + '>' + esc(flows[fi].name) + '</option>';
|
|
19668
21535
|
}
|
|
19669
21536
|
flowSel.innerHTML = html;
|
|
19670
|
-
if (
|
|
19671
|
-
|
|
19672
|
-
state.defaultFlow = flowSel.value;
|
|
19673
|
-
}
|
|
21537
|
+
if (defaultFlow) flowSel.value = defaultFlow;
|
|
21538
|
+
state.defaultFlow = flowSel.value;
|
|
19674
21539
|
flowSel.onchange = function() { state.defaultFlow = this.value; api.saveConfig({defaultFlow: state.defaultFlow}); };
|
|
21540
|
+
if (window.syncNewmarkSelect) window.syncNewmarkSelect(flowSel);
|
|
19675
21541
|
};
|
|
19676
21542
|
|
|
19677
21543
|
window.loadFlows = function(options) {
|
|
@@ -19764,6 +21630,549 @@ function stopMarqueeJS() {
|
|
|
19764
21630
|
if (marqueeRAF) { cancelAnimationFrame(marqueeRAF); marqueeRAF = null; }
|
|
19765
21631
|
}
|
|
19766
21632
|
|
|
21633
|
+
// === Unified GUI Command Registry & Keyboard Routing ===
|
|
21634
|
+
function guiCommand(id, titleKey, category, options) {
|
|
21635
|
+
return Object.assign({ id: id, titleKey: titleKey, category: category, bindings: [], scope: 'palette', keywords: [] }, options || {});
|
|
21636
|
+
}
|
|
21637
|
+
|
|
21638
|
+
function guiIsMac() {
|
|
21639
|
+
return String(state.platform || navigator.platform || '').toLowerCase().indexOf('mac') >= 0;
|
|
21640
|
+
}
|
|
21641
|
+
|
|
21642
|
+
function guiBindingRecord(command, input) {
|
|
21643
|
+
return typeof input === 'string'
|
|
21644
|
+
? { keys: input, scope: command.scope || 'palette' }
|
|
21645
|
+
: { keys: String((input && input.keys) || ''), scope: String((input && input.scope) || command.scope || 'palette') };
|
|
21646
|
+
}
|
|
21647
|
+
|
|
21648
|
+
function guiDisplayBinding(binding) {
|
|
21649
|
+
var keys = typeof binding === 'string' ? binding : String((binding && binding.keys) || '');
|
|
21650
|
+
return keys.replace(/\bMod\b/g, guiIsMac() ? 'Cmd' : 'Ctrl').replace(/ /g, ' then ');
|
|
21651
|
+
}
|
|
21652
|
+
|
|
21653
|
+
function guiSetSelectValue(id, value) {
|
|
21654
|
+
var select = document.getElementById(id);
|
|
21655
|
+
if (!select) return false;
|
|
21656
|
+
select.value = value;
|
|
21657
|
+
select.dispatchEvent(new Event('change', { bubbles: true }));
|
|
21658
|
+
return true;
|
|
21659
|
+
}
|
|
21660
|
+
|
|
21661
|
+
function guiSubWindowOpen() {
|
|
21662
|
+
return !!(els['sub-win-overlay'] && els['sub-win-overlay'].classList.contains('open'));
|
|
21663
|
+
}
|
|
21664
|
+
|
|
21665
|
+
function guiFocusPrompt() {
|
|
21666
|
+
if (guiSubWindowOpen()) return false;
|
|
21667
|
+
if (els.prompt) {
|
|
21668
|
+
els.prompt.focus({ preventScroll: true });
|
|
21669
|
+
return true;
|
|
21670
|
+
}
|
|
21671
|
+
return false;
|
|
21672
|
+
}
|
|
21673
|
+
|
|
21674
|
+
function guiFocusTerminal() {
|
|
21675
|
+
if (guiSubWindowOpen()) return false;
|
|
21676
|
+
if (state.bottomCollapsed) window.toggleBottom();
|
|
21677
|
+
var input = document.querySelector('#terminal-body .terminal-pane.active .terminal-input') || document.querySelector('#terminal-body .terminal-input');
|
|
21678
|
+
if (input) {
|
|
21679
|
+
input.focus({ preventScroll: true });
|
|
21680
|
+
return true;
|
|
21681
|
+
}
|
|
21682
|
+
return false;
|
|
21683
|
+
}
|
|
21684
|
+
|
|
21685
|
+
function guiFocusBrowserAddress() {
|
|
21686
|
+
if (guiSubWindowOpen()) return false;
|
|
21687
|
+
window.switchRightTab('browser');
|
|
21688
|
+
requestAnimationFrame(function() {
|
|
21689
|
+
var input = document.getElementById('browser-url');
|
|
21690
|
+
if (input) { input.focus({ preventScroll: true }); input.select(); }
|
|
21691
|
+
});
|
|
21692
|
+
return true;
|
|
21693
|
+
}
|
|
21694
|
+
|
|
21695
|
+
function guiCycleConversation(direction) {
|
|
21696
|
+
var conversations = currentWorkspaceConversations ? currentWorkspaceConversations() : [];
|
|
21697
|
+
if (!conversations.length) return false;
|
|
21698
|
+
var current = Math.max(0, Math.min(conversations.length - 1, Number(state.activeConversation) || 0));
|
|
21699
|
+
var next = (current + direction + conversations.length) % conversations.length;
|
|
21700
|
+
window.switchConversation(next);
|
|
21701
|
+
return true;
|
|
21702
|
+
}
|
|
21703
|
+
|
|
21704
|
+
function guiHasSwitchableBranch() {
|
|
21705
|
+
var groups = state.conversationBranchGroups || [];
|
|
21706
|
+
var branches = state.conversationBranches || [];
|
|
21707
|
+
if (groups.length) return groups.some(function(group) { return (group.branches || []).length > 1; });
|
|
21708
|
+
return branches.length > 1;
|
|
21709
|
+
}
|
|
21710
|
+
|
|
21711
|
+
function guiToggleTheme() {
|
|
21712
|
+
var current = state.theme === 'light' ? 'light' : 'dark';
|
|
21713
|
+
window.setTheme(current === 'light' ? 'dark' : 'light');
|
|
21714
|
+
}
|
|
21715
|
+
|
|
21716
|
+
var NEWMARK_GUI_COMMANDS = [
|
|
21717
|
+
guiCommand('app.commandPalette', 'shortcuts.openPalette', 'general', { bindings: [{ keys:'Mod+Shift+P', scope:'global' }], run:function(){ window.openCommandSurface('palette'); } }),
|
|
21718
|
+
guiCommand('help.keyboardShortcuts', 'shortcuts.openHelp', 'general', { bindings: [{ keys:'F1', scope:'global' }], run:function(){ window.openCommandSurface('help'); } }),
|
|
21719
|
+
guiCommand('settings.open', 'settings.title', 'general', { bindings: [{ keys:'Mod+,', scope:'global' }, { keys:'Mod+K S', scope:'whenNotEditing' }], run:function(){ window.openSettings(); } }),
|
|
21720
|
+
guiCommand('window.minimize', 'top.minimize', 'general', { run:function(){ api.minimize(); } }),
|
|
21721
|
+
guiCommand('window.maximize', 'top.maximize', 'general', { run:function(){ api.maximize(); } }),
|
|
21722
|
+
guiCommand('view.toggleTheme', 'shortcuts.toggleTheme', 'general', { bindings:[{ keys:'Mod+K Q', scope:'whenNotEditing' }], run:guiToggleTheme }),
|
|
21723
|
+
|
|
21724
|
+
guiCommand('conversation.new', 'left.newChat', 'workspace', { bindings:[{ keys:'Mod+K N', scope:'whenNotEditing' }], run:function(){ if (state.currentWorkspaceId) window.newConversation(); else window.showNewConversationPage(); } }),
|
|
21725
|
+
guiCommand('conversation.next', 'shortcuts.nextConversation', 'workspace', { bindings:[{ keys:'Mod+Shift+ArrowRight', scope:'whenNotEditing' }], run:function(){ guiCycleConversation(1); }, available:function(){ return currentWorkspaceConversations().length > 1; } }),
|
|
21726
|
+
guiCommand('conversation.previous', 'shortcuts.previousConversation', 'workspace', { bindings:[{ keys:'Mod+Shift+ArrowLeft', scope:'whenNotEditing' }], run:function(){ guiCycleConversation(-1); }, available:function(){ return currentWorkspaceConversations().length > 1; } }),
|
|
21727
|
+
guiCommand('conversation.archive', 'archive.current', 'workspace', { run:function(){ window.archiveCurrent(); }, available:function(){ return !!state.currentWorkspaceId; } }),
|
|
21728
|
+
guiCommand('branch.previous', 'shortcuts.previousBranch', 'workspace', { bindings:[{ keys:'Alt+ArrowUp', scope:'whenNotEditing' }], run:function(){ window.switchConversationBranch(-1); }, available:function(){ return guiHasSwitchableBranch(); } }),
|
|
21729
|
+
guiCommand('branch.next', 'shortcuts.nextBranch', 'workspace', { bindings:[{ keys:'Alt+ArrowDown', scope:'whenNotEditing' }], run:function(){ window.switchConversationBranch(1); }, available:function(){ return guiHasSwitchableBranch(); } }),
|
|
21730
|
+
guiCommand('workspace.manager', 'workspace.manager', 'workspace', { bindings:[{ keys:'Mod+K W', scope:'whenNotEditing' }], run:function(){ window.openWorkspaceManager(); } }),
|
|
21731
|
+
guiCommand('workspace.new', 'workspace.new', 'workspace', { run:function(){ window.showNewWorkspaceDialog(); } }),
|
|
21732
|
+
guiCommand('workspace.settings', 'workspace.settingsTitle', 'workspace', { run:function(){ window.openWsSettings(); }, available:function(){ return !!state.currentWorkspaceId; } }),
|
|
21733
|
+
|
|
21734
|
+
guiCommand('view.plugins', 'plugins.title', 'navigation', { bindings:[{ keys:'Mod+K P', scope:'whenNotEditing' }], run:function(){ window.showPluginList(); } }),
|
|
21735
|
+
guiCommand('view.plugins.mcp', 'plugins.mcp', 'navigation', { run:function(){ window.showPluginList('mcp'); } }),
|
|
21736
|
+
guiCommand('view.plugins.dsh', 'plugins.dsh', 'navigation', { bindings:[{ keys:'Mod+K D', scope:'whenNotEditing' }], run:function(){ window.showPluginList('dsh'); } }),
|
|
21737
|
+
guiCommand('view.plugins.skills', 'plugins.management', 'navigation', { run:function(){ window.showPluginList('installed'); } }),
|
|
21738
|
+
guiCommand('view.plugins.market', 'plugins.market', 'navigation', { run:function(){ window.showPluginList('market'); } }),
|
|
21739
|
+
guiCommand('view.plugins.github', 'plugins.github', 'navigation', { run:function(){ window.showPluginList('github'); } }),
|
|
21740
|
+
guiCommand('view.memoryLab', 'memoryLab.title', 'navigation', { bindings:[{ keys:'Mod+K M', scope:'whenNotEditing' }], run:function(){ window.showMemoryLab(); } }),
|
|
21741
|
+
guiCommand('view.automation', 'automation.title', 'navigation', { bindings:[{ keys:'Mod+K A', scope:'whenNotEditing' }], run:function(){ window.showAutomationWindow(); } }),
|
|
21742
|
+
guiCommand('automation.new', 'automation.new', 'navigation', { run:function(){ window.showNewAutomationForm(); } }),
|
|
21743
|
+
guiCommand('view.flowEditor', 'flow.title', 'navigation', { bindings:[{ keys:'Mod+K F', scope:'whenNotEditing' }], run:function(){ window.showFlowEditor(); } }),
|
|
21744
|
+
guiCommand('flow.new', 'flow.new', 'navigation', { run:function(){ window.newFlowWork(); } }),
|
|
21745
|
+
|
|
21746
|
+
guiCommand('focus.primaryInput', 'shortcuts.focusPrimary', 'layout', { bindings:[{ keys:'Mod+K C', scope:'whenNotEditing' }], run:guiFocusPrompt, available:function(){ return !guiSubWindowOpen(); } }),
|
|
21747
|
+
guiCommand('focus.nextRegion', 'shortcuts.focusNext', 'layout', { bindings:[{ keys:'F6', scope:'global' }], run:function(){ window.cycleGuiRegionFocus(1); }, available:function(){ return !guiSubWindowOpen() && !window.commandSurfaceIsOpen(); } }),
|
|
21748
|
+
guiCommand('focus.previousRegion', 'shortcuts.focusPrevious', 'layout', { bindings:[{ keys:'Shift+F6', scope:'global' }], run:function(){ window.cycleGuiRegionFocus(-1); }, available:function(){ return !guiSubWindowOpen() && !window.commandSurfaceIsOpen(); } }),
|
|
21749
|
+
guiCommand('view.toggleLeft', 'shortcuts.toggleLeft', 'layout', { bindings:[{ keys:'Mod+B', scope:'whenNotEditing' }], run:function(){ window.toggleLeft(); } }),
|
|
21750
|
+
guiCommand('view.toggleWorkspacePanel', 'shortcuts.toggleWorkspacePanel', 'layout', { run:function(){ window.toggleSecondarySidebar(); } }),
|
|
21751
|
+
guiCommand('view.toggleRight', 'shortcuts.toggleRight', 'layout', { run:function(){ window.toggleRight(); } }),
|
|
21752
|
+
guiCommand('view.toggleTerminal', 'shortcuts.toggleTerminal', 'layout', { bindings:[{ keys:'Mod+`', scope:'whenNotEditing' }], run:function(){ window.toggleBottom(); } }),
|
|
21753
|
+
guiCommand('chat.scrollBottom', 'shortcuts.scrollBottom', 'layout', { bindings:[{ keys:'Mod+End', scope:'whenNotEditing' }], run:function(){ window.scrollToBottom(); } }),
|
|
21754
|
+
|
|
21755
|
+
guiCommand('right.files', 'right.files', 'navigation', { bindings:[{ keys:'Mod+K 1', scope:'whenNotEditing' }], run:function(){ window.switchRightTab('file-tree'); } }),
|
|
21756
|
+
guiCommand('right.editor', 'right.editor', 'navigation', { bindings:[{ keys:'Mod+K 2', scope:'whenNotEditing' }], run:function(){ window.switchRightTab('editor'); } }),
|
|
21757
|
+
guiCommand('right.plan', 'right.plan', 'navigation', { bindings:[{ keys:'Mod+K 3', scope:'whenNotEditing' }], run:function(){ window.switchRightTab('plan'); } }),
|
|
21758
|
+
guiCommand('right.subagents', 'right.subagents', 'navigation', { run:function(){ window.switchRightTab('subagent'); } }),
|
|
21759
|
+
guiCommand('right.browser', 'right.browser', 'navigation', { bindings:[{ keys:'Mod+K 4', scope:'whenNotEditing' }], run:function(){ window.switchRightTab('browser'); } }),
|
|
21760
|
+
guiCommand('right.status', 'right.status', 'navigation', { run:function(){ window.switchRightTab('status'); } }),
|
|
21761
|
+
guiCommand('right.archives', 'right.archives', 'navigation', { run:function(){ window.switchRightTab('archives'); } }),
|
|
21762
|
+
|
|
21763
|
+
guiCommand('mode.build', 'mode.build', 'input', { bindings:[{ keys:'Mod+1', scope:'whenNotEditing' }], run:function(){ guiSetSelectValue('mode-select','build'); } }),
|
|
21764
|
+
guiCommand('mode.plan', 'mode.plan', 'input', { bindings:[{ keys:'Mod+2', scope:'whenNotEditing' }], run:function(){ guiSetSelectValue('mode-select','plan'); } }),
|
|
21765
|
+
guiCommand('mode.goal', 'mode.goal', 'input', { bindings:[{ keys:'Mod+3', scope:'whenNotEditing' }], run:function(){ guiSetSelectValue('mode-select','goal'); } }),
|
|
21766
|
+
guiCommand('mode.flow', 'mode.flow', 'input', { bindings:[{ keys:'Mod+4', scope:'whenNotEditing' }], run:function(){ guiSetSelectValue('mode-select','flow'); } }),
|
|
21767
|
+
guiCommand('input.guide', 'input.guide', 'input', { bindings:[{ keys:'Mod+K G', scope:'whenNotEditing' }], run:function(){ window.setInputMode('guide'); } }),
|
|
21768
|
+
guiCommand('input.next', 'input.next', 'input', { bindings:[{ keys:'Mod+K E', scope:'whenNotEditing' }], run:function(){ window.setInputMode('next'); } }),
|
|
21769
|
+
guiCommand('goal.edit', 'goal.edit', 'input', { run:function(){ window.editGoal(); } }),
|
|
21770
|
+
guiCommand('goal.pauseResume', 'goal.pause', 'input', { bindings:[{ keys:'Mod+K Shift+G', scope:'whenNotEditing' }], run:function(){ window.toggleGoalPause(); }, available:function(){ return !!state.goalVisible; } }),
|
|
21771
|
+
|
|
21772
|
+
guiCommand('editor.save', 'common.save', 'editor', { bindings:[{ keys:'Mod+S', scope:'editor' }], run:function(){ window.saveEditor(); }, available:function(){ return !!state.editorPath; } }),
|
|
21773
|
+
guiCommand('editor.close', 'common.close', 'editor', { run:function(){ window.closeEditor(); }, available:function(){ return !!state.editorPath; } }),
|
|
21774
|
+
guiCommand('editor.markdownPreview', 'right.md', 'editor', { run:function(){ window.toggleEditorMarkdownPreview(); }, available:function(){ return !!state.editorPath; } }),
|
|
21775
|
+
guiCommand('editor.prediction', 'model.thinking', 'editor', { run:function(){ window.toggleEditorPrediction(); }, available:function(){ return !!state.editorPath; } }),
|
|
21776
|
+
guiCommand('editor.completion', 'model.validationCurrent', 'editor', { run:function(){ window.requestEditorCompletion({ force:true }); }, available:function(){ return !!state.editorPath; } }),
|
|
21777
|
+
|
|
21778
|
+
guiCommand('terminal.focus', 'shortcuts.focusTerminal', 'terminal', { bindings:[{ keys:'Mod+K T', scope:'whenNotEditing' }], run:guiFocusTerminal, available:function(){ return !guiSubWindowOpen(); } }),
|
|
21779
|
+
guiCommand('terminal.new', 'shortcuts.newTerminal', 'terminal', { run:function(){ window.addTerminalTab(); } }),
|
|
21780
|
+
guiCommand('terminal.clear', 'terminal.clear', 'terminal', { run:function(){ window.clearTerminal(); } }),
|
|
21781
|
+
|
|
21782
|
+
guiCommand('browser.focusAddress', 'shortcuts.focusBrowserAddress', 'browser', { bindings:[{ keys:'Mod+L', scope:'browser' }, { keys:'Mod+K B', scope:'whenNotEditing' }], run:guiFocusBrowserAddress, available:function(){ return !guiSubWindowOpen(); } }),
|
|
21783
|
+
guiCommand('browser.back', 'browser.back', 'browser', { bindings:[{ keys:'Alt+ArrowLeft', scope:'browser' }], run:function(){ window.browserBack(); } }),
|
|
21784
|
+
guiCommand('browser.forward', 'browser.forward', 'browser', { bindings:[{ keys:'Alt+ArrowRight', scope:'browser' }], run:function(){ window.browserForward(); } }),
|
|
21785
|
+
guiCommand('browser.reload', 'browser.reload', 'browser', { bindings:[{ keys:'Mod+R', scope:'browser' }, { keys:'F5', scope:'browser' }], run:function(){ window.browserReload(); } }),
|
|
21786
|
+
guiCommand('browser.computerUse', 'right.browser', 'browser', { run:function(){ window.toggleComputerUse(); } }),
|
|
21787
|
+
|
|
21788
|
+
guiCommand('settings.general', 'settings.general', 'context', { run:function(){ window.openSettings('general'); } }),
|
|
21789
|
+
guiCommand('settings.models', 'settings.models', 'context', { run:function(){ window.openSettings('models'); } }),
|
|
21790
|
+
guiCommand('settings.tools', 'settings.tools', 'context', { run:function(){ window.openSettings('tools'); } }),
|
|
21791
|
+
guiCommand('settings.archive', 'settings.archive', 'context', { run:function(){ window.openSettings('archive'); } }),
|
|
21792
|
+
guiCommand('settings.updates', 'settings.updates', 'context', { run:function(){ window.openSettings('updates'); } })
|
|
21793
|
+
];
|
|
21794
|
+
window.NEWMARK_GUI_COMMANDS = NEWMARK_GUI_COMMANDS;
|
|
21795
|
+
|
|
21796
|
+
window.activateButtonLike = function(event) {
|
|
21797
|
+
if (!event || event.defaultPrevented || event.isComposing || event.key === 'Process' || event.keyCode === 229) return false;
|
|
21798
|
+
if (event.key !== 'Enter' && event.key !== ' ') return false;
|
|
21799
|
+
if (event.target !== event.currentTarget) return false;
|
|
21800
|
+
event.preventDefault();
|
|
21801
|
+
event.currentTarget.click();
|
|
21802
|
+
return true;
|
|
21803
|
+
};
|
|
21804
|
+
|
|
21805
|
+
function guiCommandTitle(command) {
|
|
21806
|
+
return t(command.titleKey || command.id);
|
|
21807
|
+
}
|
|
21808
|
+
|
|
21809
|
+
function guiCommandCategory(command) {
|
|
21810
|
+
return t('shortcuts.category.' + (command.category || 'general'));
|
|
21811
|
+
}
|
|
21812
|
+
|
|
21813
|
+
function guiCommandAvailable(command) {
|
|
21814
|
+
try { return !command.available || command.available() !== false; }
|
|
21815
|
+
catch(e) { return false; }
|
|
21816
|
+
}
|
|
21817
|
+
|
|
21818
|
+
function guiKeyboardContext(event) {
|
|
21819
|
+
var target = event && event.target && event.target.nodeType === 1 ? event.target : document.activeElement;
|
|
21820
|
+
var closest = function(selector) { return target && target.closest ? target.closest(selector) : null; };
|
|
21821
|
+
var editable = !!(target && ((target.matches && target.matches('input, textarea, select, [role="textbox"], [role="combobox"]')) || target.isContentEditable || closest('[contenteditable]:not([contenteditable="false"])')));
|
|
21822
|
+
return {
|
|
21823
|
+
target: target,
|
|
21824
|
+
editable: editable,
|
|
21825
|
+
editor: !!closest('#native-editor, #panel-editor'),
|
|
21826
|
+
terminal: !!closest('#bottom, .terminal-pane'),
|
|
21827
|
+
browser: !!closest('#panel-browser, .browser-url-bar') || state.rightTab === 'browser' && !!closest('#right'),
|
|
21828
|
+
prompt: !!(els.prompt && (target === els.prompt || (els.prompt.contains && els.prompt.contains(target)))),
|
|
21829
|
+
dialog: !!closest('[role="dialog"]')
|
|
21830
|
+
};
|
|
21831
|
+
}
|
|
21832
|
+
|
|
21833
|
+
function guiBindingScopeMatches(scope, context) {
|
|
21834
|
+
if (scope === 'global') return true;
|
|
21835
|
+
if (scope === 'whenNotEditing') return !context.editable && !context.editor && !context.terminal && !context.browser && !context.dialog;
|
|
21836
|
+
if (scope === 'editor') return context.editor;
|
|
21837
|
+
if (scope === 'terminal') return context.terminal;
|
|
21838
|
+
if (scope === 'browser') return context.browser;
|
|
21839
|
+
if (scope === 'prompt') return context.prompt;
|
|
21840
|
+
if (scope === 'dialog') return context.dialog;
|
|
21841
|
+
return false;
|
|
21842
|
+
}
|
|
21843
|
+
|
|
21844
|
+
function guiEventSegment(event) {
|
|
21845
|
+
var key = String(event.key || '');
|
|
21846
|
+
if (!key || ['Control','Shift','Alt','Meta','AltGraph'].indexOf(key) >= 0) return '';
|
|
21847
|
+
var parts = [];
|
|
21848
|
+
var mac = guiIsMac();
|
|
21849
|
+
if ((mac && event.metaKey) || (!mac && event.ctrlKey)) parts.push('Mod');
|
|
21850
|
+
if ((mac && event.ctrlKey) || (!mac && event.metaKey)) parts.push(mac ? 'Ctrl' : 'Meta');
|
|
21851
|
+
if (event.altKey) parts.push('Alt');
|
|
21852
|
+
if (event.shiftKey) parts.push('Shift');
|
|
21853
|
+
var named = { ' ':'Space', 'Esc':'Escape', 'Left':'ArrowLeft', 'Right':'ArrowRight', 'Up':'ArrowUp', 'Down':'ArrowDown' };
|
|
21854
|
+
key = named[key] || key;
|
|
21855
|
+
if (key.length === 1 && /[a-z]/i.test(key)) key = key.toUpperCase();
|
|
21856
|
+
parts.push(key);
|
|
21857
|
+
return parts.join('+');
|
|
21858
|
+
}
|
|
21859
|
+
|
|
21860
|
+
var guiCommandSurfaceOriginFocus = null;
|
|
21861
|
+
var guiCommandSurfaceMode = 'palette';
|
|
21862
|
+
var guiCommandSurfaceMatches = [];
|
|
21863
|
+
var guiCommandSurfaceSelection = 0;
|
|
21864
|
+
var guiPendingChord = null;
|
|
21865
|
+
var guiPendingChordTimer = 0;
|
|
21866
|
+
|
|
21867
|
+
window.commandSurfaceIsOpen = function() {
|
|
21868
|
+
var overlay = document.getElementById('command-surface-overlay');
|
|
21869
|
+
return !!(overlay && overlay.classList.contains('open'));
|
|
21870
|
+
};
|
|
21871
|
+
|
|
21872
|
+
function guiClearChord() {
|
|
21873
|
+
guiPendingChord = null;
|
|
21874
|
+
if (guiPendingChordTimer) clearTimeout(guiPendingChordTimer);
|
|
21875
|
+
guiPendingChordTimer = 0;
|
|
21876
|
+
var hint = document.getElementById('shortcut-chord-hint');
|
|
21877
|
+
if (hint) hint.classList.remove('open');
|
|
21878
|
+
}
|
|
21879
|
+
|
|
21880
|
+
function guiShowChord(prefix, candidates) {
|
|
21881
|
+
guiClearChord();
|
|
21882
|
+
guiPendingChord = { prefix:prefix, candidates:candidates };
|
|
21883
|
+
var seconds = candidates.map(function(item){ return item.binding.keys.split(' ')[1]; }).filter(function(key,index,array){ return array.indexOf(key) === index; });
|
|
21884
|
+
var hint = document.getElementById('shortcut-chord-hint');
|
|
21885
|
+
if (hint) {
|
|
21886
|
+
hint.textContent = t('shortcuts.chordHint').replace('{prefix}', guiDisplayBinding(prefix)).replace('{keys}', seconds.join(' · '));
|
|
21887
|
+
hint.classList.add('open');
|
|
21888
|
+
}
|
|
21889
|
+
guiPendingChordTimer = setTimeout(guiClearChord, 1800);
|
|
21890
|
+
}
|
|
21891
|
+
|
|
21892
|
+
function guiNormalizeCommandSearchText(value) {
|
|
21893
|
+
return String(value || '')
|
|
21894
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
21895
|
+
.replace(/[._:/\\-]+/g, ' ')
|
|
21896
|
+
.replace(/\s+/g, ' ')
|
|
21897
|
+
.trim()
|
|
21898
|
+
.toLocaleLowerCase(uiLocale());
|
|
21899
|
+
}
|
|
21900
|
+
|
|
21901
|
+
function guiCommandSearchText(command) {
|
|
21902
|
+
var bindings = (command.bindings || []).map(guiDisplayBinding).join(' ');
|
|
21903
|
+
return guiNormalizeCommandSearchText([command.id, guiCommandTitle(command), guiCommandCategory(command), bindings].concat(command.keywords || []).join(' '));
|
|
21904
|
+
}
|
|
21905
|
+
|
|
21906
|
+
function guiCommandContextLabel(command) {
|
|
21907
|
+
var scopes = (command.bindings || []).map(function(binding){ return guiBindingRecord(command,binding).scope; });
|
|
21908
|
+
var scope = scopes[0] || command.scope || 'palette';
|
|
21909
|
+
if (scope === 'editor') return t('shortcuts.context.editor');
|
|
21910
|
+
if (scope === 'browser') return t('shortcuts.context.browser');
|
|
21911
|
+
if (scope === 'terminal') return t('shortcuts.context.terminal');
|
|
21912
|
+
if (scope === 'prompt') return t('shortcuts.context.prompt');
|
|
21913
|
+
if (scope === 'dialog') return t('shortcuts.context.dialog');
|
|
21914
|
+
return t('shortcuts.context.global');
|
|
21915
|
+
}
|
|
21916
|
+
|
|
21917
|
+
window.renderCommandSurface = function() {
|
|
21918
|
+
var list = document.getElementById('command-list');
|
|
21919
|
+
var search = document.getElementById('command-search');
|
|
21920
|
+
if (!list || !search) return;
|
|
21921
|
+
var query = guiNormalizeCommandSearchText(search.value);
|
|
21922
|
+
guiCommandSurfaceMatches = NEWMARK_GUI_COMMANDS.filter(function(command){ return !query || guiCommandSearchText(command).indexOf(query) >= 0; });
|
|
21923
|
+
if (guiCommandSurfaceSelection >= guiCommandSurfaceMatches.length) guiCommandSurfaceSelection = Math.max(0, guiCommandSurfaceMatches.length - 1);
|
|
21924
|
+
if (!guiCommandSurfaceMatches.length) {
|
|
21925
|
+
list.innerHTML = '<div class="command-empty">' + esc(t('shortcuts.noResults')) + '</div>';
|
|
21926
|
+
search.removeAttribute('aria-activedescendant');
|
|
21927
|
+
return;
|
|
21928
|
+
}
|
|
21929
|
+
var html = '';
|
|
21930
|
+
var priorCategory = '';
|
|
21931
|
+
for (var i = 0; i < guiCommandSurfaceMatches.length; i++) {
|
|
21932
|
+
var command = guiCommandSurfaceMatches[i];
|
|
21933
|
+
var category = guiCommandCategory(command);
|
|
21934
|
+
if (category !== priorCategory) {
|
|
21935
|
+
html += '<div class="command-category">' + esc(category) + '</div>';
|
|
21936
|
+
priorCategory = category;
|
|
21937
|
+
}
|
|
21938
|
+
var available = guiCommandAvailable(command);
|
|
21939
|
+
var keys = (command.bindings || []).map(function(binding){ return '<span class="command-key">' + esc(guiDisplayBinding(binding)) + '</span>'; }).join('');
|
|
21940
|
+
html += '<button type="button" class="command-option' + (i === guiCommandSurfaceSelection ? ' active' : '') + '" id="command-option-' + i + '" role="option" aria-selected="' + (i === guiCommandSurfaceSelection ? 'true' : 'false') + '" aria-disabled="' + (available ? 'false' : 'true') + '" tabindex="-1" onclick="window.executeCommandSurfaceIndex(' + i + ')">' +
|
|
21941
|
+
'<span><span class="command-option-title">' + esc(guiCommandTitle(command)) + '</span><span class="command-option-context">' + esc(guiCommandContextLabel(command)) + '</span></span>' +
|
|
21942
|
+
'<span class="command-shortcuts">' + keys + '</span></button>';
|
|
21943
|
+
}
|
|
21944
|
+
list.innerHTML = html;
|
|
21945
|
+
search.setAttribute('aria-activedescendant', 'command-option-' + guiCommandSurfaceSelection);
|
|
21946
|
+
var active = document.getElementById('command-option-' + guiCommandSurfaceSelection);
|
|
21947
|
+
if (active) active.scrollIntoView({ block:'nearest' });
|
|
21948
|
+
};
|
|
21949
|
+
|
|
21950
|
+
function guiMoveCommandSelection(delta, edge) {
|
|
21951
|
+
if (!guiCommandSurfaceMatches.length) return;
|
|
21952
|
+
if (edge === 'start') guiCommandSurfaceSelection = 0;
|
|
21953
|
+
else if (edge === 'end') guiCommandSurfaceSelection = guiCommandSurfaceMatches.length - 1;
|
|
21954
|
+
else guiCommandSurfaceSelection = (guiCommandSurfaceSelection + delta + guiCommandSurfaceMatches.length) % guiCommandSurfaceMatches.length;
|
|
21955
|
+
window.renderCommandSurface();
|
|
21956
|
+
}
|
|
21957
|
+
|
|
21958
|
+
window.openCommandSurface = function(mode) {
|
|
21959
|
+
var overlay = document.getElementById('command-surface-overlay');
|
|
21960
|
+
var search = document.getElementById('command-search');
|
|
21961
|
+
if (!overlay || !search) return;
|
|
21962
|
+
guiClearChord();
|
|
21963
|
+
if (!window.commandSurfaceIsOpen() && document.activeElement && typeof document.activeElement.focus === 'function') guiCommandSurfaceOriginFocus = document.activeElement;
|
|
21964
|
+
guiCommandSurfaceMode = mode === 'help' ? 'help' : 'palette';
|
|
21965
|
+
document.getElementById('command-surface-title').textContent = t(guiCommandSurfaceMode === 'help' ? 'shortcuts.helpTitle' : 'shortcuts.paletteTitle');
|
|
21966
|
+
document.getElementById('command-surface-subtitle').textContent = t(guiCommandSurfaceMode === 'help' ? 'shortcuts.helpSubtitle' : 'shortcuts.paletteSubtitle');
|
|
21967
|
+
document.getElementById('command-surface-footer').textContent = t('shortcuts.footer');
|
|
21968
|
+
search.setAttribute('placeholder', t(guiCommandSurfaceMode === 'help' ? 'shortcuts.searchShortcuts' : 'shortcuts.searchCommands'));
|
|
21969
|
+
search.value = '';
|
|
21970
|
+
guiCommandSurfaceSelection = 0;
|
|
21971
|
+
overlay.classList.add('open');
|
|
21972
|
+
updateApplicationInertState();
|
|
21973
|
+
window.renderCommandSurface();
|
|
21974
|
+
requestAnimationFrame(function(){ search.focus({ preventScroll:true }); });
|
|
21975
|
+
};
|
|
21976
|
+
|
|
21977
|
+
window.closeCommandSurface = function(options) {
|
|
21978
|
+
options = options || {};
|
|
21979
|
+
var overlay = document.getElementById('command-surface-overlay');
|
|
21980
|
+
if (!overlay || !overlay.classList.contains('open')) return;
|
|
21981
|
+
overlay.classList.remove('open');
|
|
21982
|
+
updateApplicationInertState();
|
|
21983
|
+
var restore = guiCommandSurfaceOriginFocus;
|
|
21984
|
+
guiCommandSurfaceOriginFocus = null;
|
|
21985
|
+
if (options.restoreFocus !== false) requestAnimationFrame(function(){ if (restore && restore.isConnected && typeof restore.focus === 'function') restore.focus({ preventScroll:true }); });
|
|
21986
|
+
return restore;
|
|
21987
|
+
};
|
|
21988
|
+
|
|
21989
|
+
window.executeGuiCommand = function(id, options) {
|
|
21990
|
+
var command = NEWMARK_GUI_COMMANDS.find(function(item){ return item.id === id; });
|
|
21991
|
+
if (!command || !guiCommandAvailable(command) || typeof command.run !== 'function') return false;
|
|
21992
|
+
try {
|
|
21993
|
+
var result = command.run(options || {});
|
|
21994
|
+
if (result && typeof result.catch === 'function') result.catch(function(error){ showUiNotice(error && error.message ? error.message : String(error), 'error', 'gui-command-' + id); });
|
|
21995
|
+
return true;
|
|
21996
|
+
} catch(error) {
|
|
21997
|
+
showUiNotice(error && error.message ? error.message : String(error), 'error', 'gui-command-' + id);
|
|
21998
|
+
return false;
|
|
21999
|
+
}
|
|
22000
|
+
};
|
|
22001
|
+
|
|
22002
|
+
window.executeCommandSurfaceIndex = function(index) {
|
|
22003
|
+
var command = guiCommandSurfaceMatches[index];
|
|
22004
|
+
if (!command || !guiCommandAvailable(command)) return false;
|
|
22005
|
+
var restore = window.closeCommandSurface({ restoreFocus:false });
|
|
22006
|
+
setTimeout(function(){
|
|
22007
|
+
window.executeGuiCommand(command.id, { source:'commandSurface' });
|
|
22008
|
+
requestAnimationFrame(function() {
|
|
22009
|
+
if (!guiSubWindowOpen() && !window.commandSurfaceIsOpen() && restore && restore.isConnected && typeof restore.focus === 'function') restore.focus({ preventScroll:true });
|
|
22010
|
+
});
|
|
22011
|
+
}, 0);
|
|
22012
|
+
return true;
|
|
22013
|
+
};
|
|
22014
|
+
|
|
22015
|
+
function guiVisible(element) {
|
|
22016
|
+
return !!(element && element.isConnected && element.getClientRects().length && !element.closest('[inert]'));
|
|
22017
|
+
}
|
|
22018
|
+
|
|
22019
|
+
function guiRegionTargets() {
|
|
22020
|
+
var activeTerminalInput = document.querySelector('#terminal-body .terminal-pane.active .terminal-input') || document.getElementById('bottom-toggle-btn');
|
|
22021
|
+
var activeRightTab = document.querySelector('#right-tabs .tab-btn[data-tab].active') || document.querySelector('#right-tabs .tab-btn[data-tab]');
|
|
22022
|
+
return [
|
|
22023
|
+
{ container:document.getElementById('left'), target:document.querySelector('#left-content .left-nav-icon') || document.querySelector('#left-thumb .lt-item') },
|
|
22024
|
+
{ container:document.getElementById('left-secondary'), target:document.querySelector('#left-secondary button, #conversation-list button, #conversation-list [tabindex="0"]') },
|
|
22025
|
+
{ container:document.getElementById('center'), target:els.prompt },
|
|
22026
|
+
{ container:document.getElementById('bottom'), target:activeTerminalInput },
|
|
22027
|
+
{ container:document.getElementById('right'), target:activeRightTab }
|
|
22028
|
+
].filter(function(region){ return guiVisible(region.container) && guiVisible(region.target); });
|
|
22029
|
+
}
|
|
22030
|
+
|
|
22031
|
+
window.cycleGuiRegionFocus = function(direction) {
|
|
22032
|
+
var regions = guiRegionTargets();
|
|
22033
|
+
if (!regions.length) return false;
|
|
22034
|
+
var active = document.activeElement;
|
|
22035
|
+
var current = regions.findIndex(function(region){ return region.container === active || region.container.contains(active); });
|
|
22036
|
+
var next = current < 0 ? (direction > 0 ? 0 : regions.length - 1) : (current + direction + regions.length) % regions.length;
|
|
22037
|
+
regions[next].target.focus({ preventScroll:true });
|
|
22038
|
+
return true;
|
|
22039
|
+
};
|
|
22040
|
+
|
|
22041
|
+
window.validateGuiCommandRegistry = function() {
|
|
22042
|
+
var errors = [];
|
|
22043
|
+
var ids = Object.create(null);
|
|
22044
|
+
var bindings = Object.create(null);
|
|
22045
|
+
for (var i = 0; i < NEWMARK_GUI_COMMANDS.length; i++) {
|
|
22046
|
+
var command = NEWMARK_GUI_COMMANDS[i];
|
|
22047
|
+
if (!command.id || ids[command.id]) errors.push('duplicate command id: ' + command.id);
|
|
22048
|
+
ids[command.id] = true;
|
|
22049
|
+
if (typeof command.run !== 'function') errors.push('missing command handler: ' + command.id);
|
|
22050
|
+
for (var j = 0; j < (command.bindings || []).length; j++) {
|
|
22051
|
+
var binding = guiBindingRecord(command, command.bindings[j]);
|
|
22052
|
+
if (!binding.keys) { errors.push('empty binding: ' + command.id); continue; }
|
|
22053
|
+
var identity = binding.scope + '::' + binding.keys;
|
|
22054
|
+
if (bindings[identity]) errors.push('binding conflict: ' + binding.keys + ' (' + binding.scope + ')');
|
|
22055
|
+
bindings[identity] = command.id;
|
|
22056
|
+
if (/\bMeta\b/.test(binding.keys) || /(?:^|\+)Mod\+Alt\+/.test(binding.keys)) errors.push('reserved modifier: ' + binding.keys);
|
|
22057
|
+
if (/^(Alt\+F4|Alt\+Tab|Mod\+Alt\+Delete|Mod\+Shift\+Escape)$/.test(binding.keys)) errors.push('reserved shortcut: ' + binding.keys);
|
|
22058
|
+
}
|
|
22059
|
+
}
|
|
22060
|
+
return errors;
|
|
22061
|
+
};
|
|
22062
|
+
|
|
22063
|
+
function guiManifestHash(value) {
|
|
22064
|
+
var input = String(value || '');
|
|
22065
|
+
var hash = 2166136261;
|
|
22066
|
+
for (var i = 0; i < input.length; i++) {
|
|
22067
|
+
hash ^= input.charCodeAt(i);
|
|
22068
|
+
hash = Math.imul(hash, 16777619);
|
|
22069
|
+
}
|
|
22070
|
+
return ('00000000' + (hash >>> 0).toString(16)).slice(-8);
|
|
22071
|
+
}
|
|
22072
|
+
|
|
22073
|
+
window.getGuiCommandManifest = function() {
|
|
22074
|
+
var commands = NEWMARK_GUI_COMMANDS.map(function(command) {
|
|
22075
|
+
return {
|
|
22076
|
+
id: command.id,
|
|
22077
|
+
category: command.category || 'general',
|
|
22078
|
+
bindings: (command.bindings || []).map(function(binding) {
|
|
22079
|
+
var record = guiBindingRecord(command, binding);
|
|
22080
|
+
return { keys: record.keys, scope: record.scope };
|
|
22081
|
+
})
|
|
22082
|
+
};
|
|
22083
|
+
});
|
|
22084
|
+
var serialized = JSON.stringify(commands);
|
|
22085
|
+
return {
|
|
22086
|
+
schemaVersion: 1,
|
|
22087
|
+
revision: 'fnv1a-' + guiManifestHash(serialized),
|
|
22088
|
+
commands: commands,
|
|
22089
|
+
errors: window.validateGuiCommandRegistry()
|
|
22090
|
+
};
|
|
22091
|
+
};
|
|
22092
|
+
|
|
22093
|
+
function guiHandleCommandKeydown(event) {
|
|
22094
|
+
if (!event || event.defaultPrevented || event.isComposing || event.key === 'Process' || event.keyCode === 229) return false;
|
|
22095
|
+
if (window.commandSurfaceIsOpen()) {
|
|
22096
|
+
if (event.key === 'Escape' && !event.repeat) { event.preventDefault(); event.stopPropagation(); window.closeCommandSurface(); return true; }
|
|
22097
|
+
if (event.key === 'Tab') return trapNewmarkDialogFocus(event, document.getElementById('command-surface'));
|
|
22098
|
+
return false;
|
|
22099
|
+
}
|
|
22100
|
+
if (event.repeat) return false;
|
|
22101
|
+
var segment = guiEventSegment(event);
|
|
22102
|
+
if (!segment) return false;
|
|
22103
|
+
if (guiPendingChord) {
|
|
22104
|
+
var match = guiPendingChord.candidates.find(function(item){ return item.binding.keys.split(' ')[1] === segment; });
|
|
22105
|
+
guiClearChord();
|
|
22106
|
+
event.preventDefault();
|
|
22107
|
+
event.stopPropagation();
|
|
22108
|
+
if (match) window.executeGuiCommand(match.command.id, { source:'shortcut' });
|
|
22109
|
+
return true;
|
|
22110
|
+
}
|
|
22111
|
+
var context = guiKeyboardContext(event);
|
|
22112
|
+
var direct = [];
|
|
22113
|
+
var chords = [];
|
|
22114
|
+
for (var i = 0; i < NEWMARK_GUI_COMMANDS.length; i++) {
|
|
22115
|
+
var command = NEWMARK_GUI_COMMANDS[i];
|
|
22116
|
+
if (!guiCommandAvailable(command)) continue;
|
|
22117
|
+
for (var j = 0; j < (command.bindings || []).length; j++) {
|
|
22118
|
+
var binding = guiBindingRecord(command, command.bindings[j]);
|
|
22119
|
+
if (!guiBindingScopeMatches(binding.scope, context)) continue;
|
|
22120
|
+
var pieces = binding.keys.split(' ');
|
|
22121
|
+
if (pieces[0] !== segment) continue;
|
|
22122
|
+
if (pieces.length === 1) direct.push({ command:command, binding:binding });
|
|
22123
|
+
else if (pieces.length === 2) chords.push({ command:command, binding:binding });
|
|
22124
|
+
}
|
|
22125
|
+
}
|
|
22126
|
+
if (direct.length) {
|
|
22127
|
+
event.preventDefault();
|
|
22128
|
+
event.stopPropagation();
|
|
22129
|
+
window.executeGuiCommand(direct[0].command.id, { source:'shortcut' });
|
|
22130
|
+
return true;
|
|
22131
|
+
}
|
|
22132
|
+
if (chords.length) {
|
|
22133
|
+
event.preventDefault();
|
|
22134
|
+
event.stopPropagation();
|
|
22135
|
+
guiShowChord(segment, chords);
|
|
22136
|
+
return true;
|
|
22137
|
+
}
|
|
22138
|
+
return false;
|
|
22139
|
+
}
|
|
22140
|
+
|
|
22141
|
+
function setupGuiKeyboard() {
|
|
22142
|
+
if (state._guiKeyboardReady) return;
|
|
22143
|
+
state._guiKeyboardReady = true;
|
|
22144
|
+
var errors = window.validateGuiCommandRegistry();
|
|
22145
|
+
if (errors.length) console.error('[Keyboard] command registry conflicts:', errors);
|
|
22146
|
+
var search = document.getElementById('command-search');
|
|
22147
|
+
if (search) {
|
|
22148
|
+
search.addEventListener('input', function(){ guiCommandSurfaceSelection = 0; window.renderCommandSurface(); });
|
|
22149
|
+
search.addEventListener('keydown', function(event){
|
|
22150
|
+
if (event.isComposing || event.key === 'Process' || event.keyCode === 229) return;
|
|
22151
|
+
if (event.key === 'ArrowDown') { event.preventDefault(); guiMoveCommandSelection(1); }
|
|
22152
|
+
else if (event.key === 'ArrowUp') { event.preventDefault(); guiMoveCommandSelection(-1); }
|
|
22153
|
+
else if (event.key === 'Home' && !event.ctrlKey && !event.metaKey) { event.preventDefault(); guiMoveCommandSelection(0,'start'); }
|
|
22154
|
+
else if (event.key === 'End' && !event.ctrlKey && !event.metaKey) { event.preventDefault(); guiMoveCommandSelection(0,'end'); }
|
|
22155
|
+
else if (event.key === 'Enter') { event.preventDefault(); window.executeCommandSurfaceIndex(guiCommandSurfaceSelection); }
|
|
22156
|
+
});
|
|
22157
|
+
}
|
|
22158
|
+
document.addEventListener('keydown', guiHandleCommandKeydown, true);
|
|
22159
|
+
if (api.onKeyboardCommand) api.onKeyboardCommand(function(payload){ if (payload && payload.id) window.executeGuiCommand(String(payload.id), { source:'browserGuest' }); });
|
|
22160
|
+
var attributes = [
|
|
22161
|
+
['#left-collapse-btn','view.toggleLeft'],
|
|
22162
|
+
['#bottom-toggle-btn','view.toggleTerminal'],
|
|
22163
|
+
['.sub-win-close','common.close']
|
|
22164
|
+
];
|
|
22165
|
+
for (var i = 0; i < attributes.length; i++) {
|
|
22166
|
+
var element = document.querySelector(attributes[i][0]);
|
|
22167
|
+
var command = NEWMARK_GUI_COMMANDS.find(function(item){ return item.id === attributes[i][1]; });
|
|
22168
|
+
if (!element || !command || !command.bindings.length) continue;
|
|
22169
|
+
var direct = guiBindingRecord(command,command.bindings[0]).keys;
|
|
22170
|
+
if (direct.indexOf(' ') < 0) element.setAttribute('aria-keyshortcuts', direct.replace(/\bMod\b/g, guiIsMac() ? 'Meta' : 'Control'));
|
|
22171
|
+
}
|
|
22172
|
+
var manifest = window.getGuiCommandManifest();
|
|
22173
|
+
document.documentElement.dataset.keyboardRegistry = manifest.errors.length ? 'invalid' : manifest.revision;
|
|
22174
|
+
}
|
|
22175
|
+
|
|
19767
22176
|
function schedulePostStartupUiRendering() {
|
|
19768
22177
|
if (state._postStartupUiRendering && state._postStartupUiRendering.cancel) state._postStartupUiRendering.cancel();
|
|
19769
22178
|
var tasks = [
|
|
@@ -19812,8 +22221,33 @@ function schedulePostStartupUiRendering() {
|
|
|
19812
22221
|
(function initResize() {
|
|
19813
22222
|
var handles = document.querySelectorAll('.resize-handle');
|
|
19814
22223
|
for (var i = 0; i < handles.length; i++) {
|
|
22224
|
+
var resizeTarget = handles[i].getAttribute('data-target');
|
|
22225
|
+
if (resizeTarget === 'left') { handles[i].setAttribute('aria-valuemin', '220'); handles[i].setAttribute('aria-valuemax', '460'); }
|
|
22226
|
+
if (resizeTarget === 'right') { handles[i].setAttribute('aria-valuemin', '340'); handles[i].setAttribute('aria-valuemax', '680'); }
|
|
22227
|
+
handles[i].addEventListener('keydown', function(e) {
|
|
22228
|
+
if (!e || e.defaultPrevented || e.isComposing || e.key === 'Process' || e.keyCode === 229 || e.ctrlKey || e.metaKey || e.altKey) return;
|
|
22229
|
+
var target = this.getAttribute('data-target');
|
|
22230
|
+
var side = this.getAttribute('data-side');
|
|
22231
|
+
var el = target === 'left' ? (els.left || document.getElementById('left')) : (target === 'right' ? (els.right || document.getElementById('right')) : null);
|
|
22232
|
+
if (!el || (target === 'left' && state.leftCollapsed) || (target === 'right' && state.rightCollapsed)) return;
|
|
22233
|
+
var min = target === 'left' ? 220 : 340;
|
|
22234
|
+
var max = target === 'left' ? 460 : 680;
|
|
22235
|
+
var size = el.offsetWidth;
|
|
22236
|
+
var delta = e.shiftKey ? 32 : 12;
|
|
22237
|
+
if (e.key === 'Home') size = min;
|
|
22238
|
+
else if (e.key === 'End') size = max;
|
|
22239
|
+
else if (e.key === 'ArrowLeft') size += side === 'left' ? delta : -delta;
|
|
22240
|
+
else if (e.key === 'ArrowRight') size += side === 'left' ? -delta : delta;
|
|
22241
|
+
else return;
|
|
22242
|
+
e.preventDefault();
|
|
22243
|
+
size = Math.max(min, Math.min(max, size));
|
|
22244
|
+
if (target === 'left') { setLeftWidthPx(size); state.leftWidth = size; }
|
|
22245
|
+
else window.setRightWidthPx(size);
|
|
22246
|
+
this.setAttribute('aria-valuenow', String(Math.round(size)));
|
|
22247
|
+
});
|
|
19815
22248
|
handles[i].addEventListener('mousedown', function(e) {
|
|
19816
22249
|
e.preventDefault();
|
|
22250
|
+
var handle = this;
|
|
19817
22251
|
var target = this.getAttribute('data-target');
|
|
19818
22252
|
var side = this.getAttribute('data-side');
|
|
19819
22253
|
var el = target === 'left' ? els.left : (target === 'right' ? els.right : null);
|
|
@@ -19833,10 +22267,12 @@ function schedulePostStartupUiRendering() {
|
|
|
19833
22267
|
var leftSize = Math.max(220, Math.min(460, newSize));
|
|
19834
22268
|
setLeftWidthPx(leftSize);
|
|
19835
22269
|
state.leftWidth = leftSize;
|
|
22270
|
+
handle.setAttribute('aria-valuenow', String(Math.round(leftSize)));
|
|
19836
22271
|
} else if (side === 'left') {
|
|
19837
22272
|
var newSize2 = startSize - dx;
|
|
19838
22273
|
var rightSize = Math.max(340, Math.min(680, newSize2));
|
|
19839
22274
|
window.setRightWidthPx(rightSize);
|
|
22275
|
+
handle.setAttribute('aria-valuenow', String(Math.round(rightSize)));
|
|
19840
22276
|
} else if (side === 'top') {
|
|
19841
22277
|
var newSize3 = startSize - dy;
|
|
19842
22278
|
el.style.height = Math.max(0, Math.min(400, newSize3)) + 'px';
|
|
@@ -19935,6 +22371,10 @@ function schedulePostStartupUiRendering() {
|
|
|
19935
22371
|
var startupHydrationError = null;
|
|
19936
22372
|
cacheEls();
|
|
19937
22373
|
setupAgentWorkEvents();
|
|
22374
|
+
if (api.onEditorCompletionDelta && !state._editorCompletionDeltaReady) {
|
|
22375
|
+
state._editorCompletionDeltaReady = true;
|
|
22376
|
+
api.onEditorCompletionDelta(function(payload) { window.applyEditorCompletionDelta(payload); });
|
|
22377
|
+
}
|
|
19938
22378
|
if (api.onBrowserEnsureGuest) {
|
|
19939
22379
|
api.onBrowserEnsureGuest(function(target) {
|
|
19940
22380
|
cancelBrowserGuestIdleDestroy();
|
|
@@ -20047,6 +22487,7 @@ function schedulePostStartupUiRendering() {
|
|
|
20047
22487
|
startupHydrationError = e;
|
|
20048
22488
|
}
|
|
20049
22489
|
applyUiAppearance();
|
|
22490
|
+
setupGuiKeyboard();
|
|
20050
22491
|
window.renderContextWindow();
|
|
20051
22492
|
if (api.onAutomationUpdated) {
|
|
20052
22493
|
api.onAutomationUpdated(function() {
|
|
@@ -20071,19 +22512,69 @@ function schedulePostStartupUiRendering() {
|
|
|
20071
22512
|
updateWorkspaceGate();
|
|
20072
22513
|
|
|
20073
22514
|
// === Event Listeners ===
|
|
22515
|
+
function escapeBelongsToFocusedControl(event) {
|
|
22516
|
+
var target = event && event.target;
|
|
22517
|
+
if (!target || target === document || target === document.body || target === document.documentElement) return false;
|
|
22518
|
+
if (els.prompt && (target === els.prompt || (els.prompt.contains && els.prompt.contains(target)))) return false;
|
|
22519
|
+
if (target.closest && target.closest('.modal.active, .sub-win.open, .newmark-select-shell.open')) return true;
|
|
22520
|
+
return !!(target.matches && target.matches('input, textarea, select, [contenteditable="true"]'));
|
|
22521
|
+
}
|
|
22522
|
+
if (api.onWorkspaceChanged) {
|
|
22523
|
+
var workspaceRefreshTimer = null;
|
|
22524
|
+
api.onWorkspaceChanged(function() {
|
|
22525
|
+
if (workspaceRefreshTimer) clearTimeout(workspaceRefreshTimer);
|
|
22526
|
+
workspaceRefreshTimer = setTimeout(function() {
|
|
22527
|
+
workspaceRefreshTimer = null;
|
|
22528
|
+
if (window.refreshWorkspaceState) window.refreshWorkspaceState().catch(function(){});
|
|
22529
|
+
if (document.getElementById('right-archive-list')) window.refreshRightArchives();
|
|
22530
|
+
}, 120);
|
|
22531
|
+
});
|
|
22532
|
+
}
|
|
22533
|
+
|
|
22534
|
+
function stopRunningFromEscape(event) {
|
|
22535
|
+
if (!event || event.key !== 'Escape' || event.defaultPrevented || escapeBelongsToFocusedControl(event)) return false;
|
|
22536
|
+
if (currentFlowRunning() && flowTakeoverMatchesCurrent()) {
|
|
22537
|
+
event.preventDefault();
|
|
22538
|
+
window.stopFlowRun();
|
|
22539
|
+
return true;
|
|
22540
|
+
}
|
|
22541
|
+
if (isCurrentConversationRunning()) {
|
|
22542
|
+
event.preventDefault();
|
|
22543
|
+
window.stopCurrentConversation();
|
|
22544
|
+
return true;
|
|
22545
|
+
}
|
|
22546
|
+
return false;
|
|
22547
|
+
}
|
|
22548
|
+
|
|
22549
|
+
// The prompt handler below covers the normal focused-input path. Keep a
|
|
22550
|
+
// document-level fallback so a physical Escape still stops a running target
|
|
22551
|
+
// after focus moved to the chat, title bar, button, or another non-editor
|
|
22552
|
+
// surface. Modal/editor/select Escape behavior remains owned by that UI.
|
|
22553
|
+
document.addEventListener('keydown', function(event) {
|
|
22554
|
+
if (!event || event.defaultPrevented || event.repeat || event.isComposing || event.key === 'Process' || event.keyCode === 229) return;
|
|
22555
|
+
if (event.key === 'Escape' && !event.defaultPrevented && els['sub-win-overlay'] && els['sub-win-overlay'].classList.contains('open')) {
|
|
22556
|
+
event.preventDefault();
|
|
22557
|
+
event.stopPropagation();
|
|
22558
|
+
window.closeSubWin();
|
|
22559
|
+
return;
|
|
22560
|
+
}
|
|
22561
|
+
if (stopRunningFromEscape(event)) event.stopPropagation();
|
|
22562
|
+
});
|
|
22563
|
+
|
|
20074
22564
|
if (els.prompt) {
|
|
20075
22565
|
els.prompt.addEventListener('keydown', function(e) {
|
|
20076
|
-
if (e.key === '
|
|
22566
|
+
if (e.isComposing || e.key === 'Process' || e.keyCode === 229) return;
|
|
22567
|
+
if (e.key === 'Escape' && currentFlowRunning() && flowTakeoverMatchesCurrent()) {
|
|
20077
22568
|
e.preventDefault();
|
|
20078
22569
|
window.stopFlowRun();
|
|
20079
22570
|
return;
|
|
20080
22571
|
}
|
|
20081
|
-
if (e.key === 'Escape' && isCurrentConversationRunning()
|
|
22572
|
+
if (e.key === 'Escape' && isCurrentConversationRunning()) {
|
|
20082
22573
|
e.preventDefault();
|
|
20083
22574
|
window.stopCurrentConversation();
|
|
20084
22575
|
return;
|
|
20085
22576
|
}
|
|
20086
|
-
if (e.key === 'Enter' && e.ctrlKey) {
|
|
22577
|
+
if (e.key === 'Enter' && (e.ctrlKey || e.metaKey) && !e.altKey && !e.shiftKey) {
|
|
20087
22578
|
e.preventDefault();
|
|
20088
22579
|
if (state.mode === 'flow' || (currentFlowRunning() && flowTakeoverMatchesCurrent())) {
|
|
20089
22580
|
window.submitCurrentAction();
|
|
@@ -20093,9 +22584,9 @@ function schedulePostStartupUiRendering() {
|
|
|
20093
22584
|
window.sendMessage(opposite);
|
|
20094
22585
|
return;
|
|
20095
22586
|
}
|
|
20096
|
-
if (e.key === 'Enter' && !e.shiftKey) {
|
|
22587
|
+
if (e.key === 'Enter' && !e.shiftKey && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
20097
22588
|
e.preventDefault();
|
|
20098
|
-
window.submitCurrentAction();
|
|
22589
|
+
window.submitCurrentAction('enter');
|
|
20099
22590
|
}
|
|
20100
22591
|
});
|
|
20101
22592
|
els.prompt.addEventListener('input', function() {
|
|
@@ -20190,10 +22681,10 @@ function schedulePostStartupUiRendering() {
|
|
|
20190
22681
|
els['editor-textarea'].addEventListener('select', window.handleEditorCaretChange);
|
|
20191
22682
|
els['editor-textarea'].addEventListener('keyup', window.handleEditorCaretChange);
|
|
20192
22683
|
els['editor-textarea'].addEventListener('keydown', function(e) {
|
|
22684
|
+
if (e.isComposing || e.key === 'Process' || e.keyCode === 229) return;
|
|
20193
22685
|
if (state.editorCompletionText && e.key === 'Tab') { e.preventDefault(); window.acceptEditorCompletion(); return; }
|
|
20194
22686
|
if (e.key === 'Escape' && (state.editorCompletionText || (els['editor-completion'] && els['editor-completion'].classList.contains('open')))) { e.preventDefault(); window.dismissEditorCompletion(); return; }
|
|
20195
22687
|
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 's') { e.preventDefault(); window.saveEditor(); return; }
|
|
20196
|
-
if ((e.ctrlKey && e.key === ' ') || (e.altKey && e.key === '\\')) { e.preventDefault(); window.requestEditorCompletion(); return; }
|
|
20197
22688
|
if (state.editorVimEnabled && e.key === 'Escape') { state.editorVimMode = 'normal'; state.editorVimPending = ''; e.preventDefault(); window.renderNativeEditor(); return; }
|
|
20198
22689
|
if (window.handleEditorVimKey(e)) return;
|
|
20199
22690
|
});
|