dsh-ntr 0.2.0 → 0.3.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/README.en.md +9 -6
- package/README.md +9 -6
- package/cordis.patch.yml +12 -0
- package/lib/bridge.js +654 -85
- package/lib/client/panel.js +224 -78
- package/lib/client/store.js +133 -1
- package/lib/client.js +702 -304
- package/lib/client.js.map +1 -1
- package/lib/impl.js +47 -0
- package/lib/index.js +15 -1
- package/lib/types/bridge.d.ts +208 -6
- package/lib/types/client/panel.d.ts +0 -1
- package/lib/types/client/store.d.ts +54 -1
- package/lib/types/impl.d.ts +26 -1
- package/lib/types/protocol.d.ts +73 -0
- package/lib/types/update.d.ts +183 -0
- package/lib/update.js +681 -0
- package/package.json +5 -1
- package/src/bridge.ts +700 -83
- package/src/client/panel.tsx +406 -205
- package/src/client/store.ts +146 -2
- package/src/impl.ts +66 -1
- package/src/index.ts +16 -1
- package/src/protocol.ts +76 -0
- package/src/update.ts +699 -0
package/lib/client.js
CHANGED
|
@@ -49,6 +49,12 @@ window.__ModuleLoader__.load({
|
|
|
49
49
|
const MAX_WATCHED = 6;
|
|
50
50
|
/** Raw JSON budget for one event block; the cut is marked. */
|
|
51
51
|
const RAW_MAX = 256e3;
|
|
52
|
+
/**
|
|
53
|
+
* How long a fetched update state stays fresh. The settings panel asks on every
|
|
54
|
+
* mount; without this, every open would hit the registry. A forced check (the
|
|
55
|
+
* card's own button) always goes out.
|
|
56
|
+
*/
|
|
57
|
+
const PLUGIN_UPDATE_TTL_MS = 6e5;
|
|
52
58
|
/** Pretty-printed JSON of an agent message (never throws, cuts only at {@link RAW_MAX} with a marker). */
|
|
53
59
|
function jsonText(value) {
|
|
54
60
|
let text;
|
|
@@ -262,6 +268,14 @@ window.__ModuleLoader__.load({
|
|
|
262
268
|
defaultCommand: "opencode",
|
|
263
269
|
defaultArgs: ["acp"]
|
|
264
270
|
},
|
|
271
|
+
{
|
|
272
|
+
id: "cursor",
|
|
273
|
+
name: "Cursor CLI",
|
|
274
|
+
description: "Cursor CLI — run as `agent acp` over stdio (legacy alias `cursor-agent acp`)",
|
|
275
|
+
detected: false,
|
|
276
|
+
defaultCommand: "agent",
|
|
277
|
+
defaultArgs: ["acp"]
|
|
278
|
+
},
|
|
265
279
|
{
|
|
266
280
|
id: "qwen",
|
|
267
281
|
name: "Qwen Code",
|
|
@@ -377,6 +391,22 @@ window.__ModuleLoader__.load({
|
|
|
377
391
|
cachedModelReads = /* @__PURE__ */ new Set();
|
|
378
392
|
/** Counts behind the last successful explicit re-detect, so a locale switch can re-render its summary. */
|
|
379
393
|
detectCounts;
|
|
394
|
+
/** When {@link UiState.pluginUpdate} was last read from the host (epoch ms). */
|
|
395
|
+
pluginUpdateFetchedAt = 0;
|
|
396
|
+
/**
|
|
397
|
+
* The shared in-flight `plugin/update-check`. The settings section mounts
|
|
398
|
+
* twice (both entries) and the update popover asks too; without this, two
|
|
399
|
+
* mounts in the same tick each fire their own registry read.
|
|
400
|
+
*/
|
|
401
|
+
pluginUpdateInflight;
|
|
402
|
+
/** Re-entry guard for `plugin/update-apply` (a double click is one install). */
|
|
403
|
+
pluginUpdateApplying = false;
|
|
404
|
+
/**
|
|
405
|
+
* Update read generation. An apply bumps it so a check that was already in
|
|
406
|
+
* flight (started before the install) cannot land afterwards and overwrite
|
|
407
|
+
* the install's verdict with the pre-install `available`.
|
|
408
|
+
*/
|
|
409
|
+
pluginUpdateGeneration = 0;
|
|
380
410
|
constructor(rpc, locale) {
|
|
381
411
|
this.rpc = rpc;
|
|
382
412
|
this.locale = locale;
|
|
@@ -499,14 +529,15 @@ window.__ModuleLoader__.load({
|
|
|
499
529
|
/** Snapshot refresh used on panel open and after a stream outage. */
|
|
500
530
|
async resync() {
|
|
501
531
|
try {
|
|
502
|
-
const [{ agents }, { sessions }, defaultAgentInfo, detectResult, presetResult, tagHaloResult, deadlinesResult] = await Promise.all([
|
|
532
|
+
const [{ agents }, { sessions }, defaultAgentInfo, detectResult, presetResult, tagHaloResult, deadlinesResult, versionResult] = await Promise.all([
|
|
503
533
|
this.call("agents/list"),
|
|
504
534
|
this.call("sessions/list"),
|
|
505
535
|
this.call("default/agent").catch(() => ({})),
|
|
506
536
|
this.call("agents/detect").catch(() => null),
|
|
507
537
|
this.call("preset/status").catch(() => null),
|
|
508
538
|
this.call("ui/tag-halo").catch(() => ({ halo: { ...DEFAULT_TAG_HALO } })),
|
|
509
|
-
this.call("ui/approval-deadlines").catch(() => ({ deadlines: void 0 }))
|
|
539
|
+
this.call("ui/approval-deadlines").catch(() => ({ deadlines: void 0 })),
|
|
540
|
+
this.call("plugin/version").catch(() => null)
|
|
510
541
|
]);
|
|
511
542
|
const detectedAgents = detectResult && detectResult.agents.length > 0 ? detectResult.agents : this.state.detectedAgents.length > 0 ? this.state.detectedAgents : [...DEFAULT_KNOWN_PRESETS];
|
|
512
543
|
this.mutate({
|
|
@@ -517,7 +548,8 @@ window.__ModuleLoader__.load({
|
|
|
517
548
|
detectedAgents,
|
|
518
549
|
preset: presetResult?.preset ?? void 0,
|
|
519
550
|
tagHalo: tagHaloResult?.halo ?? { ...DEFAULT_TAG_HALO },
|
|
520
|
-
approvalDeadlines: deadlinesResult.deadlines
|
|
551
|
+
approvalDeadlines: deadlinesResult.deadlines,
|
|
552
|
+
pluginVersion: versionResult?.version !== void 0 && versionResult.version !== "" ? versionResult.version : void 0
|
|
521
553
|
});
|
|
522
554
|
const active = this.state.activeSessionId ?? sessions[0]?.sessionId;
|
|
523
555
|
if (active !== void 0) await this.loadTranscript(active);
|
|
@@ -525,6 +557,89 @@ window.__ModuleLoader__.load({
|
|
|
525
557
|
this.mutate({ notice: String(error instanceof Error ? error.message : error) });
|
|
526
558
|
}
|
|
527
559
|
}
|
|
560
|
+
/**
|
|
561
|
+
* Read the plugin's update state (`plugin/update-check`). Throttled to ten
|
|
562
|
+
* minutes unless `force`: the settings panel asks on mount, and every
|
|
563
|
+
* remount must not hit the registry.
|
|
564
|
+
*
|
|
565
|
+
* An older host serves no such endpoint (`unknown endpoint`). That is a
|
|
566
|
+
* normal degradation, not an error worth a notice: the answer is `undefined`
|
|
567
|
+
* and the panel simply keeps its update entry hidden.
|
|
568
|
+
*/
|
|
569
|
+
async checkPluginUpdate(force = false) {
|
|
570
|
+
if (this.pluginUpdateInflight !== void 0) return this.pluginUpdateInflight;
|
|
571
|
+
const current = this.state.pluginUpdate;
|
|
572
|
+
if (!force && current !== void 0 && Date.now() - this.pluginUpdateFetchedAt < PLUGIN_UPDATE_TTL_MS) return current;
|
|
573
|
+
const generation = this.pluginUpdateGeneration;
|
|
574
|
+
const inflight = this.readPluginUpdate(generation);
|
|
575
|
+
this.pluginUpdateInflight = inflight;
|
|
576
|
+
try {
|
|
577
|
+
return await inflight;
|
|
578
|
+
} finally {
|
|
579
|
+
this.pluginUpdateInflight = void 0;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
async readPluginUpdate(generation) {
|
|
583
|
+
try {
|
|
584
|
+
const pluginUpdate = await this.call("plugin/update-check");
|
|
585
|
+
if (generation !== this.pluginUpdateGeneration) return void 0;
|
|
586
|
+
this.pluginUpdateFetchedAt = Date.now();
|
|
587
|
+
this.mutate({ pluginUpdate });
|
|
588
|
+
return pluginUpdate;
|
|
589
|
+
} catch {
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Install one exact version (`plugin/update-apply`). The status flips to
|
|
595
|
+
* `applying` first so the badge answers the click; the host's answer then
|
|
596
|
+
* becomes the state.
|
|
597
|
+
*
|
|
598
|
+
* A failed call does NOT prove the install did not happen: on an HMR host
|
|
599
|
+
* the update uninstalls the plugin before reinstalling it, which can cut the
|
|
600
|
+
* response. Whatever the error, the disk may already carry the new version,
|
|
601
|
+
* so the state becomes `restart-required` (the one neutral verdict for "the
|
|
602
|
+
* running code is not the disk's") with `installed` dropped (unknown, not a
|
|
603
|
+
* fact to display) and the notice asks for a reload rather than restoring
|
|
604
|
+
* `available` and pretending nothing changed.
|
|
605
|
+
*/
|
|
606
|
+
async applyPluginUpdate(version) {
|
|
607
|
+
if (this.pluginUpdateApplying) return void 0;
|
|
608
|
+
this.pluginUpdateApplying = true;
|
|
609
|
+
this.pluginUpdateGeneration += 1;
|
|
610
|
+
const previous = this.state.pluginUpdate;
|
|
611
|
+
if (previous !== void 0) this.mutate({ pluginUpdate: {
|
|
612
|
+
...previous,
|
|
613
|
+
status: "applying"
|
|
614
|
+
} });
|
|
615
|
+
try {
|
|
616
|
+
const pluginUpdate = await this.call("plugin/update-apply", { version });
|
|
617
|
+
this.pluginUpdateFetchedAt = Date.now();
|
|
618
|
+
this.mutate({ pluginUpdate });
|
|
619
|
+
return pluginUpdate;
|
|
620
|
+
} catch (error) {
|
|
621
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
622
|
+
const interrupted = previous !== void 0 ? {
|
|
623
|
+
...previous,
|
|
624
|
+
status: "restart-required",
|
|
625
|
+
installed: void 0,
|
|
626
|
+
message
|
|
627
|
+
} : {
|
|
628
|
+
status: "restart-required",
|
|
629
|
+
current: this.state.pluginVersion ?? "?",
|
|
630
|
+
message
|
|
631
|
+
};
|
|
632
|
+
this.pluginUpdateFetchedAt = 0;
|
|
633
|
+
this.mutate({
|
|
634
|
+
pluginUpdate: interrupted,
|
|
635
|
+
notice: this.locale("更新请求已中断;请刷新页面确认当前版本。", "The update request was interrupted. Reload the page to confirm the installed version.")
|
|
636
|
+
});
|
|
637
|
+
return;
|
|
638
|
+
} finally {
|
|
639
|
+
this.pluginUpdateGeneration += 1;
|
|
640
|
+
this.pluginUpdateApplying = false;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
528
643
|
async detectAgents() {
|
|
529
644
|
this.mutate({ detecting: true });
|
|
530
645
|
try {
|
|
@@ -2612,18 +2727,34 @@ window.__ModuleLoader__.load({
|
|
|
2612
2727
|
--ntr-success: color-mix(in srgb, var(--dsw-alias-state-success-primary, #16a34a) 72%, var(--dsw-alias-label-primary, #111827));
|
|
2613
2728
|
--ntr-accent: var(--dsw-alias-button-primary-fill, #2563eb);
|
|
2614
2729
|
width: 100%; max-width: 960px; box-sizing: border-box; margin: 0 auto;
|
|
2615
|
-
padding:
|
|
2730
|
+
padding: 28px 32px; min-width: 0; container-type: inline-size; font-size: var(--ntr-font); line-height: 1.55;
|
|
2616
2731
|
}
|
|
2617
|
-
.dwa-root
|
|
2732
|
+
.dwa-root [hidden] { display: none !important; }
|
|
2733
|
+
.dwa-root button, .dwa-root input, .dwa-root select, .dwa-root textarea { font-family: inherit; }
|
|
2734
|
+
.dwa-root input, .dwa-root textarea { min-width: 0; }
|
|
2735
|
+
.dwa-tabs { display: flex; gap: 24px; flex-wrap: wrap; border-bottom: var(--ntr-line); margin-bottom: 24px; }
|
|
2736
|
+
.dwa-tabs > button { font: inherit; color: var(--ntr-muted); background: transparent; border: 0; border-bottom: 2px solid transparent; padding: 0 0 12px; min-height: 40px; white-space: nowrap; cursor: pointer; }
|
|
2737
|
+
.dwa-tabs > button:hover { color: var(--dsw-alias-label-primary, #111827); }
|
|
2738
|
+
.dwa-tabs > button[aria-pressed="true"] { color: var(--dsw-alias-label-primary, #111827); border-bottom-color: currentColor; font-weight: 550; }
|
|
2739
|
+
.dwa-detail-tabs { margin: 4px 0 20px; gap: 20px; }
|
|
2740
|
+
.dwa-detail-tabs > button { font-size: var(--ntr-font-sm); }
|
|
2741
|
+
.dwa-row-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
|
|
2742
|
+
.dwa-notice { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
|
|
2743
|
+
.dwa-notice > span { flex: 1; min-width: 0; overflow-wrap: anywhere; }
|
|
2744
|
+
.dwa-empty { text-align: center; padding: 40px 16px; color: var(--ntr-muted); }
|
|
2745
|
+
.dwa-empty h3 { font-size: 16px; font-weight: 550; color: var(--dsw-alias-label-primary, #111827); margin: 0 0 8px; }
|
|
2746
|
+
.dwa-empty .dwa-btn { margin-top: 20px; }
|
|
2747
|
+
.dwa-health { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin-top: 24px; color: var(--ntr-muted); font-size: var(--ntr-font-sm); flex-wrap: wrap; }
|
|
2748
|
+
.dwa-health-status { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
|
|
2749
|
+
.dwa-health-status > span:last-child:not(:nth-child(2)) { padding-left: 12px; border-left: var(--ntr-line); }
|
|
2750
|
+
.dwa-back { margin-bottom: 16px; }
|
|
2618
2751
|
.dwa-root button:focus-visible, .dwa-root input:focus-visible, .dwa-root select:focus-visible {
|
|
2619
2752
|
outline: 2px solid var(--ntr-accent); outline-offset: 2px;
|
|
2620
2753
|
}
|
|
2621
|
-
.dwa-page-header { display: flex; align-items:
|
|
2754
|
+
.dwa-page-header { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 28px; }
|
|
2622
2755
|
.dwa-page-heading { min-width: 0; }
|
|
2623
|
-
.dwa-page-title { margin: 0; font-size: 20px; line-height: 1.35; font-weight:
|
|
2756
|
+
.dwa-page-title { margin: 0; font-size: 20px; line-height: 1.35; font-weight: 550; letter-spacing: -0.02em; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
|
|
2624
2757
|
.dwa-page-description { margin: 5px 0 0; color: var(--ntr-muted); font-size: var(--ntr-font-sm); }
|
|
2625
|
-
.dwa-page-status { display: flex; align-items: center; gap: 8px; margin-top: 10px; color: var(--ntr-muted); font-size: var(--ntr-font-xs); }
|
|
2626
|
-
.dwa-page-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
|
|
2627
2758
|
.dwa-btn {
|
|
2628
2759
|
min-height: 32px; box-sizing: border-box; font: inherit; border-radius: var(--ntr-radius-sm);
|
|
2629
2760
|
border: 1px solid var(--dsw-alias-border-l2, #d1d5db); background: var(--dsw-alias-bg-layer-1, #fff);
|
|
@@ -2636,14 +2767,16 @@ window.__ModuleLoader__.load({
|
|
|
2636
2767
|
.dwa-btn-primary { background: var(--ntr-accent); color: var(--dsw-alias-label-primary-foreground, #fff); border-color: transparent; font-weight: 550; }
|
|
2637
2768
|
.dwa-btn-primary:hover { background: var(--ntr-accent); border-color: transparent; opacity: 0.88; }
|
|
2638
2769
|
.dwa-btn-secondary { background: var(--dsw-alias-bg-layer-2, #f3f4f6); }
|
|
2770
|
+
.dwa-btn-quiet { background: transparent; border-color: transparent; color: var(--ntr-muted); }
|
|
2771
|
+
.dwa-btn-quiet:hover { border-color: transparent; color: var(--dsw-alias-label-primary, #111827); }
|
|
2639
2772
|
.dwa-btn-danger { color: var(--ntr-danger); border-color: var(--dsw-alias-state-error-secondary, #fca5a5); }
|
|
2640
2773
|
.dwa-btn-danger:hover { background: var(--dsw-alias-interactive-bg-hover-danger, #fee2e2); }
|
|
2641
2774
|
.dwa-section { margin-bottom: 24px; }
|
|
2642
2775
|
.dwa-section-heading { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 10px; }
|
|
2643
|
-
.dwa-section-title { font-size:
|
|
2776
|
+
.dwa-section-title { font-size: 13px; font-weight: 550; margin: 0; display: flex; align-items: center; gap: 8px; }
|
|
2644
2777
|
.dwa-section-copy { margin: 3px 0 0; font-size: var(--ntr-font-xs); color: var(--ntr-muted); }
|
|
2645
2778
|
.dwa-card { border: var(--ntr-line); border-radius: var(--ntr-radius); padding: 16px; background: var(--dsw-alias-bg-layer-1, #fff); font-size: var(--ntr-font); line-height: 1.55; }
|
|
2646
|
-
.dwa-card-warn { border-
|
|
2779
|
+
.dwa-card-warn { border-color: color-mix(in srgb, var(--ntr-warn) 30%, var(--dsw-alias-border-l2, #e5e7eb)); background: var(--dsw-alias-state-warn-tertiary, #fffbeb); }
|
|
2647
2780
|
.dwa-mode-banner { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 5px 16px; align-items: start; margin-bottom: 24px; padding: 14px 16px; }
|
|
2648
2781
|
.dwa-mode-title { display: flex; align-items: center; gap: 8px; font-weight: 650; }
|
|
2649
2782
|
.dwa-mode-copy { grid-column: 1 / -1; color: var(--ntr-muted); font-size: var(--ntr-font-xs); }
|
|
@@ -2652,26 +2785,36 @@ window.__ModuleLoader__.load({
|
|
|
2652
2785
|
.dwa-badge-success { background: var(--dsw-alias-state-success-tertiary, #dcfce7); color: var(--ntr-success); }
|
|
2653
2786
|
.dwa-badge-warn { background: var(--dsw-alias-state-warn-tertiary, #fef3c7); color: var(--ntr-warn); }
|
|
2654
2787
|
.dwa-badge-info { background: var(--dsw-alias-state-business-tertiary, #dbeafe); color: var(--dsw-alias-state-business-primary, #2563eb); }
|
|
2788
|
+
/* The update badge is a button (it expands the update card): strip the
|
|
2789
|
+
browser's default button chrome, keep the badge look. */
|
|
2790
|
+
.dwa-update-badge { border: 0; font-family: inherit; cursor: pointer; }
|
|
2791
|
+
.dwa-update-badge:hover { opacity: 0.85; }
|
|
2792
|
+
/* The version badge doubles as the update entry: same badge look, no chrome. */
|
|
2793
|
+
.dwa-version-btn { border: 0; font-family: inherit; cursor: pointer; }
|
|
2794
|
+
.dwa-version-btn:hover { opacity: 0.85; }
|
|
2795
|
+
.dwa-version { font-family: var(--ds-font-family-code, monospace); }
|
|
2796
|
+
/* The update card sits between the page header and the permission mirror. */
|
|
2797
|
+
.dwa-update-card { margin-bottom: 16px; }
|
|
2798
|
+
.dwa-update-summary { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; font-weight: 550; }
|
|
2799
|
+
.dwa-update-copy { margin: 6px 0 0; color: var(--ntr-muted); font-size: var(--ntr-font-xs); }
|
|
2800
|
+
.dwa-update-message { margin: 6px 0 0; color: var(--ntr-muted); font-size: var(--ntr-font-xs); white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
2801
|
+
.dwa-update-actions { margin-top: 10px; }
|
|
2655
2802
|
.dwa-dot { width: 7px; height: 7px; border-radius: 50%; display: inline-block; flex-shrink: 0; }
|
|
2656
|
-
.dwa-agent-list { display: flex; flex-direction: column;
|
|
2657
|
-
.dwa-agent-card { border: var(--ntr-line);
|
|
2658
|
-
.dwa-agent-
|
|
2659
|
-
.dwa-agent-
|
|
2803
|
+
.dwa-agent-list { display: flex; flex-direction: column; border-top: var(--ntr-line); }
|
|
2804
|
+
.dwa-agent-card { border-bottom: var(--ntr-line); min-width: 0; }
|
|
2805
|
+
.dwa-agent-row { display: grid; grid-template-columns: 38px minmax(0, 1fr) auto; align-items: center; gap: 14px; padding: 16px 0; }
|
|
2806
|
+
.dwa-agent-avatar { display: grid; place-items: center; width: 38px; height: 38px; border: var(--ntr-line); border-radius: 9px; background: var(--dsw-alias-bg-layer-2, #f3f4f6); color: var(--ntr-muted); font: 12px var(--ds-font-family-code, monospace); }
|
|
2660
2807
|
.dwa-caret { font-size: 14px; line-height: 1; display: inline-flex; align-items: center; justify-content: center; width: 1em; }
|
|
2661
2808
|
.dwa-caret-btn { font: inherit; border: none; background: var(--dsw-alias-bg-layer-2, #f3f4f6); width: 28px; height: 28px; padding: 0; border-radius: var(--ntr-radius-sm); display: inline-flex; align-items: center; justify-content: center; color: var(--ntr-muted); cursor: pointer; }
|
|
2662
2809
|
.dwa-caret-btn:hover { background: var(--dsw-alias-interactive-bg-active, #e5e7eb); color: inherit; }
|
|
2663
2810
|
.dwa-agent-summary { min-width: 0; }
|
|
2664
2811
|
.dwa-agent-titleline { display: flex; align-items: center; gap: 8px; min-width: 0; flex-wrap: wrap; }
|
|
2665
|
-
.dwa-agent-name { font-size: 13px; font-weight:
|
|
2812
|
+
.dwa-agent-name { font-size: 13px; font-weight: 550; overflow-wrap: anywhere; }
|
|
2666
2813
|
.dwa-agent-meta { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 4px; color: var(--ntr-muted); font-size: var(--ntr-font-xs); }
|
|
2667
2814
|
.dwa-agent-meta-separator { opacity: 0.45; }
|
|
2668
|
-
.dwa-agent-body {
|
|
2669
|
-
.dwa-subsection {
|
|
2670
|
-
.dwa-
|
|
2671
|
-
.dwa-subsection-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 12px; }
|
|
2672
|
-
.dwa-subsection-title { margin: 0; font-size: 13px; font-weight: 650; }
|
|
2673
|
-
.dwa-subsection-copy { margin: 3px 0 0; color: var(--ntr-muted); font-size: var(--ntr-font-xs); }
|
|
2674
|
-
.dwa-form-row { display: flex; gap: var(--ntr-gap-3); margin-bottom: 14px; align-items: flex-start; }
|
|
2815
|
+
.dwa-agent-body { padding: 0 0 24px 52px; }
|
|
2816
|
+
.dwa-subsection { min-width: 0; }
|
|
2817
|
+
.dwa-form-row { display: flex; gap: var(--ntr-gap-3); margin-bottom: 14px; align-items: stretch; }
|
|
2675
2818
|
.dwa-form-col { flex: 1; display: flex; flex-direction: column; gap: 6px; min-width: 0; }
|
|
2676
2819
|
.dwa-form-label { font-size: var(--ntr-font-sm); font-weight: 600; color: var(--dsw-alias-label-primary, #374151); }
|
|
2677
2820
|
.dwa-hint { font-size: var(--ntr-font-xs); line-height: 1.55; color: var(--ntr-muted); }
|
|
@@ -2680,11 +2823,13 @@ window.__ModuleLoader__.load({
|
|
|
2680
2823
|
.dwa-select { min-height: 32px; font: inherit; font-size: var(--ntr-font-sm); padding: 5px 8px; border: 1px solid var(--dsw-alias-border-l2, #d1d5db); border-radius: var(--ntr-radius-sm); background: var(--dsw-alias-bg-layer-1, #fff); color: inherit; }
|
|
2681
2824
|
.dwa-input:hover, .dwa-select:hover { border-color: var(--dsw-alias-border-l1, #9ca3af); }
|
|
2682
2825
|
.dwa-input:focus, .dwa-select:focus { border-color: var(--ntr-accent); }
|
|
2683
|
-
.dwa-input-mono, .dwa-mono { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; }
|
|
2826
|
+
.dwa-input-mono, .dwa-mono { font-family: var(--ds-font-family-code, ui-monospace), SFMono-Regular, Menlo, Monaco, Consolas, monospace; }
|
|
2684
2827
|
.dwa-stderr { max-height: 120px; overflow: auto; font-family: monospace; font-size: var(--ntr-font-xs); white-space: pre-wrap; color: var(--ntr-warn); margin: 12px 0 0; }
|
|
2685
2828
|
.dwa-default-hint { background: var(--dsw-alias-bg-layer-2, #f9fafb); border: var(--ntr-line); border-radius: var(--ntr-radius-sm); padding: 10px 12px; font-size: var(--ntr-font-sm); display: flex; align-items: center; justify-content: space-between; margin: 12px 0 14px; gap: 12px; }
|
|
2686
2829
|
.dwa-form-actions { display: flex; align-items: center; gap: 8px; margin-top: 16px; padding-top: 14px; border-top: var(--ntr-line); flex-wrap: wrap; }
|
|
2687
2830
|
.dwa-form-actions .dwa-btn-primary { min-width: 88px; }
|
|
2831
|
+
.dwa-form-actions > .dwa-hint:first-child { margin-right: auto; }
|
|
2832
|
+
.dwa-form-actions > .dwa-hint:last-child:not(:first-child) { width: 100%; }
|
|
2688
2833
|
.dwa-menu-wrap { position: relative; }
|
|
2689
2834
|
.dwa-menu-wrap > .dwa-btn { width: 32px; padding: 0; }
|
|
2690
2835
|
.dwa-menu { position: absolute; right: 0; top: calc(100% + 4px); z-index: 20; min-width: 190px; border: var(--ntr-line); border-radius: var(--ntr-radius-sm); background: var(--dsw-alias-bg-layer-1, #fff); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); padding: 4px; display: flex; flex-direction: column; }
|
|
@@ -2692,10 +2837,10 @@ window.__ModuleLoader__.load({
|
|
|
2692
2837
|
.dwa-menu-item:hover { background: var(--dsw-alias-interactive-bg-active, #f3f4f6); }
|
|
2693
2838
|
.dwa-menu-item-danger { color: var(--ntr-danger); }
|
|
2694
2839
|
.dwa-menu-confirm { display: flex; align-items: center; gap: 4px; padding: 4px; }
|
|
2695
|
-
.dwa-add-panel
|
|
2696
|
-
.dwa-add-
|
|
2697
|
-
.dwa-add-
|
|
2698
|
-
.dwa-add-content {
|
|
2840
|
+
.dwa-add-panel .dwa-agent-row { display: none; }
|
|
2841
|
+
.dwa-add-panel .dwa-agent-body { padding: 0 0 24px; }
|
|
2842
|
+
.dwa-add-panel .dwa-agent-card { border: 0; }
|
|
2843
|
+
.dwa-add-content { padding-top: 10px; }
|
|
2699
2844
|
.dwa-chip { min-height: 30px; font: inherit; font-size: var(--ntr-font-sm); border: var(--ntr-line); border-radius: 999px; padding: 4px 12px; background: var(--dsw-alias-bg-layer-1, #fff); cursor: pointer; color: inherit; }
|
|
2700
2845
|
.dwa-chip:hover { background: var(--dsw-alias-interactive-bg-active, #f3f4f6); }
|
|
2701
2846
|
.dwa-chip-active { border-color: var(--ntr-accent); background: color-mix(in srgb, var(--dsw-alias-state-business-primary, #2563eb) 8%, transparent); color: var(--dsw-alias-state-business-primary, #2563eb); font-weight: 550; }
|
|
@@ -2727,13 +2872,13 @@ window.__ModuleLoader__.load({
|
|
|
2727
2872
|
.dwa-model-status { margin-left: auto; white-space: nowrap; }
|
|
2728
2873
|
.dwa-model-search { width: 200px; min-height: 30px; }
|
|
2729
2874
|
.dwa-model-empty { padding: 6px; }
|
|
2730
|
-
.dwa-model-row { display: flex; align-items: center; gap:
|
|
2875
|
+
.dwa-model-row { display: flex; align-items: center; gap: 8px; width: 100%; min-height: 38px; border: none; background: none; padding: 7px 8px; border-radius: 5px; cursor: pointer; color: inherit; font: inherit; font-size: var(--ntr-font-sm); text-align: left; }
|
|
2731
2876
|
.dwa-model-row:hover { background: var(--dsw-alias-interactive-bg-active, #f3f4f6); }
|
|
2732
2877
|
.dwa-model-row.is-on { background: color-mix(in srgb, var(--dsw-alias-state-business-primary, #2563eb) 8%, transparent); color: var(--dsw-alias-state-business-primary, #2563eb); }
|
|
2733
2878
|
.dwa-model-row-mark { width: 12px; flex: none; text-align: center; opacity: 0.75; }
|
|
2734
2879
|
.dwa-model-row-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2735
2880
|
/* Name and credit keep their room; the id is the only cell that collapses. */
|
|
2736
|
-
.dwa-model-row-desc { flex: 0 0 auto; max-width: 45%; opacity: 0.75; font-size:
|
|
2881
|
+
.dwa-model-row-desc { flex: 0 0 auto; max-width: 45%; opacity: 0.75; font-size: var(--ntr-font-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2737
2882
|
/* The trailing 14px is reserved for the fade mask: while the id fits, the
|
|
2738
2883
|
gradient only covers empty padding; once it overflows, its tail dissolves
|
|
2739
2884
|
instead of ending in a hard ellipsis. armModelIdMarquee reads the same
|
|
@@ -2747,12 +2892,12 @@ window.__ModuleLoader__.load({
|
|
|
2747
2892
|
}
|
|
2748
2893
|
.dwa-model-row-remove { flex: none; opacity: 0.5; padding: 0 2px; }
|
|
2749
2894
|
.dwa-model-row:hover .dwa-model-row-remove { opacity: 1; }
|
|
2750
|
-
.dwa-seg { display: inline-flex; border-radius: var(--ntr-radius-sm); border:
|
|
2751
|
-
.dwa-seg > button { min-height:
|
|
2752
|
-
.dwa-seg > button + button { border-left: 1px solid var(--dsw-alias-border-l2, #d1d5db); }
|
|
2895
|
+
.dwa-seg { display: inline-flex; gap: 4px; padding: 4px; box-sizing: border-box; border-radius: var(--ntr-radius-sm); border: var(--ntr-line); background: var(--dsw-alias-bg-layer-2, #f3f4f6); vertical-align: middle; }
|
|
2896
|
+
.dwa-seg > button { min-height: 32px; font: inherit; font-size: var(--ntr-font-sm); color: var(--ntr-muted); border: 1px solid transparent; border-radius: 4px; background: transparent; padding: 4px 12px; cursor: pointer; white-space: nowrap; }
|
|
2753
2897
|
.dwa-seg > button:hover { background: var(--dsw-alias-interactive-bg-active, #f3f4f6); }
|
|
2754
|
-
.dwa-seg > button.is-on { background: var(--ntr-
|
|
2755
|
-
.dwa-
|
|
2898
|
+
.dwa-seg > button.is-on { background: var(--dsw-alias-bg-layer-1, #fff); border: var(--ntr-line); color: var(--dsw-alias-label-primary, #111827); font-weight: 550; }
|
|
2899
|
+
.dwa-preferences { border-top: var(--ntr-line); }
|
|
2900
|
+
.dwa-preference-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 20px 0; }
|
|
2756
2901
|
.dwa-preference-row + .dwa-preference-row { border-top: var(--ntr-line); }
|
|
2757
2902
|
/* A control that needs the whole card: the label sits above it, not beside
|
|
2758
2903
|
it. A right-aligned segmented control squeezed its labels into two lines
|
|
@@ -2777,13 +2922,20 @@ window.__ModuleLoader__.load({
|
|
|
2777
2922
|
.dwa-deadline-warn { margin-top: 10px; padding: 9px 12px; border-left: 3px solid var(--dsw-alias-state-warn-primary, #d97706); background: var(--dsw-alias-state-warn-secondary, #fffbeb); border-radius: var(--ntr-radius-sm); font-size: var(--ntr-font-xs); line-height: 1.55; }
|
|
2778
2923
|
.dwa-deadline-reset { display: flex; justify-content: flex-end; margin-top: 8px; }
|
|
2779
2924
|
@media (max-width: 640px) {
|
|
2780
|
-
.dwa-root { padding:
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
.dwa-page-
|
|
2925
|
+
.dwa-root { padding: 20px 16px; }
|
|
2926
|
+
}
|
|
2927
|
+
@container (max-width: 640px) {
|
|
2928
|
+
.dwa-page-header { align-items: flex-start; flex-wrap: wrap; }
|
|
2929
|
+
.dwa-agent-body { padding-left: 0; }
|
|
2930
|
+
.dwa-agent-row { grid-template-columns: 32px minmax(0, 1fr) auto; gap: 10px; }
|
|
2931
|
+
.dwa-agent-avatar { width: 32px; height: 32px; }
|
|
2932
|
+
.dwa-section-heading { flex-wrap: wrap; }
|
|
2933
|
+
.dwa-tabs { gap: 20px; }
|
|
2934
|
+
.dwa-notice { flex-wrap: wrap; }
|
|
2935
|
+
.dwa-seg-wide > button { padding-inline: 5px; }
|
|
2784
2936
|
.dwa-model-toolbar-actions { width: 100%; }
|
|
2785
2937
|
.dwa-model-search { flex: 1 1 auto; width: auto; }
|
|
2786
|
-
.dwa-
|
|
2938
|
+
.dwa-preference-row { align-items: flex-start; flex-direction: column; }
|
|
2787
2939
|
.dwa-default-hint { align-items: flex-start; flex-direction: column; }
|
|
2788
2940
|
/* The slider's scale: up to eight rungs with full unit words ("15 分钟")
|
|
2789
2941
|
need a smaller face before they can collide on a narrow panel. The rung
|
|
@@ -3271,11 +3423,7 @@ window.__ModuleLoader__.load({
|
|
|
3271
3423
|
children: acp.label("权限请求的等待时长与超时处理方式。", "How long to wait for a permission request, and what happens when nobody answers.")
|
|
3272
3424
|
})] })
|
|
3273
3425
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3274
|
-
className: "dwa-
|
|
3275
|
-
style: {
|
|
3276
|
-
paddingTop: 4,
|
|
3277
|
-
paddingBottom: 4
|
|
3278
|
-
},
|
|
3426
|
+
className: "dwa-preferences",
|
|
3279
3427
|
children: [
|
|
3280
3428
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeadlineModeBlock, {
|
|
3281
3429
|
acp,
|
|
@@ -3301,17 +3449,161 @@ window.__ModuleLoader__.load({
|
|
|
3301
3449
|
})]
|
|
3302
3450
|
});
|
|
3303
3451
|
}
|
|
3304
|
-
/**
|
|
3452
|
+
/** The states that carry an update badge next to the version badge. */
|
|
3453
|
+
function updateBadgeText(update, acp) {
|
|
3454
|
+
if (update.status === "available") return acp.label(`可更新 v${update.latest ?? update.current}`, `Update v${update.latest ?? update.current}`);
|
|
3455
|
+
if (update.status === "applying") return acp.label("更新中…", "Updating…");
|
|
3456
|
+
if (update.status === "applied") {
|
|
3457
|
+
const installed = update.installed ?? update.latest ?? update.current;
|
|
3458
|
+
return acp.label(`已更新 v${installed}`, `Updated v${installed}`);
|
|
3459
|
+
}
|
|
3460
|
+
if (update.status === "restart-required") {
|
|
3461
|
+
if (update.installed === void 0) return void 0;
|
|
3462
|
+
return acp.label(`待重启 v${update.installed}`, `Restart for v${update.installed}`);
|
|
3463
|
+
}
|
|
3464
|
+
}
|
|
3465
|
+
/**
|
|
3466
|
+
* The version badge's update companion. Every badge is a button, `applying`
|
|
3467
|
+
* included: the card is where the install's outcome is read, so the running
|
|
3468
|
+
* install must be able to open it too. States without anything to act on get
|
|
3469
|
+
* no badge at all — the version badge itself still opens the card.
|
|
3470
|
+
*/
|
|
3471
|
+
function PluginUpdateBadge(props) {
|
|
3472
|
+
const { acp, update, open, onToggle } = props;
|
|
3473
|
+
const text = updateBadgeText(update, acp);
|
|
3474
|
+
if (text === void 0) return null;
|
|
3475
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3476
|
+
type: "button",
|
|
3477
|
+
className: "dwa-badge dwa-badge-info dwa-update-badge",
|
|
3478
|
+
"aria-expanded": open,
|
|
3479
|
+
"aria-controls": "ntr-plugin-update-card",
|
|
3480
|
+
onClick: onToggle,
|
|
3481
|
+
children: text
|
|
3482
|
+
});
|
|
3483
|
+
}
|
|
3484
|
+
/**
|
|
3485
|
+
* The update card. In-page, no dialog: the settings page already owns the one
|
|
3486
|
+
* action (install the exact version the host reported), and a modal on top of
|
|
3487
|
+
* a settings section would hide the version it is updating.
|
|
3488
|
+
*
|
|
3489
|
+
* The copy stays to one line per state (constraint 33); the host's raw error
|
|
3490
|
+
* (`message`) is the only long text, and it wraps on its own line so a stack
|
|
3491
|
+
* trace or a registry error is readable without stretching the card.
|
|
3492
|
+
*/
|
|
3493
|
+
function PluginUpdateCard(props) {
|
|
3494
|
+
const { acp, update, onClose } = props;
|
|
3495
|
+
const applying = update.status === "applying";
|
|
3496
|
+
const latest = update.latest ?? update.current;
|
|
3497
|
+
const onDisk = update.installed !== void 0 && update.installed !== update.current ? update.installed : void 0;
|
|
3498
|
+
const published = update.publishedAt !== void 0 && !Number.isNaN(new Date(update.publishedAt).getTime()) ? new Date(update.publishedAt).toLocaleDateString() : void 0;
|
|
3499
|
+
const copy = update.status === "available" ? acp.label("更新会卸载并重装插件,之后可能需要重启 DSH。", "Updating uninstalls and reinstalls the plugin, and may require restarting DSH.") : update.status === "applied" ? acp.label("已应用,刷新页面即可使用新版本。", "Applied. Reload the page to use the new version.") : update.status === "restart-required" ? update.installed !== void 0 ? acp.label(`磁盘已是 v${update.installed},重启 DSH 后生效(桌面 App 退出重开;命令行重启 dsh web)。`, `On disk v${update.installed}. Restart DSH to apply (quit and reopen the app, or restart dsh web).`) : acp.label("更新可能已完成,请刷新页面确认当前版本。", "The update may already be complete. Refresh the page to confirm the current version.") : update.status === "busy" ? acp.label("有进行中的对话,结束后才能更新。", "Finish the running conversation before updating.") : update.status === "failed" ? acp.label("更新失败。", "Update failed.") : update.status === "current" ? acp.label("已是最新版本。", "Up to date.") : update.status === "source-install" ? acp.label("源码或本地安装,无法通过 registry 更新。", "Source or local install; update it through its own checkout.") : update.status === "managed" ? acp.label("此安装由宿主管理,不能在这里更新。", "This install is managed by the host and cannot be updated here.") : void 0;
|
|
3500
|
+
const showMessage = (update.status === "failed" || update.status === "busy" || update.status === "managed") && update.message !== void 0;
|
|
3501
|
+
const apply = async () => {
|
|
3502
|
+
if (update.latest === void 0) return;
|
|
3503
|
+
try {
|
|
3504
|
+
await acp.applyPluginUpdate(update.latest);
|
|
3505
|
+
} catch {}
|
|
3506
|
+
};
|
|
3507
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3508
|
+
id: "ntr-plugin-update-card",
|
|
3509
|
+
className: "dwa-card dwa-update-card",
|
|
3510
|
+
role: "group",
|
|
3511
|
+
"aria-label": acp.label("插件更新", "Plugin update"),
|
|
3512
|
+
children: [
|
|
3513
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3514
|
+
className: "dwa-update-summary",
|
|
3515
|
+
children: [
|
|
3516
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: acp.label(`当前 v${update.current}`, `Current v${update.current}`) }),
|
|
3517
|
+
onDisk !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3518
|
+
className: "dwa-hint",
|
|
3519
|
+
children: acp.label(`磁盘 v${onDisk}`, `On disk v${onDisk}`)
|
|
3520
|
+
}),
|
|
3521
|
+
update.latest !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
3522
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3523
|
+
"aria-hidden": "true",
|
|
3524
|
+
children: "→"
|
|
3525
|
+
}),
|
|
3526
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: acp.label(`最新 v${latest}`, `Latest v${latest}`) }),
|
|
3527
|
+
published !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3528
|
+
className: "dwa-hint",
|
|
3529
|
+
children: published
|
|
3530
|
+
})
|
|
3531
|
+
] })
|
|
3532
|
+
]
|
|
3533
|
+
}),
|
|
3534
|
+
copy !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3535
|
+
className: "dwa-update-copy",
|
|
3536
|
+
children: copy
|
|
3537
|
+
}),
|
|
3538
|
+
showMessage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3539
|
+
className: "dwa-update-message",
|
|
3540
|
+
children: update.message
|
|
3541
|
+
}),
|
|
3542
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3543
|
+
className: "dwa-row-actions dwa-update-actions",
|
|
3544
|
+
children: [
|
|
3545
|
+
update.status === "available" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3546
|
+
type: "button",
|
|
3547
|
+
className: "dwa-btn dwa-btn-primary",
|
|
3548
|
+
onClick: () => {
|
|
3549
|
+
apply();
|
|
3550
|
+
},
|
|
3551
|
+
children: acp.label("更新", "Update")
|
|
3552
|
+
}),
|
|
3553
|
+
applying && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3554
|
+
type: "button",
|
|
3555
|
+
className: "dwa-btn dwa-btn-primary",
|
|
3556
|
+
disabled: true,
|
|
3557
|
+
children: acp.label("正在更新…", "Updating…")
|
|
3558
|
+
}),
|
|
3559
|
+
update.status !== "applying" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3560
|
+
type: "button",
|
|
3561
|
+
className: "dwa-btn",
|
|
3562
|
+
onClick: onClose,
|
|
3563
|
+
children: acp.label("关闭", "Close")
|
|
3564
|
+
}),
|
|
3565
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3566
|
+
type: "button",
|
|
3567
|
+
className: "dwa-btn dwa-btn-quiet",
|
|
3568
|
+
disabled: applying,
|
|
3569
|
+
onClick: () => void acp.checkPluginUpdate(true),
|
|
3570
|
+
children: acp.label("重新检查", "Check again")
|
|
3571
|
+
})
|
|
3572
|
+
]
|
|
3573
|
+
})
|
|
3574
|
+
]
|
|
3575
|
+
});
|
|
3576
|
+
}
|
|
3577
|
+
/**
|
|
3578
|
+
* The card is drawn for every state a host can report about this install,
|
|
3579
|
+
* except the two where there is no install to talk about at all.
|
|
3580
|
+
*/
|
|
3581
|
+
function updateCardVisible(update, open) {
|
|
3582
|
+
if (update === void 0 || !open) return false;
|
|
3583
|
+
return update.status !== "unsupported" && update.status !== "not-installed";
|
|
3584
|
+
}
|
|
3305
3585
|
function AcpSettingsSection(props) {
|
|
3306
3586
|
const acp = props.acp;
|
|
3307
3587
|
ensureStyle();
|
|
3308
3588
|
const ui = useUi$1(acp);
|
|
3309
3589
|
const ledger = permissionLedgerCard(ui);
|
|
3310
|
-
const [
|
|
3590
|
+
const [page, setPage] = (0, react.useState)("agents");
|
|
3591
|
+
const [addOpen, setAddOpen] = (0, react.useState)(false);
|
|
3311
3592
|
const [addTarget, setAddTarget] = (0, react.useState)(void 0);
|
|
3312
|
-
const [
|
|
3593
|
+
const [updateOpen, setUpdateOpen] = (0, react.useState)(false);
|
|
3594
|
+
(0, react.useEffect)(() => {
|
|
3595
|
+
acp.checkPluginUpdate();
|
|
3596
|
+
}, [acp]);
|
|
3313
3597
|
const { configured, available } = partitionAgents(ui.detectedAgents, ui.agents);
|
|
3314
3598
|
const selected = addTarget ?? available[0] ?? NEW_AGENT_SEED;
|
|
3599
|
+
const openAdd = () => {
|
|
3600
|
+
setAddOpen(true);
|
|
3601
|
+
setPage("add");
|
|
3602
|
+
};
|
|
3603
|
+
const presetProblem = ui.preset !== void 0 && (!ui.preset.installed || ui.preset.problem !== void 0);
|
|
3604
|
+
const update = ui.pluginUpdate;
|
|
3605
|
+
const versionTitle = update?.status === "source-install" ? acp.label("源码或本地安装,无法通过 registry 更新。", "Source or local install; update it through its own checkout.") : void 0;
|
|
3606
|
+
const versionOpensUpdate = update !== void 0 && update.status !== "unsupported" && update.status !== "not-installed";
|
|
3315
3607
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3316
3608
|
className: "dwa-root",
|
|
3317
3609
|
children: [
|
|
@@ -3319,41 +3611,47 @@ window.__ModuleLoader__.load({
|
|
|
3319
3611
|
className: "dwa-page-header",
|
|
3320
3612
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3321
3613
|
className: "dwa-page-heading",
|
|
3322
|
-
children: [
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
}
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3614
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h2", {
|
|
3615
|
+
className: "dwa-page-title",
|
|
3616
|
+
"aria-label": acp.label("NTR 设置", "NTR settings"),
|
|
3617
|
+
children: [
|
|
3618
|
+
acp.label("NTR 设置", "NTR settings"),
|
|
3619
|
+
ui.pluginVersion !== void 0 && (versionOpensUpdate ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3620
|
+
type: "button",
|
|
3621
|
+
className: "dwa-badge dwa-version dwa-version-btn",
|
|
3622
|
+
title: versionTitle,
|
|
3623
|
+
"aria-expanded": updateOpen,
|
|
3624
|
+
"aria-controls": "ntr-plugin-update-card",
|
|
3625
|
+
onClick: () => setUpdateOpen((open) => !open),
|
|
3626
|
+
children: `v${ui.pluginVersion}`
|
|
3627
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3628
|
+
className: "dwa-badge dwa-version",
|
|
3629
|
+
title: versionTitle,
|
|
3630
|
+
children: `v${ui.pluginVersion}`
|
|
3631
|
+
})),
|
|
3632
|
+
update !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PluginUpdateBadge, {
|
|
3633
|
+
acp,
|
|
3634
|
+
update,
|
|
3635
|
+
open: updateOpen,
|
|
3636
|
+
onToggle: () => setUpdateOpen((open) => !open)
|
|
3637
|
+
})
|
|
3638
|
+
]
|
|
3639
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3640
|
+
className: "dwa-page-description",
|
|
3641
|
+
children: acp.label("连接智能体,设置你的对话偏好。", "Connect agents and set your conversation preferences.")
|
|
3642
|
+
})]
|
|
3643
|
+
}), page === "agents" && configured.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3644
|
+
type: "button",
|
|
3645
|
+
className: "dwa-btn dwa-btn-primary",
|
|
3646
|
+
onClick: openAdd,
|
|
3647
|
+
children: acp.label("添加智能体", "Add agent")
|
|
3355
3648
|
})]
|
|
3356
3649
|
}),
|
|
3650
|
+
update !== void 0 && updateCardVisible(update, updateOpen) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PluginUpdateCard, {
|
|
3651
|
+
acp,
|
|
3652
|
+
update,
|
|
3653
|
+
onClose: () => setUpdateOpen(false)
|
|
3654
|
+
}),
|
|
3357
3655
|
ledger.visible && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3358
3656
|
className: "dwa-card dwa-card-warn",
|
|
3359
3657
|
style: { marginBottom: 16 },
|
|
@@ -3393,18 +3691,20 @@ window.__ModuleLoader__.load({
|
|
|
3393
3691
|
})]
|
|
3394
3692
|
}),
|
|
3395
3693
|
permission.options.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3396
|
-
|
|
3694
|
+
type: "button",
|
|
3695
|
+
className: "dwa-btn",
|
|
3397
3696
|
onClick: () => {
|
|
3398
3697
|
acp.respondPermission(permission.requestId, option.optionId).catch(() => void 0);
|
|
3399
3698
|
},
|
|
3400
3699
|
children: option.name
|
|
3401
3700
|
}, option.optionId)),
|
|
3402
3701
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3403
|
-
|
|
3702
|
+
type: "button",
|
|
3703
|
+
className: "dwa-btn dwa-btn-quiet",
|
|
3404
3704
|
onClick: () => {
|
|
3405
3705
|
acp.respondPermission(permission.requestId).catch(() => void 0);
|
|
3406
3706
|
},
|
|
3407
|
-
children: acp.label("
|
|
3707
|
+
children: acp.label("取消", "Cancel")
|
|
3408
3708
|
})
|
|
3409
3709
|
]
|
|
3410
3710
|
}, permission.requestId))
|
|
@@ -3422,12 +3722,81 @@ window.__ModuleLoader__.load({
|
|
|
3422
3722
|
style: { flex: 1 },
|
|
3423
3723
|
children: ui.notice
|
|
3424
3724
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3425
|
-
|
|
3725
|
+
type: "button",
|
|
3726
|
+
className: "dwa-btn dwa-btn-quiet",
|
|
3727
|
+
"aria-label": acp.label("关闭通知", "Dismiss notice"),
|
|
3426
3728
|
onClick: () => acp.clearNotice(),
|
|
3427
3729
|
children: "✕"
|
|
3428
3730
|
})]
|
|
3429
3731
|
}),
|
|
3430
|
-
|
|
3732
|
+
presetProblem && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3733
|
+
className: "dwa-card dwa-card-warn dwa-notice",
|
|
3734
|
+
role: "status",
|
|
3735
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: acp.label("NTR 模式需要检查,当前可能无法开始对话。", "NTR mode needs attention; new conversations may be unavailable.") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3736
|
+
type: "button",
|
|
3737
|
+
className: "dwa-btn",
|
|
3738
|
+
onClick: () => setPage("diagnostics"),
|
|
3739
|
+
children: acp.label("查看诊断", "View diagnostics")
|
|
3740
|
+
})]
|
|
3741
|
+
}),
|
|
3742
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("nav", {
|
|
3743
|
+
className: "dwa-tabs",
|
|
3744
|
+
"aria-label": acp.label("NTR 设置分类", "NTR settings categories"),
|
|
3745
|
+
children: [
|
|
3746
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3747
|
+
type: "button",
|
|
3748
|
+
"aria-pressed": page === "agents",
|
|
3749
|
+
onClick: () => setPage("agents"),
|
|
3750
|
+
children: acp.label("智能体", "Agents")
|
|
3751
|
+
}),
|
|
3752
|
+
ui.approvalDeadlines !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3753
|
+
type: "button",
|
|
3754
|
+
"aria-pressed": page === "approvals",
|
|
3755
|
+
onClick: () => setPage("approvals"),
|
|
3756
|
+
children: acp.label("审批时限", "Approval deadlines")
|
|
3757
|
+
}),
|
|
3758
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3759
|
+
type: "button",
|
|
3760
|
+
"aria-pressed": page === "appearance",
|
|
3761
|
+
onClick: () => setPage("appearance"),
|
|
3762
|
+
children: acp.label("对话外观", "Appearance")
|
|
3763
|
+
})
|
|
3764
|
+
]
|
|
3765
|
+
}),
|
|
3766
|
+
page === "diagnostics" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
3767
|
+
className: "dwa-section",
|
|
3768
|
+
children: [
|
|
3769
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
3770
|
+
className: "dwa-section-title",
|
|
3771
|
+
children: acp.label("连接诊断", "Connection diagnostics")
|
|
3772
|
+
}),
|
|
3773
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3774
|
+
className: "dwa-preference-row",
|
|
3775
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: acp.label("宿主事件流", "Host event stream") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3776
|
+
className: "dwa-hint",
|
|
3777
|
+
children: streamText(ui.stream, acp)
|
|
3778
|
+
})]
|
|
3779
|
+
}),
|
|
3780
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3781
|
+
className: "dwa-row-actions",
|
|
3782
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3783
|
+
type: "button",
|
|
3784
|
+
className: "dwa-btn",
|
|
3785
|
+
onClick: () => {
|
|
3786
|
+
acp.resync();
|
|
3787
|
+
acp.detectAgents();
|
|
3788
|
+
},
|
|
3789
|
+
disabled: ui.detecting,
|
|
3790
|
+
children: ui.detecting ? acp.label("检测中...", "Detecting...") : acp.label("重新检测与刷新", "Re-detect & Refresh")
|
|
3791
|
+
}), ui.detectSummary !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3792
|
+
className: "dwa-hint",
|
|
3793
|
+
role: "status",
|
|
3794
|
+
children: ui.detectSummary
|
|
3795
|
+
})]
|
|
3796
|
+
})
|
|
3797
|
+
]
|
|
3798
|
+
}),
|
|
3799
|
+
page === "diagnostics" && ui.preset !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3431
3800
|
className: "dwa-card dwa-mode-banner",
|
|
3432
3801
|
children: [
|
|
3433
3802
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -3460,28 +3829,42 @@ window.__ModuleLoader__.load({
|
|
|
3460
3829
|
}),
|
|
3461
3830
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
3462
3831
|
className: "dwa-section",
|
|
3832
|
+
hidden: page !== "agents",
|
|
3833
|
+
"aria-label": acp.label("已接入的智能体", "Connected agents"),
|
|
3463
3834
|
children: [
|
|
3464
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3835
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3465
3836
|
className: "dwa-section-heading",
|
|
3466
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.
|
|
3837
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h3", {
|
|
3467
3838
|
className: "dwa-section-title",
|
|
3468
|
-
children: [acp.label("已接入的智能体", "Connected agents"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3839
|
+
children: [acp.label("已接入的智能体", "Connected agents"), ui.agentsLoaded && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3469
3840
|
className: "dwa-badge",
|
|
3470
3841
|
children: configured.length
|
|
3471
3842
|
})]
|
|
3472
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
3473
|
-
className: "dwa-
|
|
3474
|
-
children: acp.label("
|
|
3475
|
-
})]
|
|
3843
|
+
}) }), configured.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3844
|
+
className: "dwa-hint",
|
|
3845
|
+
children: acp.label("默认项用于新的 NTR 会话", "The default serves new NTR conversations")
|
|
3846
|
+
})]
|
|
3476
3847
|
}),
|
|
3477
|
-
|
|
3478
|
-
className: "dwa-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
children:
|
|
3848
|
+
!ui.agentsLoaded && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3849
|
+
className: "dwa-empty",
|
|
3850
|
+
role: "status",
|
|
3851
|
+
children: acp.label("正在读取智能体…", "Loading agents…")
|
|
3852
|
+
}),
|
|
3853
|
+
ui.agentsLoaded && configured.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3854
|
+
className: "dwa-empty",
|
|
3855
|
+
children: [
|
|
3856
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: acp.label("接入第一个智能体", "Connect your first agent") }),
|
|
3857
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3858
|
+
className: "dwa-section-copy",
|
|
3859
|
+
children: acp.label("选择已有预设,或填写自己的 ACP 启动命令。", "Choose a preset or enter your own ACP launch command.")
|
|
3860
|
+
}),
|
|
3861
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3862
|
+
type: "button",
|
|
3863
|
+
className: "dwa-btn dwa-btn-primary",
|
|
3864
|
+
onClick: openAdd,
|
|
3865
|
+
children: acp.label("添加智能体", "Add agent")
|
|
3866
|
+
})
|
|
3867
|
+
]
|
|
3485
3868
|
}),
|
|
3486
3869
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3487
3870
|
className: "dwa-agent-list",
|
|
@@ -3492,36 +3875,33 @@ window.__ModuleLoader__.load({
|
|
|
3492
3875
|
activeAgent,
|
|
3493
3876
|
acp,
|
|
3494
3877
|
isDefault: ui.defaultAgent === info.id,
|
|
3495
|
-
synthesized
|
|
3878
|
+
synthesized,
|
|
3879
|
+
active: page === "agents"
|
|
3496
3880
|
}, info.id);
|
|
3497
3881
|
})
|
|
3498
3882
|
})
|
|
3499
3883
|
]
|
|
3500
3884
|
}),
|
|
3501
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3885
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
3502
3886
|
className: "dwa-section",
|
|
3503
|
-
|
|
3887
|
+
hidden: page !== "add",
|
|
3888
|
+
"aria-label": acp.label("添加智能体", "Add agent"),
|
|
3889
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3890
|
+
type: "button",
|
|
3891
|
+
className: "dwa-btn dwa-btn-quiet dwa-back",
|
|
3892
|
+
onClick: () => setPage("agents"),
|
|
3893
|
+
children: acp.label("返回智能体列表", "Back to agents")
|
|
3894
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3504
3895
|
className: "dwa-add-panel",
|
|
3505
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
"aria-expanded": addOpen,
|
|
3509
|
-
onClick: () => setAddOpen((open) => !open),
|
|
3510
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3896
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3897
|
+
className: "dwa-section-heading",
|
|
3898
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
3511
3899
|
className: "dwa-section-title",
|
|
3512
3900
|
children: acp.label("添加智能体", "Add agent")
|
|
3513
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
3901
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3514
3902
|
className: "dwa-section-copy",
|
|
3515
|
-
style: { display: "block" },
|
|
3516
3903
|
children: acp.label("从预设快速启用,或创建自定义连接。", "Enable a preset or create a custom connection.")
|
|
3517
|
-
})] })
|
|
3518
|
-
className: "dwa-caret-btn",
|
|
3519
|
-
"aria-hidden": true,
|
|
3520
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3521
|
-
className: "dwa-caret",
|
|
3522
|
-
children: addOpen ? "▾" : "▸"
|
|
3523
|
-
})
|
|
3524
|
-
})]
|
|
3904
|
+
})] })
|
|
3525
3905
|
}), addOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3526
3906
|
className: "dwa-add-content",
|
|
3527
3907
|
children: [
|
|
@@ -3551,21 +3931,28 @@ window.__ModuleLoader__.load({
|
|
|
3551
3931
|
isDefault: false,
|
|
3552
3932
|
synthesized: false,
|
|
3553
3933
|
newCustom: selected.id === "",
|
|
3934
|
+
active: page === "add",
|
|
3554
3935
|
onCreated: () => {
|
|
3555
3936
|
setAddTarget(void 0);
|
|
3556
|
-
|
|
3937
|
+
setAddOpen(false);
|
|
3938
|
+
setPage("agents");
|
|
3557
3939
|
}
|
|
3558
|
-
}, selected.id
|
|
3940
|
+
}, selected.id)
|
|
3559
3941
|
]
|
|
3560
3942
|
})]
|
|
3561
|
-
})
|
|
3943
|
+
})]
|
|
3562
3944
|
}),
|
|
3563
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
3564
|
-
|
|
3565
|
-
|
|
3945
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3946
|
+
hidden: page !== "approvals",
|
|
3947
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ApprovalDeadlinesCard, {
|
|
3948
|
+
acp,
|
|
3949
|
+
ui
|
|
3950
|
+
})
|
|
3566
3951
|
}),
|
|
3567
3952
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
3568
3953
|
className: "dwa-section",
|
|
3954
|
+
hidden: page !== "appearance",
|
|
3955
|
+
"aria-label": acp.label("对话外观", "Appearance"),
|
|
3569
3956
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3570
3957
|
className: "dwa-section-heading",
|
|
3571
3958
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
@@ -3576,11 +3963,7 @@ window.__ModuleLoader__.load({
|
|
|
3576
3963
|
children: acp.label("设置对话中 NTR 挂牌的进程存活提示。", "Choose how the NTR tag indicates a running agent process.")
|
|
3577
3964
|
})] })
|
|
3578
3965
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3579
|
-
className: "dwa-
|
|
3580
|
-
style: {
|
|
3581
|
-
paddingTop: 4,
|
|
3582
|
-
paddingBottom: 4
|
|
3583
|
-
},
|
|
3966
|
+
className: "dwa-preferences",
|
|
3584
3967
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3585
3968
|
className: "dwa-preference-row",
|
|
3586
3969
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -3627,15 +4010,35 @@ window.__ModuleLoader__.load({
|
|
|
3627
4010
|
})]
|
|
3628
4011
|
})]
|
|
3629
4012
|
})]
|
|
4013
|
+
}),
|
|
4014
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("footer", {
|
|
4015
|
+
className: "dwa-health",
|
|
4016
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4017
|
+
className: "dwa-health-status",
|
|
4018
|
+
children: [
|
|
4019
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4020
|
+
className: "dwa-dot",
|
|
4021
|
+
style: { background: ui.stream === "live" ? "var(--ntr-success)" : ui.stream === "down" ? "var(--ntr-danger)" : "var(--ntr-muted)" }
|
|
4022
|
+
}),
|
|
4023
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: streamText(ui.stream, acp) }),
|
|
4024
|
+
ui.preset !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: ui.preset.installed && !presetProblem ? acp.label("NTR 模式已就绪", "NTR mode ready") : acp.label("NTR 模式需检查", "NTR mode needs attention") })
|
|
4025
|
+
]
|
|
4026
|
+
}), page !== "diagnostics" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4027
|
+
type: "button",
|
|
4028
|
+
className: "dwa-btn dwa-btn-quiet",
|
|
4029
|
+
onClick: () => setPage("diagnostics"),
|
|
4030
|
+
children: acp.label("查看诊断", "View diagnostics")
|
|
4031
|
+
})]
|
|
3630
4032
|
})
|
|
3631
4033
|
]
|
|
3632
4034
|
});
|
|
3633
4035
|
}
|
|
3634
4036
|
/** One row per agent: compact when collapsed, the full form when expanded. */
|
|
3635
|
-
function AgentRow({ detected, activeAgent, acp, isDefault, synthesized, newCustom = false, onCreated }) {
|
|
4037
|
+
function AgentRow({ detected, activeAgent, acp, isDefault, synthesized, active, newCustom = false, onCreated }) {
|
|
3636
4038
|
const ui = useUi$1(acp);
|
|
3637
4039
|
const configured = activeAgent !== void 0 || detected.currentConfig !== void 0;
|
|
3638
4040
|
const [expanded, setExpanded] = (0, react.useState)(!configured);
|
|
4041
|
+
const [detailPage, setDetailPage] = (0, react.useState)(configured ? "models" : "connection");
|
|
3639
4042
|
const [form, setForm] = (0, react.useState)(() => initialForm(detected, activeAgent));
|
|
3640
4043
|
const [saving, setSaving] = (0, react.useState)(false);
|
|
3641
4044
|
const [savedSuccess, setSavedSuccess] = (0, react.useState)(false);
|
|
@@ -3671,7 +4074,9 @@ window.__ModuleLoader__.load({
|
|
|
3671
4074
|
const formIncomplete = splitCommandLine(form.commandLine).command === "" || !idValid || idTaken || cwdInvalid || rootsInvalid || idleInvalid || mcpInvalid;
|
|
3672
4075
|
const payload = buildPayload(form, detected, newCustom);
|
|
3673
4076
|
const current = persistedDef(detected, activeAgent);
|
|
3674
|
-
const
|
|
4077
|
+
const clearingIdleOverride = payload.idleTimeoutMs === void 0 && detected.currentConfig?.idleTimeoutMs !== void 0;
|
|
4078
|
+
const dirty = current !== void 0 && (!payloadEquals(payload, current) || clearingIdleOverride);
|
|
4079
|
+
const showSaveWarning = dirty && activeAgent !== void 0 && activeAgent.state !== "stopped";
|
|
3675
4080
|
const handleUseDefault = () => patch({ commandLine: formatCommandLine(detected.defaultCommand, detected.defaultArgs) });
|
|
3676
4081
|
const handleSave = async () => {
|
|
3677
4082
|
setSaving(true);
|
|
@@ -3711,7 +4116,7 @@ window.__ModuleLoader__.load({
|
|
|
3711
4116
|
const displayName = newCustom ? acp.label("新建自定义 Agent", "New Custom Agent") : activeAgent?.title ?? detected.currentConfig?.title ?? detected.name;
|
|
3712
4117
|
const stderr = activeAgent?.state === "error" ? activeAgent.stderrTail ?? [] : [];
|
|
3713
4118
|
const errorSummary = stderr.length > 0 ? stderr[stderr.length - 1] : void 0;
|
|
3714
|
-
const
|
|
4119
|
+
const selectedModelCount = form.exposed?.length ?? 0;
|
|
3715
4120
|
const isPreset = PRESET_IDS.has(detected.id);
|
|
3716
4121
|
const open = expanded || activeAgent?.state === "error" && configured;
|
|
3717
4122
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -3719,17 +4124,10 @@ window.__ModuleLoader__.load({
|
|
|
3719
4124
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3720
4125
|
className: "dwa-agent-row",
|
|
3721
4126
|
children: [
|
|
3722
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
onClick: () => setExpanded((value) => !value),
|
|
3727
|
-
title: open ? acp.label("收起", "Collapse") : acp.label("展开配置与模型", "Expand configuration and models"),
|
|
3728
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3729
|
-
className: "dwa-caret",
|
|
3730
|
-
"aria-hidden": true,
|
|
3731
|
-
children: open ? "▾" : "▸"
|
|
3732
|
-
})
|
|
4127
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4128
|
+
className: "dwa-agent-avatar",
|
|
4129
|
+
"aria-hidden": true,
|
|
4130
|
+
children: displayName.slice(0, 2).toUpperCase()
|
|
3733
4131
|
}),
|
|
3734
4132
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3735
4133
|
className: "dwa-agent-summary",
|
|
@@ -3743,7 +4141,7 @@ window.__ModuleLoader__.load({
|
|
|
3743
4141
|
children: displayName
|
|
3744
4142
|
}),
|
|
3745
4143
|
isDefault && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3746
|
-
className: "dwa-badge dwa-badge-
|
|
4144
|
+
className: "dwa-badge dwa-badge-info",
|
|
3747
4145
|
children: acp.label("默认", "Default")
|
|
3748
4146
|
}),
|
|
3749
4147
|
!isPreset && !newCustom && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -3770,7 +4168,7 @@ window.__ModuleLoader__.load({
|
|
|
3770
4168
|
configured && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [state !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3771
4169
|
className: "dwa-agent-meta-separator",
|
|
3772
4170
|
children: "·"
|
|
3773
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children:
|
|
4171
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: acp.label(`${String(selectedModelCount)} 个已选模型`, `${String(selectedModelCount)} selected models`) })] }),
|
|
3774
4172
|
!synthesized && !newCustom && !detected.detected && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3775
4173
|
style: { color: "var(--ntr-warn)" },
|
|
3776
4174
|
title: detected.description,
|
|
@@ -3789,24 +4187,31 @@ window.__ModuleLoader__.load({
|
|
|
3789
4187
|
]
|
|
3790
4188
|
}),
|
|
3791
4189
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
4190
|
+
className: "dwa-row-actions",
|
|
4191
|
+
children: [
|
|
4192
|
+
configured && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4193
|
+
type: "button",
|
|
4194
|
+
className: "dwa-btn dwa-btn-quiet",
|
|
4195
|
+
"aria-expanded": open,
|
|
4196
|
+
"aria-label": acp.label(`${open ? "收起" : "管理"} ${displayName}`, `${open ? "Collapse" : "Manage"} ${displayName}`),
|
|
4197
|
+
onClick: () => setExpanded((value) => !value),
|
|
4198
|
+
children: open ? acp.label("收起", "Collapse") : acp.label("管理", "Manage")
|
|
4199
|
+
}),
|
|
4200
|
+
activeAgent?.state === "error" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4201
|
+
className: "dwa-btn",
|
|
4202
|
+
disabled: testing,
|
|
4203
|
+
onClick: () => void handleTest(),
|
|
4204
|
+
children: testing ? acp.label("测试中...", "Testing...") : acp.label("测试", "Test")
|
|
4205
|
+
}),
|
|
4206
|
+
configured && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowMenu, {
|
|
4207
|
+
acp,
|
|
4208
|
+
canStop: activeAgent !== void 0 && activeAgent.state !== "stopped",
|
|
4209
|
+
onStop: () => void acp.stopAgent(detected.id),
|
|
4210
|
+
onRemove: async () => {
|
|
4211
|
+
await acp.deleteAgent(detected.id).catch(() => {});
|
|
4212
|
+
}
|
|
4213
|
+
})
|
|
4214
|
+
]
|
|
3810
4215
|
})
|
|
3811
4216
|
]
|
|
3812
4217
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -3817,42 +4222,52 @@ window.__ModuleLoader__.load({
|
|
|
3817
4222
|
className: "dwa-stderr",
|
|
3818
4223
|
children: stderr.join("\n")
|
|
3819
4224
|
}),
|
|
3820
|
-
|
|
4225
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("nav", {
|
|
4226
|
+
className: "dwa-tabs dwa-detail-tabs",
|
|
4227
|
+
"aria-label": acp.label(`${displayName} 配置`, `${displayName} settings`),
|
|
4228
|
+
children: [
|
|
4229
|
+
configured && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4230
|
+
type: "button",
|
|
4231
|
+
"aria-pressed": detailPage === "models",
|
|
4232
|
+
onClick: () => setDetailPage("models"),
|
|
4233
|
+
children: acp.label("模型", "Models")
|
|
4234
|
+
}),
|
|
4235
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4236
|
+
type: "button",
|
|
4237
|
+
"aria-pressed": detailPage === "connection",
|
|
4238
|
+
onClick: () => setDetailPage("connection"),
|
|
4239
|
+
children: acp.label("连接", "Connection")
|
|
4240
|
+
}),
|
|
4241
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4242
|
+
type: "button",
|
|
4243
|
+
"aria-pressed": detailPage === "advanced",
|
|
4244
|
+
onClick: () => setDetailPage("advanced"),
|
|
4245
|
+
children: acp.label("高级", "Advanced")
|
|
4246
|
+
})
|
|
4247
|
+
]
|
|
4248
|
+
}),
|
|
4249
|
+
configured && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
|
|
3821
4250
|
className: "dwa-subsection",
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
|
|
3825
|
-
className: "dwa-subsection-title",
|
|
3826
|
-
children: acp.label("模型与默认值", "Models & defaults")
|
|
3827
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3828
|
-
className: "dwa-subsection-copy",
|
|
3829
|
-
children: acp.label("检测模型目录,并控制对话中可选择的模型。", "Detect the model catalog and choose what appears in conversations.")
|
|
3830
|
-
})] })
|
|
3831
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelCatalogBlock, {
|
|
4251
|
+
hidden: detailPage !== "models",
|
|
4252
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelCatalogBlock, {
|
|
3832
4253
|
agentId: detected.id,
|
|
3833
4254
|
detected,
|
|
3834
4255
|
acp,
|
|
3835
|
-
active: open,
|
|
4256
|
+
active: active && open && detailPage === "models",
|
|
3836
4257
|
exposed: form.exposed,
|
|
3837
4258
|
onExposedChange: (exposed) => patch({ exposed }),
|
|
3838
4259
|
autoDiscover: form.autoDiscoverModels,
|
|
3839
4260
|
onAutoDiscoverChange: (autoDiscoverModels) => patch({ autoDiscoverModels }),
|
|
3840
4261
|
isDefault
|
|
3841
|
-
})
|
|
4262
|
+
})
|
|
3842
4263
|
}),
|
|
3843
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
4264
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
|
|
3844
4265
|
className: "dwa-subsection",
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
|
|
3848
|
-
className: "dwa-subsection-title",
|
|
3849
|
-
children: acp.label("连接配置", "Connection")
|
|
3850
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3851
|
-
className: "dwa-subsection-copy",
|
|
3852
|
-
children: acp.label("设置显示名与启动命令,高级选项按需展开。", "Set the display name and launch command; expand advanced options only when needed.")
|
|
3853
|
-
})] })
|
|
3854
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AgentDetails, {
|
|
4266
|
+
hidden: detailPage === "models",
|
|
4267
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AgentDetails, {
|
|
3855
4268
|
acp,
|
|
4269
|
+
advancedOpen: detailPage === "advanced",
|
|
4270
|
+
dirty,
|
|
3856
4271
|
detected,
|
|
3857
4272
|
form,
|
|
3858
4273
|
patch,
|
|
@@ -3873,7 +4288,7 @@ window.__ModuleLoader__.load({
|
|
|
3873
4288
|
onUseDefault: handleUseDefault,
|
|
3874
4289
|
onSave: () => void handleSave(),
|
|
3875
4290
|
onTest: () => void handleTest()
|
|
3876
|
-
})
|
|
4291
|
+
})
|
|
3877
4292
|
})
|
|
3878
4293
|
]
|
|
3879
4294
|
})]
|
|
@@ -3976,111 +4391,90 @@ window.__ModuleLoader__.load({
|
|
|
3976
4391
|
return payload;
|
|
3977
4392
|
}
|
|
3978
4393
|
/** The expanded body: connection form, workspace allow-list, env, actions. */
|
|
3979
|
-
function AgentDetails({ acp, detected, form, patch, isConfigured, newCustom, formIncomplete, idValid, idTaken, cwdInvalid, rootsInvalid, idleInvalid, mcpInvalid, saving, savedSuccess, testing, testResult, showSaveWarning, onUseDefault, onSave, onTest }) {
|
|
3980
|
-
useUi$1(acp);
|
|
3981
|
-
const [advancedOpen, setAdvancedOpen] = (0, react.useState)(false);
|
|
4394
|
+
function AgentDetails({ acp, advancedOpen, dirty, detected, form, patch, isConfigured, newCustom, formIncomplete, idValid, idTaken, cwdInvalid, rootsInvalid, idleInvalid, mcpInvalid, saving, savedSuccess, testing, testResult, showSaveWarning, onUseDefault, onSave, onTest }) {
|
|
3982
4395
|
const parsedCommand = splitCommandLine(form.commandLine);
|
|
3983
4396
|
const commandPreview = parsedCommand.command === "" ? acp.label("填整条命令,例如:codebuddy --acp", "Type the whole command, e.g. codebuddy --acp") : `${acp.label("程序", "Program")}: ${parsedCommand.command}` + (parsedCommand.args.length === 0 ? "" : ` ${acp.label("参数", "Arguments")}: ${parsedCommand.args.join(" ")}`);
|
|
3984
4397
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
3985
|
-
newCustom && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3986
|
-
className: "dwa-form-row",
|
|
3987
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3988
|
-
className: "dwa-form-col",
|
|
3989
|
-
children: [
|
|
3990
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
3991
|
-
className: "dwa-form-label",
|
|
3992
|
-
children: acp.label("Agent ID(唯一标识,创建后不可改)", "Agent ID (unique, immutable after creation)")
|
|
3993
|
-
}),
|
|
3994
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3995
|
-
className: "dwa-input dwa-input-mono",
|
|
3996
|
-
value: form.agentId,
|
|
3997
|
-
onChange: (e) => patch({ agentId: e.target.value }),
|
|
3998
|
-
placeholder: "e.g. my-agent"
|
|
3999
|
-
}),
|
|
4000
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4001
|
-
className: idValid && !idTaken ? "dwa-hint" : "dwa-error",
|
|
4002
|
-
children: idTaken ? acp.label("该 ID 已被现有 Agent 占用。", "This id is already taken by a configured agent.") : idValid ? acp.label("小写字母或数字开头,可用 a-z 0-9 . _ -,最长 64 字符。", "Starts with a lowercase letter or digit; a-z 0-9 . _ - allowed; max 64 chars.") : acp.label("ID 格式不合法:小写字母或数字开头,可用 a-z 0-9 . _ -。", "Invalid id: start with a lowercase letter or digit; only a-z 0-9 . _ - allowed.")
|
|
4003
|
-
})
|
|
4004
|
-
]
|
|
4005
|
-
})
|
|
4006
|
-
}),
|
|
4007
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4008
|
-
className: "dwa-form-row",
|
|
4009
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4010
|
-
className: "dwa-form-col",
|
|
4011
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
4012
|
-
className: "dwa-form-label",
|
|
4013
|
-
children: acp.label("显示名", "Display Name")
|
|
4014
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4015
|
-
className: "dwa-input",
|
|
4016
|
-
value: form.title,
|
|
4017
|
-
onChange: (e) => patch({ title: e.target.value }),
|
|
4018
|
-
placeholder: detected.name === "" ? acp.label("我的 Agent", "My Agent") : detected.name
|
|
4019
|
-
})]
|
|
4020
|
-
})
|
|
4021
|
-
}),
|
|
4022
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4023
|
-
className: "dwa-form-row",
|
|
4024
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4025
|
-
className: "dwa-form-col",
|
|
4026
|
-
children: [
|
|
4027
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
4028
|
-
className: "dwa-form-label",
|
|
4029
|
-
children: acp.label("启动命令(程序 + 参数)", "Launch Command (program + arguments)")
|
|
4030
|
-
}),
|
|
4031
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4032
|
-
className: "dwa-input dwa-input-mono",
|
|
4033
|
-
value: form.commandLine,
|
|
4034
|
-
onChange: (e) => patch({ commandLine: e.target.value }),
|
|
4035
|
-
placeholder: detected.defaultCommand === "" ? "e.g. codebuddy --acp" : formatCommandLine(detected.defaultCommand, detected.defaultArgs)
|
|
4036
|
-
}),
|
|
4037
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4038
|
-
className: "dwa-hint",
|
|
4039
|
-
children: commandPreview
|
|
4040
|
-
}),
|
|
4041
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4042
|
-
className: "dwa-hint",
|
|
4043
|
-
children: acp.label("参数直接跟在程序后面即可;路径里含空格时用引号包住整条路径,例如 \"C:\\Program Files\\nodejs\\node.exe\" --acp。", "Arguments go right after the program; quote a whole path that contains spaces, e.g. \"C:\\Program Files\\nodejs\\node.exe\" --acp.")
|
|
4044
|
-
})
|
|
4045
|
-
]
|
|
4046
|
-
})
|
|
4047
|
-
}),
|
|
4048
4398
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4049
|
-
|
|
4050
|
-
display: "flex",
|
|
4051
|
-
alignItems: "center",
|
|
4052
|
-
gap: 8,
|
|
4053
|
-
marginTop: 12,
|
|
4054
|
-
flexWrap: "wrap"
|
|
4055
|
-
},
|
|
4399
|
+
hidden: advancedOpen,
|
|
4056
4400
|
children: [
|
|
4057
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4401
|
+
newCustom && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4402
|
+
className: "dwa-form-row",
|
|
4403
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4404
|
+
className: "dwa-form-col",
|
|
4405
|
+
children: [
|
|
4406
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
4407
|
+
className: "dwa-form-label",
|
|
4408
|
+
children: acp.label("Agent ID(唯一标识,创建后不可改)", "Agent ID (unique, immutable after creation)")
|
|
4409
|
+
}),
|
|
4410
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4411
|
+
className: "dwa-input dwa-input-mono",
|
|
4412
|
+
"aria-label": acp.label("Agent ID", "Agent ID"),
|
|
4413
|
+
value: form.agentId,
|
|
4414
|
+
onChange: (e) => patch({ agentId: e.target.value }),
|
|
4415
|
+
placeholder: "e.g. my-agent"
|
|
4416
|
+
}),
|
|
4417
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4418
|
+
className: idValid && !idTaken ? "dwa-hint" : "dwa-error",
|
|
4419
|
+
children: idTaken ? acp.label("该 ID 已被现有 Agent 占用。", "This id is already taken by a configured agent.") : idValid ? acp.label("小写字母或数字开头,可用 a-z 0-9 . _ -,最长 64 字符。", "Starts with a lowercase letter or digit; a-z 0-9 . _ - allowed; max 64 chars.") : acp.label("ID 格式不合法:小写字母或数字开头,可用 a-z 0-9 . _ -。", "Invalid id: start with a lowercase letter or digit; only a-z 0-9 . _ - allowed.")
|
|
4420
|
+
})
|
|
4421
|
+
]
|
|
4422
|
+
})
|
|
4423
|
+
}),
|
|
4424
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4425
|
+
className: "dwa-form-row",
|
|
4426
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4427
|
+
className: "dwa-form-col",
|
|
4428
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
4429
|
+
className: "dwa-form-label",
|
|
4430
|
+
children: acp.label("显示名", "Display Name")
|
|
4431
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4432
|
+
className: "dwa-input",
|
|
4433
|
+
"aria-label": acp.label("显示名", "Display Name"),
|
|
4434
|
+
value: form.title,
|
|
4435
|
+
onChange: (e) => patch({ title: e.target.value }),
|
|
4436
|
+
placeholder: detected.name === "" ? acp.label("我的 Agent", "My Agent") : detected.name
|
|
4437
|
+
})]
|
|
4438
|
+
})
|
|
4071
4439
|
}),
|
|
4072
|
-
|
|
4073
|
-
className: "dwa-
|
|
4074
|
-
children:
|
|
4440
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4441
|
+
className: "dwa-form-row",
|
|
4442
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4443
|
+
className: "dwa-form-col",
|
|
4444
|
+
children: [
|
|
4445
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
4446
|
+
className: "dwa-form-label",
|
|
4447
|
+
children: acp.label("启动命令(程序 + 参数)", "Launch Command (program + arguments)")
|
|
4448
|
+
}),
|
|
4449
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4450
|
+
className: "dwa-input dwa-input-mono",
|
|
4451
|
+
"aria-label": acp.label("启动命令(程序 + 参数)", "Launch Command (program + arguments)"),
|
|
4452
|
+
value: form.commandLine,
|
|
4453
|
+
onChange: (e) => patch({ commandLine: e.target.value }),
|
|
4454
|
+
placeholder: detected.defaultCommand === "" ? "e.g. codebuddy --acp" : formatCommandLine(detected.defaultCommand, detected.defaultArgs)
|
|
4455
|
+
}),
|
|
4456
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4457
|
+
className: "dwa-hint",
|
|
4458
|
+
children: commandPreview
|
|
4459
|
+
}),
|
|
4460
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4461
|
+
className: "dwa-hint",
|
|
4462
|
+
children: acp.label("含空格的程序路径请加引号。", "Quote the program path if it contains spaces.")
|
|
4463
|
+
})
|
|
4464
|
+
]
|
|
4465
|
+
})
|
|
4075
4466
|
}),
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4467
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkspaceBlock, {
|
|
4468
|
+
acp,
|
|
4469
|
+
form,
|
|
4470
|
+
patch,
|
|
4471
|
+
cwdInvalid,
|
|
4472
|
+
rootsInvalid
|
|
4079
4473
|
})
|
|
4080
4474
|
]
|
|
4081
4475
|
}),
|
|
4082
4476
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4083
|
-
|
|
4477
|
+
hidden: !advancedOpen,
|
|
4084
4478
|
children: [
|
|
4085
4479
|
!newCustom && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4086
4480
|
className: "dwa-default-hint",
|
|
@@ -4125,13 +4519,6 @@ window.__ModuleLoader__.load({
|
|
|
4125
4519
|
})]
|
|
4126
4520
|
})
|
|
4127
4521
|
}),
|
|
4128
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkspaceBlock, {
|
|
4129
|
-
acp,
|
|
4130
|
-
form,
|
|
4131
|
-
patch,
|
|
4132
|
-
cwdInvalid,
|
|
4133
|
-
rootsInvalid
|
|
4134
|
-
}),
|
|
4135
4522
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4136
4523
|
className: "dwa-form-row",
|
|
4137
4524
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -4143,19 +4530,14 @@ window.__ModuleLoader__.load({
|
|
|
4143
4530
|
}),
|
|
4144
4531
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4145
4532
|
className: "dwa-input dwa-input-mono",
|
|
4533
|
+
"aria-label": acp.label("空闲释放(毫秒)", "Idle Release (ms)"),
|
|
4146
4534
|
value: form.idleStr,
|
|
4147
4535
|
onChange: (e) => patch({ idleStr: e.target.value }),
|
|
4148
4536
|
placeholder: acp.label(`留空 = 宿主默认(承载会话 ${String(DEFAULT_IDLE_RELEASE_MS / 6e4)} 分钟 / 探测进程 ${String(DEFAULT_PROBE_RELEASE_MS / 6e4)} 分钟)`, `Blank = host default (${String(DEFAULT_IDLE_RELEASE_MS / 6e4)} min for a chat process / ${String(DEFAULT_PROBE_RELEASE_MS / 6e4)} min for a probe)`)
|
|
4149
4537
|
}),
|
|
4150
4538
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4151
4539
|
className: idleInvalid ? "dwa-error" : "dwa-hint",
|
|
4152
|
-
children: idleInvalid ? acp.label("必须是 0(永不释放)或 [1000, 86400000] 之间的整数毫秒。", "Must be 0 (never release) or an integer in [1000, 86400000] ms.") : /* @__PURE__ */ (0, react_jsx_runtime.
|
|
4153
|
-
acp.label("空闲超过此时长就挂起进程(会话保留,下一条消息自动恢复)。", "The process is parked once it has been idle this long (the session is kept and resumes on the next message)."),
|
|
4154
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("br", {}),
|
|
4155
|
-
acp.label("0 = 永不释放;回合在跑、取消未结算或审批待答时不释放。", "0 = never; a process with a running turn, an unsettled cancel, or a pending approval is never released."),
|
|
4156
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("br", {}),
|
|
4157
|
-
acp.label("只对承载过会话的进程生效;探测进程固定 5 分钟释放,填 0 也拦不住。", "This window applies only to a process that has hosted a session; the model-probe process is always released after 5 minutes, and 0 does not stop it.")
|
|
4158
|
-
] })
|
|
4540
|
+
children: idleInvalid ? acp.label("必须是 0(永不释放)或 [1000, 86400000] 之间的整数毫秒。", "Must be 0 (never release) or an integer in [1000, 86400000] ms.") : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: acp.label("承载过会话的进程空闲后挂起;0 不释放,探测进程固定 5 分钟。", "Park idle chat processes; 0 keeps them alive. Probe processes always release after 5 minutes.") })
|
|
4159
4541
|
})
|
|
4160
4542
|
]
|
|
4161
4543
|
})
|
|
@@ -4245,6 +4627,7 @@ window.__ModuleLoader__.load({
|
|
|
4245
4627
|
minHeight: 96,
|
|
4246
4628
|
resize: "vertical"
|
|
4247
4629
|
},
|
|
4630
|
+
"aria-label": acp.label("MCP 服务器(JSON)", "MCP Servers (JSON)"),
|
|
4248
4631
|
value: form.mcpText,
|
|
4249
4632
|
onChange: (e) => patch({ mcpText: e.target.value }),
|
|
4250
4633
|
spellCheck: false,
|
|
@@ -4256,15 +4639,29 @@ window.__ModuleLoader__.load({
|
|
|
4256
4639
|
}),
|
|
4257
4640
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4258
4641
|
className: "dwa-hint",
|
|
4259
|
-
children: acp.label("
|
|
4642
|
+
children: acp.label("额外追加给智能体的 MCP 服务器,不影响其已有配置。", "Additional MCP servers for the agent; its own configuration is unchanged.")
|
|
4260
4643
|
})
|
|
4261
4644
|
]
|
|
4262
4645
|
})
|
|
4263
4646
|
]
|
|
4264
4647
|
}),
|
|
4648
|
+
!advancedOpen && (mcpInvalid || idleInvalid) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4649
|
+
className: "dwa-error",
|
|
4650
|
+
role: "alert",
|
|
4651
|
+
children: acp.label("请检查「高级」中的无效配置。", "Check the invalid settings in Advanced.")
|
|
4652
|
+
}),
|
|
4653
|
+
advancedOpen && (!idValid || idTaken || cwdInvalid || rootsInvalid || parsedCommand.command === "") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4654
|
+
className: "dwa-error",
|
|
4655
|
+
role: "alert",
|
|
4656
|
+
children: acp.label("请检查「连接」中的未完成或无效配置。", "Check the incomplete or invalid settings in Connection.")
|
|
4657
|
+
}),
|
|
4265
4658
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4266
4659
|
className: "dwa-form-actions",
|
|
4267
4660
|
children: [
|
|
4661
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4662
|
+
className: "dwa-hint",
|
|
4663
|
+
children: isConfigured ? dirty ? acp.label("有未保存的更改", "Unsaved changes") : acp.label("配置已保存", "Settings saved") : ""
|
|
4664
|
+
}),
|
|
4268
4665
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4269
4666
|
className: "dwa-btn",
|
|
4270
4667
|
onClick: onTest,
|
|
@@ -4275,8 +4672,8 @@ window.__ModuleLoader__.load({
|
|
|
4275
4672
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4276
4673
|
className: "dwa-btn dwa-btn-primary",
|
|
4277
4674
|
onClick: onSave,
|
|
4278
|
-
disabled: saving || testing || formIncomplete,
|
|
4279
|
-
children: saving ? acp.label("保存中...", "Saving...") : savedSuccess ? acp.label("✓ 已保存", "✓ Saved") : isConfigured ? acp.label("
|
|
4675
|
+
disabled: saving || testing || formIncomplete || isConfigured && !dirty,
|
|
4676
|
+
children: saving ? acp.label("保存中...", "Saving...") : savedSuccess ? acp.label("✓ 已保存", "✓ Saved") : isConfigured ? acp.label("保存更改", "Save changes") : acp.label("保存并启用", "Save & Enable")
|
|
4280
4677
|
}),
|
|
4281
4678
|
showSaveWarning && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4282
4679
|
className: "dwa-hint",
|
|
@@ -4352,7 +4749,7 @@ window.__ModuleLoader__.load({
|
|
|
4352
4749
|
}),
|
|
4353
4750
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4354
4751
|
className: "dwa-hint",
|
|
4355
|
-
children: acp.label("
|
|
4752
|
+
children: acp.label("聊天使用会话工作区;此处用于直连会话或宿主未提供工作区时。", "Chats use their session workspace; this applies to direct sessions or when the host provides no workspace.")
|
|
4356
4753
|
}),
|
|
4357
4754
|
!form.rootsOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4358
4755
|
className: "dwa-hint",
|
|
@@ -4721,7 +5118,7 @@ window.__ModuleLoader__.load({
|
|
|
4721
5118
|
fontWeight: 400
|
|
4722
5119
|
},
|
|
4723
5120
|
title: acp.label("NTR 模式下的对话只列出这里勾选的模型;未勾选的仍可用——正在生效的那个也会以「· 当前」列出来,其余不列出。", "The NTR surfaces only list what is checked here; unchecked models still work, and the one currently in force is still listed with a \"· current\" row — the rest are not offered."),
|
|
4724
|
-
children: acp.label("
|
|
5121
|
+
children: acp.label("仅影响菜单可见性", "Menu visibility only")
|
|
4725
5122
|
})]
|
|
4726
5123
|
}),
|
|
4727
5124
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -4743,6 +5140,7 @@ window.__ModuleLoader__.load({
|
|
|
4743
5140
|
children: probing ? acp.label("模型检测中...", "Probing models...") : acp.label("检测可用模型", "Detect available models")
|
|
4744
5141
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4745
5142
|
className: "dwa-input dwa-model-search",
|
|
5143
|
+
"aria-label": acp.label("搜索模型", "Search models"),
|
|
4746
5144
|
value: search,
|
|
4747
5145
|
onChange: (e) => setSearch(e.target.value),
|
|
4748
5146
|
placeholder: acp.label("搜索模型…", "Search models…")
|
|
@@ -4860,7 +5258,7 @@ window.__ModuleLoader__.load({
|
|
|
4860
5258
|
className: "dwa-model-list",
|
|
4861
5259
|
children: [selectedChoices.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4862
5260
|
className: "dwa-hint dwa-model-empty",
|
|
4863
|
-
children: acp.label("
|
|
5261
|
+
children: acp.label("尚未选择模型,从「全部模型」中加入。", "No models selected. Add from All models.")
|
|
4864
5262
|
}), selectedChoices.map((choice) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
4865
5263
|
type: "button",
|
|
4866
5264
|
className: "dwa-model-row is-on",
|