dsh-ntr 0.2.1 → 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 +4 -4
- package/README.md +4 -4
- package/cordis.patch.yml +12 -0
- package/lib/bridge.js +640 -62
- package/lib/client/panel.js +130 -2
- package/lib/client/store.js +133 -1
- package/lib/client.js +302 -6
- 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 +205 -3
- 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 +1 -1
- package/src/bridge.ts +684 -61
- package/src/client/panel.tsx +215 -3
- 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 {
|
|
@@ -2638,7 +2753,7 @@ window.__ModuleLoader__.load({
|
|
|
2638
2753
|
}
|
|
2639
2754
|
.dwa-page-header { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 28px; }
|
|
2640
2755
|
.dwa-page-heading { min-width: 0; }
|
|
2641
|
-
.dwa-page-title { margin: 0; font-size: 20px; line-height: 1.35; font-weight: 550; letter-spacing: -0.02em; }
|
|
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; }
|
|
2642
2757
|
.dwa-page-description { margin: 5px 0 0; color: var(--ntr-muted); font-size: var(--ntr-font-sm); }
|
|
2643
2758
|
.dwa-btn {
|
|
2644
2759
|
min-height: 32px; box-sizing: border-box; font: inherit; border-radius: var(--ntr-radius-sm);
|
|
@@ -2670,6 +2785,20 @@ window.__ModuleLoader__.load({
|
|
|
2670
2785
|
.dwa-badge-success { background: var(--dsw-alias-state-success-tertiary, #dcfce7); color: var(--ntr-success); }
|
|
2671
2786
|
.dwa-badge-warn { background: var(--dsw-alias-state-warn-tertiary, #fef3c7); color: var(--ntr-warn); }
|
|
2672
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; }
|
|
2673
2802
|
.dwa-dot { width: 7px; height: 7px; border-radius: 50%; display: inline-block; flex-shrink: 0; }
|
|
2674
2803
|
.dwa-agent-list { display: flex; flex-direction: column; border-top: var(--ntr-line); }
|
|
2675
2804
|
.dwa-agent-card { border-bottom: var(--ntr-line); min-width: 0; }
|
|
@@ -3320,6 +3449,139 @@ window.__ModuleLoader__.load({
|
|
|
3320
3449
|
})]
|
|
3321
3450
|
});
|
|
3322
3451
|
}
|
|
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
|
+
}
|
|
3323
3585
|
function AcpSettingsSection(props) {
|
|
3324
3586
|
const acp = props.acp;
|
|
3325
3587
|
ensureStyle();
|
|
@@ -3328,6 +3590,10 @@ window.__ModuleLoader__.load({
|
|
|
3328
3590
|
const [page, setPage] = (0, react.useState)("agents");
|
|
3329
3591
|
const [addOpen, setAddOpen] = (0, react.useState)(false);
|
|
3330
3592
|
const [addTarget, setAddTarget] = (0, react.useState)(void 0);
|
|
3593
|
+
const [updateOpen, setUpdateOpen] = (0, react.useState)(false);
|
|
3594
|
+
(0, react.useEffect)(() => {
|
|
3595
|
+
acp.checkPluginUpdate();
|
|
3596
|
+
}, [acp]);
|
|
3331
3597
|
const { configured, available } = partitionAgents(ui.detectedAgents, ui.agents);
|
|
3332
3598
|
const selected = addTarget ?? available[0] ?? NEW_AGENT_SEED;
|
|
3333
3599
|
const openAdd = () => {
|
|
@@ -3335,6 +3601,9 @@ window.__ModuleLoader__.load({
|
|
|
3335
3601
|
setPage("add");
|
|
3336
3602
|
};
|
|
3337
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";
|
|
3338
3607
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3339
3608
|
className: "dwa-root",
|
|
3340
3609
|
children: [
|
|
@@ -3342,9 +3611,31 @@ window.__ModuleLoader__.load({
|
|
|
3342
3611
|
className: "dwa-page-header",
|
|
3343
3612
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3344
3613
|
className: "dwa-page-heading",
|
|
3345
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3614
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h2", {
|
|
3346
3615
|
className: "dwa-page-title",
|
|
3347
|
-
|
|
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
|
+
]
|
|
3348
3639
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3349
3640
|
className: "dwa-page-description",
|
|
3350
3641
|
children: acp.label("连接智能体,设置你的对话偏好。", "Connect agents and set your conversation preferences.")
|
|
@@ -3356,6 +3647,11 @@ window.__ModuleLoader__.load({
|
|
|
3356
3647
|
children: acp.label("添加智能体", "Add agent")
|
|
3357
3648
|
})]
|
|
3358
3649
|
}),
|
|
3650
|
+
update !== void 0 && updateCardVisible(update, updateOpen) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PluginUpdateCard, {
|
|
3651
|
+
acp,
|
|
3652
|
+
update,
|
|
3653
|
+
onClose: () => setUpdateOpen(false)
|
|
3654
|
+
}),
|
|
3359
3655
|
ledger.visible && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3360
3656
|
className: "dwa-card dwa-card-warn",
|
|
3361
3657
|
style: { marginBottom: 16 },
|