dsh-ntr 0.1.6 → 0.2.1
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 +6 -3
- package/README.md +6 -3
- package/cordis.patch.yml +18 -18
- package/lib/bridge.js +134 -314
- package/lib/client/acp-ui.js +60 -32
- package/lib/client/index.js +17 -0
- package/lib/client/panel.js +127 -114
- package/lib/client/permission-dock.js +72 -0
- package/lib/client/session-controls.js +4 -4
- package/lib/client/store.js +58 -12
- package/lib/client.js +696 -393
- package/lib/client.js.map +1 -1
- package/lib/impl.js +30 -19
- package/lib/index.js +6 -51
- package/lib/types/bridge.d.ts +63 -157
- package/lib/types/client/panel.d.ts +12 -20
- package/lib/types/client/permission-dock.d.ts +31 -0
- package/lib/types/client/store.d.ts +42 -12
- package/lib/types/impl.d.ts +31 -17
- package/lib/types/protocol.d.ts +27 -12
- package/package.json +5 -1
- package/src/bridge.ts +163 -379
- package/src/client/acp-ui.tsx +60 -32
- package/src/client/index.tsx +18 -0
- package/src/client/panel.tsx +243 -258
- package/src/client/permission-dock.tsx +133 -0
- package/src/client/session-controls.tsx +4 -4
- package/src/client/store.ts +81 -25
- package/src/impl.ts +49 -29
- package/src/index.ts +6 -65
- package/src/protocol.ts +32 -12
package/lib/client.js
CHANGED
|
@@ -14,6 +14,36 @@ window.__ModuleLoader__.load({
|
|
|
14
14
|
};
|
|
15
15
|
//#endregion
|
|
16
16
|
//#region src/client/store.ts
|
|
17
|
+
/** Returned by {@link deadlineRemainingLabel} once the deadline has passed. */
|
|
18
|
+
const PERMISSION_DEADLINE_EXPIRED = "expired";
|
|
19
|
+
/**
|
|
20
|
+
* The asks that belong to one DSH chat conversation. An ask without a
|
|
21
|
+
* `dshSessionId` belongs to no conversation (an `/acp` RPC-only session), so it
|
|
22
|
+
* is deliberately absent from every conversation's dock and stays in the
|
|
23
|
+
* settings-panel ledger.
|
|
24
|
+
*/
|
|
25
|
+
function permissionsForSession(permissions, dshSessionId) {
|
|
26
|
+
return permissions.filter((permission) => permission.dshSessionId === dshSessionId);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Compact countdown for one ask, or `undefined` when there is nothing to count
|
|
30
|
+
* down (`wait` mode, or a frame without a deadline). Pure so the formatting is
|
|
31
|
+
* testable without a clock: the dock passes `Date.now()` on its tick.
|
|
32
|
+
*
|
|
33
|
+
* Past the deadline the answer is {@link PERMISSION_DEADLINE_EXPIRED} rather
|
|
34
|
+
* than a negative number — the host has already armed the expiry, and a card
|
|
35
|
+
* counting backwards would claim a deadline that no longer exists.
|
|
36
|
+
*/
|
|
37
|
+
function deadlineRemainingLabel(deadlineAt, now, mode) {
|
|
38
|
+
if (mode === "wait" || deadlineAt === void 0) return void 0;
|
|
39
|
+
const remainingMs = deadlineAt - now;
|
|
40
|
+
if (remainingMs <= 0) return PERMISSION_DEADLINE_EXPIRED;
|
|
41
|
+
const seconds = Math.ceil(remainingMs / 1e3);
|
|
42
|
+
if (seconds < 60) return `${String(seconds)}s`;
|
|
43
|
+
const minutes = Math.floor(seconds / 60);
|
|
44
|
+
const rest = seconds % 60;
|
|
45
|
+
return rest === 0 ? `${String(minutes)}m` : `${String(minutes)}m ${String(rest)}s`;
|
|
46
|
+
}
|
|
17
47
|
const MAX_BLOCKS = 400;
|
|
18
48
|
/** How many observed ACP transcripts stay live at once (insertion-ordered eviction). */
|
|
19
49
|
const MAX_WATCHED = 6;
|
|
@@ -284,7 +314,6 @@ window.__ModuleLoader__.load({
|
|
|
284
314
|
seatCatalogs: {},
|
|
285
315
|
probingModels: {},
|
|
286
316
|
probeErrors: {},
|
|
287
|
-
approvalRouted: false,
|
|
288
317
|
chatSessions: [],
|
|
289
318
|
tagHalo: { ...DEFAULT_TAG_HALO },
|
|
290
319
|
approvalDeadlines: void 0,
|
|
@@ -470,7 +499,7 @@ window.__ModuleLoader__.load({
|
|
|
470
499
|
/** Snapshot refresh used on panel open and after a stream outage. */
|
|
471
500
|
async resync() {
|
|
472
501
|
try {
|
|
473
|
-
const [{ agents
|
|
502
|
+
const [{ agents }, { sessions }, defaultAgentInfo, detectResult, presetResult, tagHaloResult, deadlinesResult] = await Promise.all([
|
|
474
503
|
this.call("agents/list"),
|
|
475
504
|
this.call("sessions/list"),
|
|
476
505
|
this.call("default/agent").catch(() => ({})),
|
|
@@ -486,7 +515,6 @@ window.__ModuleLoader__.load({
|
|
|
486
515
|
sessions,
|
|
487
516
|
defaultAgent: defaultAgentInfo?.agentId,
|
|
488
517
|
detectedAgents,
|
|
489
|
-
approvalRouted: approvalRouted === true,
|
|
490
518
|
preset: presetResult?.preset ?? void 0,
|
|
491
519
|
tagHalo: tagHaloResult?.halo ?? { ...DEFAULT_TAG_HALO },
|
|
492
520
|
approvalDeadlines: deadlinesResult.deadlines
|
|
@@ -1113,6 +1141,14 @@ window.__ModuleLoader__.load({
|
|
|
1113
1141
|
this.flashError(error);
|
|
1114
1142
|
}
|
|
1115
1143
|
}
|
|
1144
|
+
/**
|
|
1145
|
+
* Answer one ask (`optionId` absent = cancel it). A failure is reported
|
|
1146
|
+
* through the store's notice — the settings panel renders that — AND
|
|
1147
|
+
* rethrown, so the conversation dock can pin the message next to the card
|
|
1148
|
+
* that failed instead of leaving it on a settings page the user may not
|
|
1149
|
+
* have open. Callers that cannot show it (the settings panel) swallow it
|
|
1150
|
+
* after the notice.
|
|
1151
|
+
*/
|
|
1116
1152
|
async respondPermission(requestId, optionId) {
|
|
1117
1153
|
try {
|
|
1118
1154
|
await this.call("permission/respond", {
|
|
@@ -1121,6 +1157,7 @@ window.__ModuleLoader__.load({
|
|
|
1121
1157
|
});
|
|
1122
1158
|
} catch (error) {
|
|
1123
1159
|
this.flashError(error);
|
|
1160
|
+
throw error;
|
|
1124
1161
|
}
|
|
1125
1162
|
}
|
|
1126
1163
|
async stopAgent(agentId) {
|
|
@@ -1437,13 +1474,17 @@ window.__ModuleLoader__.load({
|
|
|
1437
1474
|
return this.loadAgentCatalog(event.agentId);
|
|
1438
1475
|
}
|
|
1439
1476
|
case "permission/request": {
|
|
1440
|
-
const
|
|
1441
|
-
this.mutate({ permissions: [...this.state.permissions.filter((p) => p.requestId !== event.requestId), {
|
|
1477
|
+
const permission = {
|
|
1442
1478
|
requestId: event.requestId,
|
|
1443
1479
|
sessionId: event.sessionId,
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1480
|
+
...event.dshSessionId === void 0 ? {} : { dshSessionId: event.dshSessionId },
|
|
1481
|
+
toolName: event.toolName,
|
|
1482
|
+
...event.reason === void 0 ? {} : { reason: event.reason },
|
|
1483
|
+
options: event.options,
|
|
1484
|
+
timeoutMode: event.timeoutMode,
|
|
1485
|
+
...event.deadlineAt === void 0 ? {} : { deadlineAt: event.deadlineAt }
|
|
1486
|
+
};
|
|
1487
|
+
this.mutate({ permissions: [...this.state.permissions.filter((p) => p.requestId !== event.requestId), permission] });
|
|
1447
1488
|
return Promise.resolve();
|
|
1448
1489
|
}
|
|
1449
1490
|
case "permission/resolved":
|
|
@@ -2380,9 +2421,9 @@ window.__ModuleLoader__.load({
|
|
|
2380
2421
|
.ntr-acp-seat:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-active, #0000000d); }
|
|
2381
2422
|
.ntr-acp-seat:disabled { opacity: 0.5; cursor: default; }
|
|
2382
2423
|
.ntr-acp-seat.is-open { border-color: var(--dsw-alias-state-business-primary, #2563eb); color: var(--dsw-alias-state-business-primary, #2563eb); }
|
|
2383
|
-
.ntr-acp-seat.is-detached { border-color: var(--
|
|
2424
|
+
.ntr-acp-seat.is-detached { border-color: var(--dsw-alias-state-warn-label, #d97706); color: var(--dsw-alias-state-warn-label, #d97706); }
|
|
2384
2425
|
.ntr-acp-seat-main { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2385
|
-
.ntr-acp-seat-sub { color: var(--dsw-alias-
|
|
2426
|
+
.ntr-acp-seat-sub { color: var(--dsw-alias-label-secondary, #6b7280); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2386
2427
|
.ntr-acp-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
|
|
2387
2428
|
.ntr-acp-tick { margin-left: auto; color: var(--dsw-alias-state-business-primary, #2563eb); }
|
|
2388
2429
|
.ntr-acp-check { display: inline-flex; align-items: center; justify-content: center; flex: none; width: 13px; height: 13px; border: 1px solid var(--dsw-alias-border-l2, #d1d5db); border-radius: 3px; font-size: 10px; line-height: 1; color: var(--dsw-alias-state-business-primary, #2563eb); }
|
|
@@ -2391,80 +2432,108 @@ window.__ModuleLoader__.load({
|
|
|
2391
2432
|
.ntr-acp-menu-head { padding: 8px 10px 6px; font-weight: 600; display: flex; align-items: center; gap: 6px; }
|
|
2392
2433
|
.ntr-acp-menu-title { flex: 1; }
|
|
2393
2434
|
.ntr-acp-menu-spin { opacity: 0.5; }
|
|
2394
|
-
.ntr-acp-menu-note { padding: 0 10px 6px; font-size: 11px; color: var(--dsw-alias-
|
|
2395
|
-
.ntr-acp-menu-error { margin: 0 10px 6px; padding: 6px 8px; border-radius: 6px; background: #
|
|
2435
|
+
.ntr-acp-menu-note { padding: 0 10px 6px; font-size: 11px; color: var(--dsw-alias-label-secondary, #6b7280); line-height: 1.5; }
|
|
2436
|
+
.ntr-acp-menu-error { margin: 0 10px 6px; padding: 6px 8px; border-radius: 6px; background: color-mix(in srgb, var(--dsw-alias-state-error-primary, #b91c1c) 12%, transparent); color: var(--dsw-alias-state-error-primary, #b91c1c); font-size: 11px; }
|
|
2396
2437
|
.ntr-acp-menu-body { overflow: auto; padding: 0 4px 6px; }
|
|
2397
2438
|
.ntr-acp-menu-section { display: flex; flex-direction: column; padding-top: 4px; }
|
|
2398
|
-
.ntr-acp-menu-section-title { padding: 6px 8px 4px; font-size: 10px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--dsw-alias-
|
|
2439
|
+
.ntr-acp-menu-section-title { padding: 6px 8px 4px; font-size: 10px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--dsw-alias-label-secondary, #6b7280); }
|
|
2399
2440
|
.ntr-acp-menu-item { display: flex; align-items: center; gap: 6px; font: inherit; font-size: 12px; text-align: left; padding: 6px 8px; border: none; border-radius: 6px; background: none; color: inherit; cursor: pointer; width: 100%; }
|
|
2400
2441
|
.ntr-acp-menu-item:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-active, #0000000d); }
|
|
2401
2442
|
.ntr-acp-menu-item:disabled { opacity: 0.45; cursor: default; }
|
|
2402
2443
|
.ntr-acp-menu-item.is-active { font-weight: 600; }
|
|
2403
2444
|
.ntr-acp-menu-item-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2404
|
-
.ntr-acp-menu-item-detail { color: var(--dsw-alias-
|
|
2405
|
-
.ntr-acp-menu-empty { padding: 10px; text-align: center; color: var(--dsw-alias-
|
|
2445
|
+
.ntr-acp-menu-item-detail { color: var(--dsw-alias-label-secondary, #6b7280); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; text-align: right; }
|
|
2446
|
+
.ntr-acp-menu-empty { padding: 10px; text-align: center; color: var(--dsw-alias-label-secondary, #6b7280); }
|
|
2406
2447
|
/* ---- ACP view tab ---- */
|
|
2407
2448
|
.ntr-acp-view { display: flex; flex-direction: column; height: 100%; min-height: 0; font-size: 13px; line-height: 1.6; }
|
|
2408
|
-
.ntr-acp-view-head { display: flex; align-items: center; gap: 8px; padding: 8px 12px; border-bottom: 1px solid var(--dsw-alias-border-l2, #e5e7eb); font-size: 12px; color: var(--dsw-alias-
|
|
2449
|
+
.ntr-acp-view-head { display: flex; align-items: center; gap: 8px; padding: 8px 12px; border-bottom: 1px solid var(--dsw-alias-border-l2, #e5e7eb); font-size: 12px; color: var(--dsw-alias-label-secondary, #6b7280); }
|
|
2409
2450
|
.ntr-acp-view-agent { font-weight: 600; color: inherit; }
|
|
2410
2451
|
.ntr-acp-view-meta { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 40%; direction: rtl; text-align: left; }
|
|
2411
2452
|
.ntr-acp-view-head .ntr-acp-more { margin-left: auto; }
|
|
2412
2453
|
.ntr-acp-stream { flex: 1; min-height: 0; overflow: auto; padding: 12px 14px 24px; display: flex; flex-direction: column; gap: 10px; }
|
|
2413
2454
|
.ntr-acp-badge { font-size: 11px; padding: 1px 8px; border-radius: 999px; border: 1px solid transparent; }
|
|
2414
|
-
.ntr-acp-badge.is-done { color: #
|
|
2415
|
-
.ntr-acp-badge.is-busy { color: #1d4ed8; background: #dbeafe; }
|
|
2416
|
-
.ntr-acp-badge.is-warn { color: #b45309; background: #fef3c7; }
|
|
2417
|
-
.ntr-acp-badge.is-fail { color: #b91c1c; background: #
|
|
2418
|
-
.ntr-acp-badge.is-idle { color: var(--dsw-alias-
|
|
2455
|
+
.ntr-acp-badge.is-done { color: color-mix(in srgb, var(--dsw-alias-state-success-primary, #22c55e) 72%, var(--dsw-alias-label-primary, #111827)); background: var(--dsw-alias-state-success-tertiary, #dcfce7); }
|
|
2456
|
+
.ntr-acp-badge.is-busy { color: var(--dsw-alias-state-business-primary, #1d4ed8); background: var(--dsw-alias-state-business-tertiary, #dbeafe); }
|
|
2457
|
+
.ntr-acp-badge.is-warn { color: var(--dsw-alias-state-warn-label, #b45309); background: var(--dsw-alias-state-warn-tertiary, #fef3c7); }
|
|
2458
|
+
.ntr-acp-badge.is-fail { color: var(--dsw-alias-state-error-primary, #b91c1c); background: color-mix(in srgb, var(--dsw-alias-state-error-primary, #b91c1c) 12%, transparent); }
|
|
2459
|
+
.ntr-acp-badge.is-idle { color: var(--dsw-alias-label-secondary, #6b7280); background: var(--dsw-alias-bg-layer-2, #f3f4f6); }
|
|
2419
2460
|
.ntr-acp-bubble { max-width: 88%; padding: 8px 12px; border-radius: 12px; white-space: pre-wrap; word-break: break-word; }
|
|
2420
2461
|
.ntr-acp-bubble.is-user { align-self: flex-end; background: color-mix(in srgb, var(--dsw-alias-state-business-primary, #2563eb) 12%, transparent); }
|
|
2421
2462
|
.ntr-acp-bubble.is-agent { align-self: flex-start; background: var(--dsw-alias-bg-layer-2, #f3f4f6); }
|
|
2422
2463
|
.ntr-acp-inline-code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; padding: 1px 4px; border-radius: 4px; background: color-mix(in srgb, currentColor 10%, transparent); }
|
|
2423
2464
|
.ntr-acp-code { margin: 6px 0; padding: 8px 10px; border-radius: 8px; background: #0f172a; color: #e2e8f0; overflow: auto; font-size: 12px; line-height: 1.5; }
|
|
2424
|
-
.ntr-acp-thought { border-left: 3px solid var(--dsw-alias-border-l2, #d1d5db); padding-left: 8px; color: var(--dsw-alias-
|
|
2465
|
+
.ntr-acp-thought { border-left: 3px solid var(--dsw-alias-border-l2, #d1d5db); padding-left: 8px; color: var(--dsw-alias-label-secondary, #6b7280); font-size: 12px; }
|
|
2425
2466
|
.ntr-acp-thought > summary { cursor: pointer; font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase; }
|
|
2426
2467
|
.ntr-acp-thought-body { white-space: pre-wrap; padding: 4px 0 2px; }
|
|
2427
2468
|
.ntr-acp-tool { border: 1px solid var(--dsw-alias-border-l2, #e5e7eb); border-radius: 10px; background: var(--dsw-alias-bg-layer-1, #fff); overflow: hidden; }
|
|
2428
|
-
.ntr-acp-tool.is-fail { border-color: #fca5a5; }
|
|
2469
|
+
.ntr-acp-tool.is-fail { border-color: var(--dsw-alias-state-error-secondary, #fca5a5); }
|
|
2429
2470
|
.ntr-acp-tool-head { display: flex; align-items: center; gap: 8px; padding: 7px 10px; font-size: 12px; }
|
|
2430
2471
|
.ntr-acp-tool-title { flex: 1; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2431
2472
|
.ntr-acp-tool-body { margin: 0; padding: 8px 10px; border-top: 1px solid var(--dsw-alias-border-l2, #e5e7eb); background: var(--dsw-alias-bg-layer-2, #f9fafb); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11.5px; line-height: 1.55; white-space: pre-wrap; word-break: break-word; max-height: 340px; overflow: auto; }
|
|
2432
|
-
.ntr-acp-tool-input { background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-
|
|
2433
|
-
.ntr-acp-tool-meta { font-size: 11px; color: var(--dsw-alias-
|
|
2473
|
+
.ntr-acp-tool-input { background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #111827); max-height: 240px; }
|
|
2474
|
+
.ntr-acp-tool-meta { font-size: 11px; color: var(--dsw-alias-label-secondary, #6b7280); }
|
|
2434
2475
|
.ntr-acp-diff { border-top: 1px solid var(--dsw-alias-border-l2, #e5e7eb); }
|
|
2435
2476
|
.ntr-acp-diff-head { display: flex; align-items: center; gap: 8px; padding: 5px 10px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11.5px; background: var(--dsw-alias-bg-layer-2, #f9fafb); }
|
|
2436
2477
|
.ntr-acp-diff-path { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2437
|
-
.ntr-acp-diff-stats .is-add { color: #15803d; }
|
|
2438
|
-
.ntr-acp-diff-stats .is-del { color: #b91c1c; }
|
|
2478
|
+
.ntr-acp-diff-stats .is-add { color: var(--dsw-alias-state-success-primary, #15803d); }
|
|
2479
|
+
.ntr-acp-diff-stats .is-del { color: var(--dsw-alias-state-error-primary, #b91c1c); }
|
|
2439
2480
|
.ntr-acp-diff-body { max-height: 360px; overflow: auto; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11.5px; line-height: 1.55; }
|
|
2440
2481
|
.ntr-acp-diff-row { display: flex; gap: 8px; padding: 0 10px; white-space: pre; }
|
|
2441
|
-
.ntr-acp-diff-row.is-add { background: #dcfce7; }
|
|
2442
|
-
.ntr-acp-diff-row.is-del { background: #fee2e2; }
|
|
2443
|
-
.ntr-acp-diff-row.is-ctx { color: var(--dsw-alias-
|
|
2482
|
+
.ntr-acp-diff-row.is-add { background: var(--dsw-alias-file-diff-added-bg, #dcfce7); }
|
|
2483
|
+
.ntr-acp-diff-row.is-del { background: var(--dsw-alias-file-diff-deleted-bg, #fee2e2); }
|
|
2484
|
+
.ntr-acp-diff-row.is-ctx { color: var(--dsw-alias-label-secondary, #6b7280); }
|
|
2444
2485
|
.ntr-acp-diff-sign { width: 1ch; flex: none; opacity: 0.7; }
|
|
2445
2486
|
.ntr-acp-diff-text { overflow-x: auto; }
|
|
2446
|
-
.ntr-acp-diff-note { padding: 4px 10px 6px; font-size: 11px; color: var(--dsw-alias-
|
|
2487
|
+
.ntr-acp-diff-note { padding: 4px 10px 6px; font-size: 11px; color: var(--dsw-alias-label-secondary, #6b7280); }
|
|
2447
2488
|
.ntr-acp-more { font: inherit; font-size: 11.5px; padding: 3px 10px; border-radius: 6px; border: 1px solid var(--dsw-alias-border-l2, #d1d5db); background: var(--dsw-alias-bg-layer-2, #f3f4f6); color: inherit; cursor: pointer; }
|
|
2448
2489
|
.ntr-acp-more:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-active, #0000000d); }
|
|
2449
2490
|
.ntr-acp-more:disabled { opacity: 0.5; cursor: default; }
|
|
2450
|
-
.ntr-acp-more.is-primary { border-color: transparent; background: var(--dsw-alias-button-primary-fill, #2563eb); color: var(--dsw-alias-
|
|
2491
|
+
.ntr-acp-more.is-primary { border-color: transparent; background: var(--dsw-alias-button-primary-fill, #2563eb); color: var(--dsw-alias-label-primary-foreground, #fff); }
|
|
2451
2492
|
.ntr-acp-tool > .ntr-acp-more, .ntr-acp-empty-actions .ntr-acp-more { margin: 6px 10px; }
|
|
2452
2493
|
.ntr-acp-plan { border: 1px solid var(--dsw-alias-border-l2, #e5e7eb); border-radius: 10px; padding: 8px 10px; background: var(--dsw-alias-bg-layer-1, #fff); }
|
|
2453
|
-
.ntr-acp-plan-head { font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--dsw-alias-
|
|
2494
|
+
.ntr-acp-plan-head { font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--dsw-alias-label-secondary, #6b7280); margin-bottom: 4px; }
|
|
2454
2495
|
.ntr-acp-plan-row { display: flex; align-items: baseline; gap: 8px; font-size: 12.5px; padding: 1px 0; }
|
|
2455
|
-
.ntr-acp-plan-row.is-completed { color: var(--dsw-alias-
|
|
2496
|
+
.ntr-acp-plan-row.is-completed { color: var(--dsw-alias-label-secondary, #6b7280); text-decoration: line-through; }
|
|
2456
2497
|
.ntr-acp-plan-row.is-in_progress { font-weight: 600; }
|
|
2457
2498
|
.ntr-acp-plan-glyph { width: 1ch; flex: none; }
|
|
2458
|
-
.ntr-acp-plan-prio { margin-left: auto; font-size: 10px; text-transform: uppercase; color: var(--dsw-alias-
|
|
2499
|
+
.ntr-acp-plan-prio { margin-left: auto; font-size: 10px; text-transform: uppercase; color: var(--dsw-alias-label-secondary, #6b7280); }
|
|
2459
2500
|
.ntr-acp-notice { padding: 6px 10px; border-radius: 8px; font-size: 12px; }
|
|
2460
|
-
.ntr-acp-notice.is-error { background: #
|
|
2461
|
-
.ntr-acp-notice.is-info { background: var(--dsw-alias-bg-layer-2, #f3f4f6); color: var(--dsw-alias-
|
|
2501
|
+
.ntr-acp-notice.is-error { background: color-mix(in srgb, var(--dsw-alias-state-error-primary, #b91c1c) 12%, transparent); color: var(--dsw-alias-state-error-primary, #b91c1c); }
|
|
2502
|
+
.ntr-acp-notice.is-info { background: var(--dsw-alias-bg-layer-2, #f3f4f6); color: var(--dsw-alias-label-secondary, #6b7280); }
|
|
2462
2503
|
.ntr-acp-empty { margin: auto; max-width: 460px; text-align: center; display: flex; flex-direction: column; gap: 10px; padding: 24px; }
|
|
2463
2504
|
.ntr-acp-empty-title { font-size: 14px; font-weight: 600; }
|
|
2464
|
-
.ntr-acp-empty-body { margin: 0; color: var(--dsw-alias-
|
|
2465
|
-
.ntr-acp-empty-hint { color: var(--dsw-alias-
|
|
2466
|
-
.ntr-acp-seat-diag { font-family: var(--
|
|
2505
|
+
.ntr-acp-empty-body { margin: 0; color: var(--dsw-alias-label-secondary, #6b7280); font-size: 12.5px; line-height: 1.7; }
|
|
2506
|
+
.ntr-acp-empty-hint { color: var(--dsw-alias-label-secondary, #6b7280); font-size: 12px; }
|
|
2507
|
+
.ntr-acp-seat-diag { font-family: var(--ds-font-family-code, ui-monospace, SFMono-Regular, Menlo, monospace); opacity: 0.72; word-break: break-word; }
|
|
2467
2508
|
.ntr-acp-empty-actions { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }
|
|
2509
|
+
/* ---- Pending permission asks (conversation.input.dock) ---- */
|
|
2510
|
+
/* The dock slot is the full conversation column, but the composer card inside
|
|
2511
|
+
it is narrower (InputBar: side clearance + card max width). Mirror that
|
|
2512
|
+
formula so each ask lines up with the input box instead of spanning the
|
|
2513
|
+
column. The list owns a bounded height and scrolls so a burst of asks cannot
|
|
2514
|
+
push the composer off screen. */
|
|
2515
|
+
.ntr-permission-dock {
|
|
2516
|
+
box-sizing: border-box;
|
|
2517
|
+
width: calc(100% - var(--dsh-composer-side-clearance, 16px) - var(--dsh-composer-side-clearance, 16px));
|
|
2518
|
+
max-width: var(--dsh-composer-card-max-width, 920px);
|
|
2519
|
+
margin: 0 auto;
|
|
2520
|
+
display: flex; flex-direction: column; gap: 6px;
|
|
2521
|
+
max-height: min(38vh, 320px); overflow-y: auto;
|
|
2522
|
+
font-size: 12px; line-height: 1.5;
|
|
2523
|
+
}
|
|
2524
|
+
.ntr-permission-card { display: flex; flex-direction: column; gap: 6px; padding: 8px 10px; border: 1px solid var(--dsw-alias-border-l2, #d1d5db); border-left: 3px solid var(--dsw-alias-state-warn-primary, #d97706); border-radius: 10px; background: var(--dsw-alias-bg-layer-1, #fff); }
|
|
2525
|
+
.ntr-permission-head { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
|
|
2526
|
+
.ntr-permission-tool { flex: none; font-weight: 600; }
|
|
2527
|
+
.ntr-permission-reason { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-secondary, #6b7280); }
|
|
2528
|
+
.ntr-permission-deadline { flex: none; font-size: 11px; color: var(--dsw-alias-label-secondary, #6b7280); font-variant-numeric: tabular-nums; }
|
|
2529
|
+
.ntr-permission-deadline.is-expired { color: var(--dsw-alias-state-warn-label, #b45309); font-weight: 600; }
|
|
2530
|
+
.ntr-permission-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
|
|
2531
|
+
.ntr-permission-option, .ntr-permission-cancel { font: inherit; font-size: 12px; line-height: 1.4; padding: 4px 10px; border-radius: 7px; border: 1px solid var(--dsw-alias-border-l2, #d1d5db); background: var(--dsw-alias-bg-layer-2, #f3f4f6); color: inherit; cursor: pointer; white-space: normal; text-align: left; }
|
|
2532
|
+
.ntr-permission-option:hover:not(:disabled), .ntr-permission-cancel:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-active, #0000000d); }
|
|
2533
|
+
.ntr-permission-option:disabled, .ntr-permission-cancel:disabled { opacity: 0.5; cursor: default; }
|
|
2534
|
+
.ntr-permission-option:focus-visible, .ntr-permission-cancel:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary, #2563eb); outline-offset: 2px; }
|
|
2535
|
+
.ntr-permission-cancel { margin-left: auto; color: var(--dsw-alias-label-secondary, #6b7280); }
|
|
2536
|
+
.ntr-permission-error { padding: 4px 8px; border-radius: 6px; background: color-mix(in srgb, var(--dsw-alias-state-error-primary, #b91c1c) 12%, transparent); color: var(--dsw-alias-state-error-primary, #b91c1c); font-size: 11px; word-break: break-word; }
|
|
2468
2537
|
/* ---- NTR settings dialog (shell.overlay) ---- */
|
|
2469
2538
|
/* Frame-wide surface opened from the agent base's empty-roster menu. The
|
|
2470
2539
|
overlay layer itself is click-through, so the layer opts back in and blocks
|
|
@@ -2501,11 +2570,11 @@ window.__ModuleLoader__.load({
|
|
|
2501
2570
|
* React surface for ACP: the settings configuration section.
|
|
2502
2571
|
*
|
|
2503
2572
|
* Scope is deliberately narrow — this is a CONFIGURATION surface. Runtime
|
|
2504
|
-
* interaction lives in the conversation: permission
|
|
2505
|
-
*
|
|
2506
|
-
*
|
|
2507
|
-
*
|
|
2508
|
-
*
|
|
2573
|
+
* interaction lives in the conversation: every permission ask with a chat
|
|
2574
|
+
* identity is answered on a card above that conversation's composer
|
|
2575
|
+
* (`permission-dock.tsx`). The ledger card here is the cross-session mirror —
|
|
2576
|
+
* asks whose conversation is not open, or which have no chat identity at all —
|
|
2577
|
+
* and is where those are answered (see `permissionLedgerCard`).
|
|
2509
2578
|
*
|
|
2510
2579
|
* Each configured agent is one compact row (status + current model + badges)
|
|
2511
2580
|
* that expands into the full connection form and model catalog. The row stays
|
|
@@ -2537,22 +2606,40 @@ window.__ModuleLoader__.load({
|
|
|
2537
2606
|
--ntr-radius: 10px; --ntr-radius-sm: 7px;
|
|
2538
2607
|
--ntr-font: 13px; --ntr-font-sm: 12px; --ntr-font-xs: 11px;
|
|
2539
2608
|
--ntr-line: 1px solid var(--dsw-alias-border-l2, #e5e7eb);
|
|
2540
|
-
--ntr-muted: var(--dsw-alias-
|
|
2541
|
-
--ntr-danger:
|
|
2609
|
+
--ntr-muted: var(--dsw-alias-label-secondary, #6b7280);
|
|
2610
|
+
--ntr-danger: var(--dsw-alias-state-error-primary, #dc2626);
|
|
2611
|
+
--ntr-warn: var(--dsw-alias-state-warn-label, #b45309);
|
|
2612
|
+
--ntr-success: color-mix(in srgb, var(--dsw-alias-state-success-primary, #16a34a) 72%, var(--dsw-alias-label-primary, #111827));
|
|
2542
2613
|
--ntr-accent: var(--dsw-alias-button-primary-fill, #2563eb);
|
|
2543
2614
|
width: 100%; max-width: 960px; box-sizing: border-box; margin: 0 auto;
|
|
2544
|
-
padding:
|
|
2615
|
+
padding: 28px 32px; min-width: 0; container-type: inline-size; font-size: var(--ntr-font); line-height: 1.55;
|
|
2545
2616
|
}
|
|
2546
|
-
.dwa-root
|
|
2617
|
+
.dwa-root [hidden] { display: none !important; }
|
|
2618
|
+
.dwa-root button, .dwa-root input, .dwa-root select, .dwa-root textarea { font-family: inherit; }
|
|
2619
|
+
.dwa-root input, .dwa-root textarea { min-width: 0; }
|
|
2620
|
+
.dwa-tabs { display: flex; gap: 24px; flex-wrap: wrap; border-bottom: var(--ntr-line); margin-bottom: 24px; }
|
|
2621
|
+
.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; }
|
|
2622
|
+
.dwa-tabs > button:hover { color: var(--dsw-alias-label-primary, #111827); }
|
|
2623
|
+
.dwa-tabs > button[aria-pressed="true"] { color: var(--dsw-alias-label-primary, #111827); border-bottom-color: currentColor; font-weight: 550; }
|
|
2624
|
+
.dwa-detail-tabs { margin: 4px 0 20px; gap: 20px; }
|
|
2625
|
+
.dwa-detail-tabs > button { font-size: var(--ntr-font-sm); }
|
|
2626
|
+
.dwa-row-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
|
|
2627
|
+
.dwa-notice { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
|
|
2628
|
+
.dwa-notice > span { flex: 1; min-width: 0; overflow-wrap: anywhere; }
|
|
2629
|
+
.dwa-empty { text-align: center; padding: 40px 16px; color: var(--ntr-muted); }
|
|
2630
|
+
.dwa-empty h3 { font-size: 16px; font-weight: 550; color: var(--dsw-alias-label-primary, #111827); margin: 0 0 8px; }
|
|
2631
|
+
.dwa-empty .dwa-btn { margin-top: 20px; }
|
|
2632
|
+
.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; }
|
|
2633
|
+
.dwa-health-status { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
|
|
2634
|
+
.dwa-health-status > span:last-child:not(:nth-child(2)) { padding-left: 12px; border-left: var(--ntr-line); }
|
|
2635
|
+
.dwa-back { margin-bottom: 16px; }
|
|
2547
2636
|
.dwa-root button:focus-visible, .dwa-root input:focus-visible, .dwa-root select:focus-visible {
|
|
2548
2637
|
outline: 2px solid var(--ntr-accent); outline-offset: 2px;
|
|
2549
2638
|
}
|
|
2550
|
-
.dwa-page-header { display: flex; align-items:
|
|
2639
|
+
.dwa-page-header { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 28px; }
|
|
2551
2640
|
.dwa-page-heading { min-width: 0; }
|
|
2552
|
-
.dwa-page-title { margin: 0; font-size: 20px; line-height: 1.35; font-weight:
|
|
2641
|
+
.dwa-page-title { margin: 0; font-size: 20px; line-height: 1.35; font-weight: 550; letter-spacing: -0.02em; }
|
|
2553
2642
|
.dwa-page-description { margin: 5px 0 0; color: var(--ntr-muted); font-size: var(--ntr-font-sm); }
|
|
2554
|
-
.dwa-page-status { display: flex; align-items: center; gap: 8px; margin-top: 10px; color: var(--ntr-muted); font-size: var(--ntr-font-xs); }
|
|
2555
|
-
.dwa-page-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
|
|
2556
2643
|
.dwa-btn {
|
|
2557
2644
|
min-height: 32px; box-sizing: border-box; font: inherit; border-radius: var(--ntr-radius-sm);
|
|
2558
2645
|
border: 1px solid var(--dsw-alias-border-l2, #d1d5db); background: var(--dsw-alias-bg-layer-1, #fff);
|
|
@@ -2562,58 +2649,58 @@ window.__ModuleLoader__.load({
|
|
|
2562
2649
|
}
|
|
2563
2650
|
.dwa-btn:hover { background: var(--dsw-alias-interactive-bg-active, #f3f4f6); border-color: var(--dsw-alias-border-l1, #9ca3af); }
|
|
2564
2651
|
.dwa-btn:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
2565
|
-
.dwa-btn-primary { background: var(--ntr-accent); color: var(--dsw-alias-
|
|
2652
|
+
.dwa-btn-primary { background: var(--ntr-accent); color: var(--dsw-alias-label-primary-foreground, #fff); border-color: transparent; font-weight: 550; }
|
|
2566
2653
|
.dwa-btn-primary:hover { background: var(--ntr-accent); border-color: transparent; opacity: 0.88; }
|
|
2567
2654
|
.dwa-btn-secondary { background: var(--dsw-alias-bg-layer-2, #f3f4f6); }
|
|
2568
|
-
.dwa-btn-
|
|
2569
|
-
.dwa-btn-
|
|
2655
|
+
.dwa-btn-quiet { background: transparent; border-color: transparent; color: var(--ntr-muted); }
|
|
2656
|
+
.dwa-btn-quiet:hover { border-color: transparent; color: var(--dsw-alias-label-primary, #111827); }
|
|
2657
|
+
.dwa-btn-danger { color: var(--ntr-danger); border-color: var(--dsw-alias-state-error-secondary, #fca5a5); }
|
|
2658
|
+
.dwa-btn-danger:hover { background: var(--dsw-alias-interactive-bg-hover-danger, #fee2e2); }
|
|
2570
2659
|
.dwa-section { margin-bottom: 24px; }
|
|
2571
2660
|
.dwa-section-heading { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 10px; }
|
|
2572
|
-
.dwa-section-title { font-size:
|
|
2661
|
+
.dwa-section-title { font-size: 13px; font-weight: 550; margin: 0; display: flex; align-items: center; gap: 8px; }
|
|
2573
2662
|
.dwa-section-copy { margin: 3px 0 0; font-size: var(--ntr-font-xs); color: var(--ntr-muted); }
|
|
2574
2663
|
.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; }
|
|
2575
|
-
.dwa-card-warn { border-
|
|
2664
|
+
.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); }
|
|
2576
2665
|
.dwa-mode-banner { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 5px 16px; align-items: start; margin-bottom: 24px; padding: 14px 16px; }
|
|
2577
2666
|
.dwa-mode-title { display: flex; align-items: center; gap: 8px; font-weight: 650; }
|
|
2578
2667
|
.dwa-mode-copy { grid-column: 1 / -1; color: var(--ntr-muted); font-size: var(--ntr-font-xs); }
|
|
2579
2668
|
.dwa-mode-source { display: block; margin-top: 5px; overflow-wrap: anywhere; opacity: 0.85; }
|
|
2580
2669
|
.dwa-badge { font-size: var(--ntr-font-xs); line-height: 1.4; border-radius: 999px; padding: 2px 8px; background: var(--dsw-alias-bg-layer-2, #f3f4f6); color: var(--ntr-muted); font-weight: 550; display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; }
|
|
2581
|
-
.dwa-badge-success { background: #
|
|
2582
|
-
.dwa-badge-warn { background: #
|
|
2583
|
-
.dwa-badge-info { background: #
|
|
2670
|
+
.dwa-badge-success { background: var(--dsw-alias-state-success-tertiary, #dcfce7); color: var(--ntr-success); }
|
|
2671
|
+
.dwa-badge-warn { background: var(--dsw-alias-state-warn-tertiary, #fef3c7); color: var(--ntr-warn); }
|
|
2672
|
+
.dwa-badge-info { background: var(--dsw-alias-state-business-tertiary, #dbeafe); color: var(--dsw-alias-state-business-primary, #2563eb); }
|
|
2584
2673
|
.dwa-dot { width: 7px; height: 7px; border-radius: 50%; display: inline-block; flex-shrink: 0; }
|
|
2585
|
-
.dwa-agent-list { display: flex; flex-direction: column;
|
|
2586
|
-
.dwa-agent-card { border: var(--ntr-line);
|
|
2587
|
-
.dwa-agent-
|
|
2588
|
-
.dwa-agent-
|
|
2674
|
+
.dwa-agent-list { display: flex; flex-direction: column; border-top: var(--ntr-line); }
|
|
2675
|
+
.dwa-agent-card { border-bottom: var(--ntr-line); min-width: 0; }
|
|
2676
|
+
.dwa-agent-row { display: grid; grid-template-columns: 38px minmax(0, 1fr) auto; align-items: center; gap: 14px; padding: 16px 0; }
|
|
2677
|
+
.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); }
|
|
2589
2678
|
.dwa-caret { font-size: 14px; line-height: 1; display: inline-flex; align-items: center; justify-content: center; width: 1em; }
|
|
2590
2679
|
.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; }
|
|
2591
2680
|
.dwa-caret-btn:hover { background: var(--dsw-alias-interactive-bg-active, #e5e7eb); color: inherit; }
|
|
2592
2681
|
.dwa-agent-summary { min-width: 0; }
|
|
2593
2682
|
.dwa-agent-titleline { display: flex; align-items: center; gap: 8px; min-width: 0; flex-wrap: wrap; }
|
|
2594
|
-
.dwa-agent-name { font-size: 13px; font-weight:
|
|
2683
|
+
.dwa-agent-name { font-size: 13px; font-weight: 550; overflow-wrap: anywhere; }
|
|
2595
2684
|
.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); }
|
|
2596
2685
|
.dwa-agent-meta-separator { opacity: 0.45; }
|
|
2597
|
-
.dwa-agent-body {
|
|
2598
|
-
.dwa-subsection {
|
|
2599
|
-
.dwa-
|
|
2600
|
-
.dwa-subsection-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 12px; }
|
|
2601
|
-
.dwa-subsection-title { margin: 0; font-size: 13px; font-weight: 650; }
|
|
2602
|
-
.dwa-subsection-copy { margin: 3px 0 0; color: var(--ntr-muted); font-size: var(--ntr-font-xs); }
|
|
2603
|
-
.dwa-form-row { display: flex; gap: var(--ntr-gap-3); margin-bottom: 14px; align-items: flex-start; }
|
|
2686
|
+
.dwa-agent-body { padding: 0 0 24px 52px; }
|
|
2687
|
+
.dwa-subsection { min-width: 0; }
|
|
2688
|
+
.dwa-form-row { display: flex; gap: var(--ntr-gap-3); margin-bottom: 14px; align-items: stretch; }
|
|
2604
2689
|
.dwa-form-col { flex: 1; display: flex; flex-direction: column; gap: 6px; min-width: 0; }
|
|
2605
|
-
.dwa-form-label { font-size: var(--ntr-font-sm); font-weight: 600; color: var(--dsw-alias-
|
|
2690
|
+
.dwa-form-label { font-size: var(--ntr-font-sm); font-weight: 600; color: var(--dsw-alias-label-primary, #374151); }
|
|
2606
2691
|
.dwa-hint { font-size: var(--ntr-font-xs); line-height: 1.55; color: var(--ntr-muted); }
|
|
2607
2692
|
.dwa-error { font-size: var(--ntr-font-xs); color: var(--ntr-danger); }
|
|
2608
2693
|
.dwa-input { min-height: 36px; font: inherit; font-size: var(--ntr-font-sm); padding: 7px 10px; 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; width: 100%; box-sizing: border-box; }
|
|
2609
2694
|
.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; }
|
|
2610
2695
|
.dwa-input:hover, .dwa-select:hover { border-color: var(--dsw-alias-border-l1, #9ca3af); }
|
|
2611
2696
|
.dwa-input:focus, .dwa-select:focus { border-color: var(--ntr-accent); }
|
|
2612
|
-
.dwa-input-mono, .dwa-mono { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; }
|
|
2697
|
+
.dwa-input-mono, .dwa-mono { font-family: var(--ds-font-family-code, ui-monospace), SFMono-Regular, Menlo, Monaco, Consolas, monospace; }
|
|
2613
2698
|
.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; }
|
|
2614
2699
|
.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; }
|
|
2615
2700
|
.dwa-form-actions { display: flex; align-items: center; gap: 8px; margin-top: 16px; padding-top: 14px; border-top: var(--ntr-line); flex-wrap: wrap; }
|
|
2616
2701
|
.dwa-form-actions .dwa-btn-primary { min-width: 88px; }
|
|
2702
|
+
.dwa-form-actions > .dwa-hint:first-child { margin-right: auto; }
|
|
2703
|
+
.dwa-form-actions > .dwa-hint:last-child:not(:first-child) { width: 100%; }
|
|
2617
2704
|
.dwa-menu-wrap { position: relative; }
|
|
2618
2705
|
.dwa-menu-wrap > .dwa-btn { width: 32px; padding: 0; }
|
|
2619
2706
|
.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; }
|
|
@@ -2621,13 +2708,13 @@ window.__ModuleLoader__.load({
|
|
|
2621
2708
|
.dwa-menu-item:hover { background: var(--dsw-alias-interactive-bg-active, #f3f4f6); }
|
|
2622
2709
|
.dwa-menu-item-danger { color: var(--ntr-danger); }
|
|
2623
2710
|
.dwa-menu-confirm { display: flex; align-items: center; gap: 4px; padding: 4px; }
|
|
2624
|
-
.dwa-add-panel
|
|
2625
|
-
.dwa-add-
|
|
2626
|
-
.dwa-add-
|
|
2627
|
-
.dwa-add-content {
|
|
2711
|
+
.dwa-add-panel .dwa-agent-row { display: none; }
|
|
2712
|
+
.dwa-add-panel .dwa-agent-body { padding: 0 0 24px; }
|
|
2713
|
+
.dwa-add-panel .dwa-agent-card { border: 0; }
|
|
2714
|
+
.dwa-add-content { padding-top: 10px; }
|
|
2628
2715
|
.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; }
|
|
2629
2716
|
.dwa-chip:hover { background: var(--dsw-alias-interactive-bg-active, #f3f4f6); }
|
|
2630
|
-
.dwa-chip-active { border-color: var(--ntr-accent); background: #
|
|
2717
|
+
.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; }
|
|
2631
2718
|
.dwa-chip-list { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; margin: 0 0 12px; }
|
|
2632
2719
|
.dwa-switch { display: inline-flex; align-items: center; gap: 7px; font-size: var(--ntr-font-sm); cursor: pointer; user-select: none; }
|
|
2633
2720
|
.dwa-inline-setting { display: flex; align-items: flex-start; gap: 10px; padding: 10px 12px; border-radius: var(--ntr-radius-sm); background: var(--dsw-alias-bg-layer-2, #f9fafb); }
|
|
@@ -2640,7 +2727,7 @@ window.__ModuleLoader__.load({
|
|
|
2640
2727
|
/* Tall enough for a comfortable selection (about ten rows) before scrolling;
|
|
2641
2728
|
the cap keeps the two stacked panes from pushing the rest of the card away. */
|
|
2642
2729
|
.dwa-model-pane { min-width: 0; max-height: 360px; display: flex; flex-direction: column; border: var(--ntr-line); border-radius: var(--ntr-radius-sm); background: var(--dsw-alias-bg-layer-1, #fff); overflow: hidden; }
|
|
2643
|
-
.dwa-model-pane-head { display: flex; align-items: center; gap: 6px; padding: 7px 9px; border-bottom: var(--ntr-line); font-size: var(--ntr-font-xs); font-weight: 600; color: var(--dsw-alias-
|
|
2730
|
+
.dwa-model-pane-head { display: flex; align-items: center; gap: 6px; padding: 7px 9px; border-bottom: var(--ntr-line); font-size: var(--ntr-font-xs); font-weight: 600; color: var(--dsw-alias-label-secondary, #4b5563); }
|
|
2644
2731
|
.dwa-model-pane-head .dwa-btn { margin-left: auto; min-height: 26px; padding: 2px 8px; font-size: var(--ntr-font-xs); }
|
|
2645
2732
|
.dwa-model-pane-head .dwa-caret-btn { flex: none; width: 22px; height: 22px; background: transparent; }
|
|
2646
2733
|
.dwa-model-pane-head .dwa-caret-btn:hover { background: var(--dsw-alias-interactive-bg-active, #e5e7eb); }
|
|
@@ -2656,13 +2743,13 @@ window.__ModuleLoader__.load({
|
|
|
2656
2743
|
.dwa-model-status { margin-left: auto; white-space: nowrap; }
|
|
2657
2744
|
.dwa-model-search { width: 200px; min-height: 30px; }
|
|
2658
2745
|
.dwa-model-empty { padding: 6px; }
|
|
2659
|
-
.dwa-model-row { display: flex; align-items: center; gap:
|
|
2746
|
+
.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; }
|
|
2660
2747
|
.dwa-model-row:hover { background: var(--dsw-alias-interactive-bg-active, #f3f4f6); }
|
|
2661
|
-
.dwa-model-row.is-on { background: #
|
|
2748
|
+
.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); }
|
|
2662
2749
|
.dwa-model-row-mark { width: 12px; flex: none; text-align: center; opacity: 0.75; }
|
|
2663
2750
|
.dwa-model-row-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2664
2751
|
/* Name and credit keep their room; the id is the only cell that collapses. */
|
|
2665
|
-
.dwa-model-row-desc { flex: 0 0 auto; max-width: 45%; opacity: 0.75; font-size:
|
|
2752
|
+
.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; }
|
|
2666
2753
|
/* The trailing 14px is reserved for the fade mask: while the id fits, the
|
|
2667
2754
|
gradient only covers empty padding; once it overflows, its tail dissolves
|
|
2668
2755
|
instead of ending in a hard ellipsis. armModelIdMarquee reads the same
|
|
@@ -2676,12 +2763,12 @@ window.__ModuleLoader__.load({
|
|
|
2676
2763
|
}
|
|
2677
2764
|
.dwa-model-row-remove { flex: none; opacity: 0.5; padding: 0 2px; }
|
|
2678
2765
|
.dwa-model-row:hover .dwa-model-row-remove { opacity: 1; }
|
|
2679
|
-
.dwa-seg { display: inline-flex; border-radius: var(--ntr-radius-sm); border:
|
|
2680
|
-
.dwa-seg > button { min-height:
|
|
2681
|
-
.dwa-seg > button + button { border-left: 1px solid var(--dsw-alias-border-l2, #d1d5db); }
|
|
2766
|
+
.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; }
|
|
2767
|
+
.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; }
|
|
2682
2768
|
.dwa-seg > button:hover { background: var(--dsw-alias-interactive-bg-active, #f3f4f6); }
|
|
2683
|
-
.dwa-seg > button.is-on { background: var(--ntr-
|
|
2684
|
-
.dwa-
|
|
2769
|
+
.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; }
|
|
2770
|
+
.dwa-preferences { border-top: var(--ntr-line); }
|
|
2771
|
+
.dwa-preference-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 20px 0; }
|
|
2685
2772
|
.dwa-preference-row + .dwa-preference-row { border-top: var(--ntr-line); }
|
|
2686
2773
|
/* A control that needs the whole card: the label sits above it, not beside
|
|
2687
2774
|
it. A right-aligned segmented control squeezed its labels into two lines
|
|
@@ -2706,13 +2793,20 @@ window.__ModuleLoader__.load({
|
|
|
2706
2793
|
.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; }
|
|
2707
2794
|
.dwa-deadline-reset { display: flex; justify-content: flex-end; margin-top: 8px; }
|
|
2708
2795
|
@media (max-width: 640px) {
|
|
2709
|
-
.dwa-root { padding:
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
.dwa-page-
|
|
2796
|
+
.dwa-root { padding: 20px 16px; }
|
|
2797
|
+
}
|
|
2798
|
+
@container (max-width: 640px) {
|
|
2799
|
+
.dwa-page-header { align-items: flex-start; flex-wrap: wrap; }
|
|
2800
|
+
.dwa-agent-body { padding-left: 0; }
|
|
2801
|
+
.dwa-agent-row { grid-template-columns: 32px minmax(0, 1fr) auto; gap: 10px; }
|
|
2802
|
+
.dwa-agent-avatar { width: 32px; height: 32px; }
|
|
2803
|
+
.dwa-section-heading { flex-wrap: wrap; }
|
|
2804
|
+
.dwa-tabs { gap: 20px; }
|
|
2805
|
+
.dwa-notice { flex-wrap: wrap; }
|
|
2806
|
+
.dwa-seg-wide > button { padding-inline: 5px; }
|
|
2713
2807
|
.dwa-model-toolbar-actions { width: 100%; }
|
|
2714
2808
|
.dwa-model-search { flex: 1 1 auto; width: auto; }
|
|
2715
|
-
.dwa-
|
|
2809
|
+
.dwa-preference-row { align-items: flex-start; flex-direction: column; }
|
|
2716
2810
|
.dwa-default-hint { align-items: flex-start; flex-direction: column; }
|
|
2717
2811
|
/* The slider's scale: up to eight rungs with full unit words ("15 分钟")
|
|
2718
2812
|
need a smaller face before they can collide on a narrow panel. The rung
|
|
@@ -2739,19 +2833,19 @@ window.__ModuleLoader__.load({
|
|
|
2739
2833
|
function stateVisual(state, acp) {
|
|
2740
2834
|
switch (state) {
|
|
2741
2835
|
case "ready": return {
|
|
2742
|
-
color: "#22c55e",
|
|
2836
|
+
color: "var(--dsw-alias-state-success-primary, #22c55e)",
|
|
2743
2837
|
text: acp.label("已连接", "Connected")
|
|
2744
2838
|
};
|
|
2745
2839
|
case "starting": return {
|
|
2746
|
-
color: "#eab308",
|
|
2840
|
+
color: "var(--dsw-alias-state-warn-primary, #eab308)",
|
|
2747
2841
|
text: acp.label("启动中", "Starting")
|
|
2748
2842
|
};
|
|
2749
2843
|
case "error": return {
|
|
2750
|
-
color: "#ef4444",
|
|
2844
|
+
color: "var(--dsw-alias-state-error-primary, #ef4444)",
|
|
2751
2845
|
text: acp.label("错误", "Error")
|
|
2752
2846
|
};
|
|
2753
2847
|
default: return {
|
|
2754
|
-
color: "#9ca3af",
|
|
2848
|
+
color: "var(--dsw-alias-state-idle-primary, #9ca3af)",
|
|
2755
2849
|
text: acp.label("已配置", "Configured"),
|
|
2756
2850
|
title: acp.label("已配置,进程不常驻。在 DSH 聊天中首次使用时自动连接;展开区可用「测试连接」验证命令能否正常起来。", "Configured; the process is not kept resident. It connects automatically the first time a DSH chat turn uses it — use “Test connection” in the expanded panel to verify the command starts.")
|
|
2757
2851
|
};
|
|
@@ -2924,25 +3018,15 @@ window.__ModuleLoader__.load({
|
|
|
2924
3018
|
/**
|
|
2925
3019
|
* The settings panel's permission-ledger rule.
|
|
2926
3020
|
*
|
|
2927
|
-
*
|
|
2928
|
-
*
|
|
2929
|
-
*
|
|
2930
|
-
*
|
|
2931
|
-
*
|
|
2932
|
-
*
|
|
2933
|
-
* (`approvalRouted` → a read-only count, no buttons) hid the only answer
|
|
2934
|
-
* entry exactly when the native route had degraded to unavailable, and the
|
|
2935
|
-
* ask then hung until its timeout.
|
|
2936
|
-
*
|
|
2937
|
-
* `fellBackFromConversation` is the case the card has to explain: the host
|
|
2938
|
-
* can route asks, and this one still did not make it.
|
|
3021
|
+
* Pending asks are shown in the conversation card while that conversation is
|
|
3022
|
+
* open; this card is the cross-session mirror for the ones it cannot show —
|
|
3023
|
+
* asks belonging to another conversation, and `/acp` RPC-only asks with no
|
|
3024
|
+
* chat identity at all. It therefore appears whenever ANY ask is pending: a
|
|
3025
|
+
* pending entry with no conversation card would otherwise have no answer
|
|
3026
|
+
* surface anywhere.
|
|
2939
3027
|
*/
|
|
2940
3028
|
function permissionLedgerCard(ui) {
|
|
2941
|
-
|
|
2942
|
-
return {
|
|
2943
|
-
visible,
|
|
2944
|
-
fellBackFromConversation: visible && ui.approvalRouted
|
|
2945
|
-
};
|
|
3029
|
+
return { visible: ui.permissions.length > 0 };
|
|
2946
3030
|
}
|
|
2947
3031
|
/**
|
|
2948
3032
|
* The ONE wait window, as the rungs the slider snaps to.
|
|
@@ -3210,11 +3294,7 @@ window.__ModuleLoader__.load({
|
|
|
3210
3294
|
children: acp.label("权限请求的等待时长与超时处理方式。", "How long to wait for a permission request, and what happens when nobody answers.")
|
|
3211
3295
|
})] })
|
|
3212
3296
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3213
|
-
className: "dwa-
|
|
3214
|
-
style: {
|
|
3215
|
-
paddingTop: 4,
|
|
3216
|
-
paddingBottom: 4
|
|
3217
|
-
},
|
|
3297
|
+
className: "dwa-preferences",
|
|
3218
3298
|
children: [
|
|
3219
3299
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DeadlineModeBlock, {
|
|
3220
3300
|
acp,
|
|
@@ -3240,17 +3320,21 @@ window.__ModuleLoader__.load({
|
|
|
3240
3320
|
})]
|
|
3241
3321
|
});
|
|
3242
3322
|
}
|
|
3243
|
-
/** Settings configuration section for ACP agents. */
|
|
3244
3323
|
function AcpSettingsSection(props) {
|
|
3245
3324
|
const acp = props.acp;
|
|
3246
3325
|
ensureStyle();
|
|
3247
3326
|
const ui = useUi$1(acp);
|
|
3248
3327
|
const ledger = permissionLedgerCard(ui);
|
|
3249
|
-
const [
|
|
3328
|
+
const [page, setPage] = (0, react.useState)("agents");
|
|
3329
|
+
const [addOpen, setAddOpen] = (0, react.useState)(false);
|
|
3250
3330
|
const [addTarget, setAddTarget] = (0, react.useState)(void 0);
|
|
3251
|
-
const [createNonce, setCreateNonce] = (0, react.useState)(0);
|
|
3252
3331
|
const { configured, available } = partitionAgents(ui.detectedAgents, ui.agents);
|
|
3253
3332
|
const selected = addTarget ?? available[0] ?? NEW_AGENT_SEED;
|
|
3333
|
+
const openAdd = () => {
|
|
3334
|
+
setAddOpen(true);
|
|
3335
|
+
setPage("add");
|
|
3336
|
+
};
|
|
3337
|
+
const presetProblem = ui.preset !== void 0 && (!ui.preset.installed || ui.preset.problem !== void 0);
|
|
3254
3338
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3255
3339
|
className: "dwa-root",
|
|
3256
3340
|
children: [
|
|
@@ -3258,39 +3342,18 @@ window.__ModuleLoader__.load({
|
|
|
3258
3342
|
className: "dwa-page-header",
|
|
3259
3343
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3260
3344
|
className: "dwa-page-heading",
|
|
3261
|
-
children: [
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3274
|
-
className: "dwa-dot",
|
|
3275
|
-
style: { background: ui.stream === "live" ? "#22c55e" : ui.stream === "down" ? "#ef4444" : "#9ca3af" },
|
|
3276
|
-
title: ui.stream
|
|
3277
|
-
}),
|
|
3278
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: streamText(ui.stream, acp) }),
|
|
3279
|
-
ui.detectSummary !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: ["· ", ui.detectSummary] })
|
|
3280
|
-
]
|
|
3281
|
-
})
|
|
3282
|
-
]
|
|
3283
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3284
|
-
className: "dwa-page-actions",
|
|
3285
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3286
|
-
className: "dwa-btn",
|
|
3287
|
-
onClick: () => {
|
|
3288
|
-
acp.resync();
|
|
3289
|
-
acp.detectAgents();
|
|
3290
|
-
},
|
|
3291
|
-
disabled: ui.detecting,
|
|
3292
|
-
children: ui.detecting ? acp.label("检测中...", "Detecting...") : acp.label("重新检测与刷新", "Re-detect & Refresh")
|
|
3293
|
-
})
|
|
3345
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
3346
|
+
className: "dwa-page-title",
|
|
3347
|
+
children: acp.label("NTR 设置", "NTR settings")
|
|
3348
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3349
|
+
className: "dwa-page-description",
|
|
3350
|
+
children: acp.label("连接智能体,设置你的对话偏好。", "Connect agents and set your conversation preferences.")
|
|
3351
|
+
})]
|
|
3352
|
+
}), page === "agents" && configured.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3353
|
+
type: "button",
|
|
3354
|
+
className: "dwa-btn dwa-btn-primary",
|
|
3355
|
+
onClick: openAdd,
|
|
3356
|
+
children: acp.label("添加智能体", "Add agent")
|
|
3294
3357
|
})]
|
|
3295
3358
|
}),
|
|
3296
3359
|
ledger.visible && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -3300,14 +3363,14 @@ window.__ModuleLoader__.load({
|
|
|
3300
3363
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3301
3364
|
style: {
|
|
3302
3365
|
fontWeight: 600,
|
|
3303
|
-
marginBottom:
|
|
3366
|
+
marginBottom: 4
|
|
3304
3367
|
},
|
|
3305
3368
|
children: acp.label("待处理权限请求", "Pending Permission Requests")
|
|
3306
3369
|
}),
|
|
3307
|
-
|
|
3370
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3308
3371
|
className: "dwa-hint",
|
|
3309
3372
|
style: { marginBottom: 8 },
|
|
3310
|
-
children: acp.label("
|
|
3373
|
+
children: acp.label("对话打开时在那边的卡片上回答;这里兜底显示其他会话的询问。", "Answer in the conversation card while that conversation is open; this list covers the asks whose conversation is not.")
|
|
3311
3374
|
}),
|
|
3312
3375
|
ui.permissions.map((permission) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3313
3376
|
style: {
|
|
@@ -3318,22 +3381,34 @@ window.__ModuleLoader__.load({
|
|
|
3318
3381
|
flexWrap: "wrap"
|
|
3319
3382
|
},
|
|
3320
3383
|
children: [
|
|
3321
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3384
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3322
3385
|
style: {
|
|
3323
3386
|
flex: 1,
|
|
3324
3387
|
minWidth: 160
|
|
3325
3388
|
},
|
|
3326
|
-
children:
|
|
3389
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3390
|
+
style: { fontWeight: 600 },
|
|
3391
|
+
children: permission.toolName
|
|
3392
|
+
}), permission.reason !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3393
|
+
style: { color: "var(--ntr-muted)" },
|
|
3394
|
+
children: [" · ", permission.reason]
|
|
3395
|
+
})]
|
|
3327
3396
|
}),
|
|
3328
3397
|
permission.options.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3329
|
-
|
|
3330
|
-
|
|
3398
|
+
type: "button",
|
|
3399
|
+
className: "dwa-btn",
|
|
3400
|
+
onClick: () => {
|
|
3401
|
+
acp.respondPermission(permission.requestId, option.optionId).catch(() => void 0);
|
|
3402
|
+
},
|
|
3331
3403
|
children: option.name
|
|
3332
3404
|
}, option.optionId)),
|
|
3333
3405
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3406
|
+
type: "button",
|
|
3407
|
+
className: "dwa-btn dwa-btn-quiet",
|
|
3408
|
+
onClick: () => {
|
|
3409
|
+
acp.respondPermission(permission.requestId).catch(() => void 0);
|
|
3410
|
+
},
|
|
3411
|
+
children: acp.label("取消", "Cancel")
|
|
3337
3412
|
})
|
|
3338
3413
|
]
|
|
3339
3414
|
}, permission.requestId))
|
|
@@ -3351,12 +3426,81 @@ window.__ModuleLoader__.load({
|
|
|
3351
3426
|
style: { flex: 1 },
|
|
3352
3427
|
children: ui.notice
|
|
3353
3428
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3354
|
-
|
|
3429
|
+
type: "button",
|
|
3430
|
+
className: "dwa-btn dwa-btn-quiet",
|
|
3431
|
+
"aria-label": acp.label("关闭通知", "Dismiss notice"),
|
|
3355
3432
|
onClick: () => acp.clearNotice(),
|
|
3356
3433
|
children: "✕"
|
|
3357
3434
|
})]
|
|
3358
3435
|
}),
|
|
3359
|
-
|
|
3436
|
+
presetProblem && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3437
|
+
className: "dwa-card dwa-card-warn dwa-notice",
|
|
3438
|
+
role: "status",
|
|
3439
|
+
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", {
|
|
3440
|
+
type: "button",
|
|
3441
|
+
className: "dwa-btn",
|
|
3442
|
+
onClick: () => setPage("diagnostics"),
|
|
3443
|
+
children: acp.label("查看诊断", "View diagnostics")
|
|
3444
|
+
})]
|
|
3445
|
+
}),
|
|
3446
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("nav", {
|
|
3447
|
+
className: "dwa-tabs",
|
|
3448
|
+
"aria-label": acp.label("NTR 设置分类", "NTR settings categories"),
|
|
3449
|
+
children: [
|
|
3450
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3451
|
+
type: "button",
|
|
3452
|
+
"aria-pressed": page === "agents",
|
|
3453
|
+
onClick: () => setPage("agents"),
|
|
3454
|
+
children: acp.label("智能体", "Agents")
|
|
3455
|
+
}),
|
|
3456
|
+
ui.approvalDeadlines !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3457
|
+
type: "button",
|
|
3458
|
+
"aria-pressed": page === "approvals",
|
|
3459
|
+
onClick: () => setPage("approvals"),
|
|
3460
|
+
children: acp.label("审批时限", "Approval deadlines")
|
|
3461
|
+
}),
|
|
3462
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3463
|
+
type: "button",
|
|
3464
|
+
"aria-pressed": page === "appearance",
|
|
3465
|
+
onClick: () => setPage("appearance"),
|
|
3466
|
+
children: acp.label("对话外观", "Appearance")
|
|
3467
|
+
})
|
|
3468
|
+
]
|
|
3469
|
+
}),
|
|
3470
|
+
page === "diagnostics" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
3471
|
+
className: "dwa-section",
|
|
3472
|
+
children: [
|
|
3473
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
3474
|
+
className: "dwa-section-title",
|
|
3475
|
+
children: acp.label("连接诊断", "Connection diagnostics")
|
|
3476
|
+
}),
|
|
3477
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3478
|
+
className: "dwa-preference-row",
|
|
3479
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: acp.label("宿主事件流", "Host event stream") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3480
|
+
className: "dwa-hint",
|
|
3481
|
+
children: streamText(ui.stream, acp)
|
|
3482
|
+
})]
|
|
3483
|
+
}),
|
|
3484
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3485
|
+
className: "dwa-row-actions",
|
|
3486
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3487
|
+
type: "button",
|
|
3488
|
+
className: "dwa-btn",
|
|
3489
|
+
onClick: () => {
|
|
3490
|
+
acp.resync();
|
|
3491
|
+
acp.detectAgents();
|
|
3492
|
+
},
|
|
3493
|
+
disabled: ui.detecting,
|
|
3494
|
+
children: ui.detecting ? acp.label("检测中...", "Detecting...") : acp.label("重新检测与刷新", "Re-detect & Refresh")
|
|
3495
|
+
}), ui.detectSummary !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3496
|
+
className: "dwa-hint",
|
|
3497
|
+
role: "status",
|
|
3498
|
+
children: ui.detectSummary
|
|
3499
|
+
})]
|
|
3500
|
+
})
|
|
3501
|
+
]
|
|
3502
|
+
}),
|
|
3503
|
+
page === "diagnostics" && ui.preset !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3360
3504
|
className: "dwa-card dwa-mode-banner",
|
|
3361
3505
|
children: [
|
|
3362
3506
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -3389,28 +3533,42 @@ window.__ModuleLoader__.load({
|
|
|
3389
3533
|
}),
|
|
3390
3534
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
3391
3535
|
className: "dwa-section",
|
|
3536
|
+
hidden: page !== "agents",
|
|
3537
|
+
"aria-label": acp.label("已接入的智能体", "Connected agents"),
|
|
3392
3538
|
children: [
|
|
3393
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3539
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3394
3540
|
className: "dwa-section-heading",
|
|
3395
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.
|
|
3541
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h3", {
|
|
3396
3542
|
className: "dwa-section-title",
|
|
3397
|
-
children: [acp.label("已接入的智能体", "Connected agents"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3543
|
+
children: [acp.label("已接入的智能体", "Connected agents"), ui.agentsLoaded && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3398
3544
|
className: "dwa-badge",
|
|
3399
3545
|
children: configured.length
|
|
3400
3546
|
})]
|
|
3401
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
3402
|
-
className: "dwa-
|
|
3403
|
-
children: acp.label("
|
|
3404
|
-
})]
|
|
3547
|
+
}) }), configured.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3548
|
+
className: "dwa-hint",
|
|
3549
|
+
children: acp.label("默认项用于新的 NTR 会话", "The default serves new NTR conversations")
|
|
3550
|
+
})]
|
|
3405
3551
|
}),
|
|
3406
|
-
|
|
3407
|
-
className: "dwa-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
children:
|
|
3552
|
+
!ui.agentsLoaded && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3553
|
+
className: "dwa-empty",
|
|
3554
|
+
role: "status",
|
|
3555
|
+
children: acp.label("正在读取智能体…", "Loading agents…")
|
|
3556
|
+
}),
|
|
3557
|
+
ui.agentsLoaded && configured.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3558
|
+
className: "dwa-empty",
|
|
3559
|
+
children: [
|
|
3560
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: acp.label("接入第一个智能体", "Connect your first agent") }),
|
|
3561
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3562
|
+
className: "dwa-section-copy",
|
|
3563
|
+
children: acp.label("选择已有预设,或填写自己的 ACP 启动命令。", "Choose a preset or enter your own ACP launch command.")
|
|
3564
|
+
}),
|
|
3565
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3566
|
+
type: "button",
|
|
3567
|
+
className: "dwa-btn dwa-btn-primary",
|
|
3568
|
+
onClick: openAdd,
|
|
3569
|
+
children: acp.label("添加智能体", "Add agent")
|
|
3570
|
+
})
|
|
3571
|
+
]
|
|
3414
3572
|
}),
|
|
3415
3573
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3416
3574
|
className: "dwa-agent-list",
|
|
@@ -3421,36 +3579,33 @@ window.__ModuleLoader__.load({
|
|
|
3421
3579
|
activeAgent,
|
|
3422
3580
|
acp,
|
|
3423
3581
|
isDefault: ui.defaultAgent === info.id,
|
|
3424
|
-
synthesized
|
|
3582
|
+
synthesized,
|
|
3583
|
+
active: page === "agents"
|
|
3425
3584
|
}, info.id);
|
|
3426
3585
|
})
|
|
3427
3586
|
})
|
|
3428
3587
|
]
|
|
3429
3588
|
}),
|
|
3430
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3589
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
3431
3590
|
className: "dwa-section",
|
|
3432
|
-
|
|
3591
|
+
hidden: page !== "add",
|
|
3592
|
+
"aria-label": acp.label("添加智能体", "Add agent"),
|
|
3593
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3594
|
+
type: "button",
|
|
3595
|
+
className: "dwa-btn dwa-btn-quiet dwa-back",
|
|
3596
|
+
onClick: () => setPage("agents"),
|
|
3597
|
+
children: acp.label("返回智能体列表", "Back to agents")
|
|
3598
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3433
3599
|
className: "dwa-add-panel",
|
|
3434
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
"aria-expanded": addOpen,
|
|
3438
|
-
onClick: () => setAddOpen((open) => !open),
|
|
3439
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3600
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3601
|
+
className: "dwa-section-heading",
|
|
3602
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
3440
3603
|
className: "dwa-section-title",
|
|
3441
3604
|
children: acp.label("添加智能体", "Add agent")
|
|
3442
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
3605
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3443
3606
|
className: "dwa-section-copy",
|
|
3444
|
-
style: { display: "block" },
|
|
3445
3607
|
children: acp.label("从预设快速启用,或创建自定义连接。", "Enable a preset or create a custom connection.")
|
|
3446
|
-
})] })
|
|
3447
|
-
className: "dwa-caret-btn",
|
|
3448
|
-
"aria-hidden": true,
|
|
3449
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3450
|
-
className: "dwa-caret",
|
|
3451
|
-
children: addOpen ? "▾" : "▸"
|
|
3452
|
-
})
|
|
3453
|
-
})]
|
|
3608
|
+
})] })
|
|
3454
3609
|
}), addOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3455
3610
|
className: "dwa-add-content",
|
|
3456
3611
|
children: [
|
|
@@ -3480,21 +3635,28 @@ window.__ModuleLoader__.load({
|
|
|
3480
3635
|
isDefault: false,
|
|
3481
3636
|
synthesized: false,
|
|
3482
3637
|
newCustom: selected.id === "",
|
|
3638
|
+
active: page === "add",
|
|
3483
3639
|
onCreated: () => {
|
|
3484
3640
|
setAddTarget(void 0);
|
|
3485
|
-
|
|
3641
|
+
setAddOpen(false);
|
|
3642
|
+
setPage("agents");
|
|
3486
3643
|
}
|
|
3487
|
-
}, selected.id
|
|
3644
|
+
}, selected.id)
|
|
3488
3645
|
]
|
|
3489
3646
|
})]
|
|
3490
|
-
})
|
|
3647
|
+
})]
|
|
3491
3648
|
}),
|
|
3492
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
3493
|
-
|
|
3494
|
-
|
|
3649
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3650
|
+
hidden: page !== "approvals",
|
|
3651
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ApprovalDeadlinesCard, {
|
|
3652
|
+
acp,
|
|
3653
|
+
ui
|
|
3654
|
+
})
|
|
3495
3655
|
}),
|
|
3496
3656
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
3497
3657
|
className: "dwa-section",
|
|
3658
|
+
hidden: page !== "appearance",
|
|
3659
|
+
"aria-label": acp.label("对话外观", "Appearance"),
|
|
3498
3660
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3499
3661
|
className: "dwa-section-heading",
|
|
3500
3662
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
@@ -3505,11 +3667,7 @@ window.__ModuleLoader__.load({
|
|
|
3505
3667
|
children: acp.label("设置对话中 NTR 挂牌的进程存活提示。", "Choose how the NTR tag indicates a running agent process.")
|
|
3506
3668
|
})] })
|
|
3507
3669
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3508
|
-
className: "dwa-
|
|
3509
|
-
style: {
|
|
3510
|
-
paddingTop: 4,
|
|
3511
|
-
paddingBottom: 4
|
|
3512
|
-
},
|
|
3670
|
+
className: "dwa-preferences",
|
|
3513
3671
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3514
3672
|
className: "dwa-preference-row",
|
|
3515
3673
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -3556,15 +3714,35 @@ window.__ModuleLoader__.load({
|
|
|
3556
3714
|
})]
|
|
3557
3715
|
})]
|
|
3558
3716
|
})]
|
|
3717
|
+
}),
|
|
3718
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("footer", {
|
|
3719
|
+
className: "dwa-health",
|
|
3720
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3721
|
+
className: "dwa-health-status",
|
|
3722
|
+
children: [
|
|
3723
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3724
|
+
className: "dwa-dot",
|
|
3725
|
+
style: { background: ui.stream === "live" ? "var(--ntr-success)" : ui.stream === "down" ? "var(--ntr-danger)" : "var(--ntr-muted)" }
|
|
3726
|
+
}),
|
|
3727
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: streamText(ui.stream, acp) }),
|
|
3728
|
+
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") })
|
|
3729
|
+
]
|
|
3730
|
+
}), page !== "diagnostics" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3731
|
+
type: "button",
|
|
3732
|
+
className: "dwa-btn dwa-btn-quiet",
|
|
3733
|
+
onClick: () => setPage("diagnostics"),
|
|
3734
|
+
children: acp.label("查看诊断", "View diagnostics")
|
|
3735
|
+
})]
|
|
3559
3736
|
})
|
|
3560
3737
|
]
|
|
3561
3738
|
});
|
|
3562
3739
|
}
|
|
3563
3740
|
/** One row per agent: compact when collapsed, the full form when expanded. */
|
|
3564
|
-
function AgentRow({ detected, activeAgent, acp, isDefault, synthesized, newCustom = false, onCreated }) {
|
|
3741
|
+
function AgentRow({ detected, activeAgent, acp, isDefault, synthesized, active, newCustom = false, onCreated }) {
|
|
3565
3742
|
const ui = useUi$1(acp);
|
|
3566
3743
|
const configured = activeAgent !== void 0 || detected.currentConfig !== void 0;
|
|
3567
3744
|
const [expanded, setExpanded] = (0, react.useState)(!configured);
|
|
3745
|
+
const [detailPage, setDetailPage] = (0, react.useState)(configured ? "models" : "connection");
|
|
3568
3746
|
const [form, setForm] = (0, react.useState)(() => initialForm(detected, activeAgent));
|
|
3569
3747
|
const [saving, setSaving] = (0, react.useState)(false);
|
|
3570
3748
|
const [savedSuccess, setSavedSuccess] = (0, react.useState)(false);
|
|
@@ -3600,7 +3778,9 @@ window.__ModuleLoader__.load({
|
|
|
3600
3778
|
const formIncomplete = splitCommandLine(form.commandLine).command === "" || !idValid || idTaken || cwdInvalid || rootsInvalid || idleInvalid || mcpInvalid;
|
|
3601
3779
|
const payload = buildPayload(form, detected, newCustom);
|
|
3602
3780
|
const current = persistedDef(detected, activeAgent);
|
|
3603
|
-
const
|
|
3781
|
+
const clearingIdleOverride = payload.idleTimeoutMs === void 0 && detected.currentConfig?.idleTimeoutMs !== void 0;
|
|
3782
|
+
const dirty = current !== void 0 && (!payloadEquals(payload, current) || clearingIdleOverride);
|
|
3783
|
+
const showSaveWarning = dirty && activeAgent !== void 0 && activeAgent.state !== "stopped";
|
|
3604
3784
|
const handleUseDefault = () => patch({ commandLine: formatCommandLine(detected.defaultCommand, detected.defaultArgs) });
|
|
3605
3785
|
const handleSave = async () => {
|
|
3606
3786
|
setSaving(true);
|
|
@@ -3640,7 +3820,7 @@ window.__ModuleLoader__.load({
|
|
|
3640
3820
|
const displayName = newCustom ? acp.label("新建自定义 Agent", "New Custom Agent") : activeAgent?.title ?? detected.currentConfig?.title ?? detected.name;
|
|
3641
3821
|
const stderr = activeAgent?.state === "error" ? activeAgent.stderrTail ?? [] : [];
|
|
3642
3822
|
const errorSummary = stderr.length > 0 ? stderr[stderr.length - 1] : void 0;
|
|
3643
|
-
const
|
|
3823
|
+
const selectedModelCount = form.exposed?.length ?? 0;
|
|
3644
3824
|
const isPreset = PRESET_IDS.has(detected.id);
|
|
3645
3825
|
const open = expanded || activeAgent?.state === "error" && configured;
|
|
3646
3826
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -3648,17 +3828,10 @@ window.__ModuleLoader__.load({
|
|
|
3648
3828
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3649
3829
|
className: "dwa-agent-row",
|
|
3650
3830
|
children: [
|
|
3651
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
onClick: () => setExpanded((value) => !value),
|
|
3656
|
-
title: open ? acp.label("收起", "Collapse") : acp.label("展开配置与模型", "Expand configuration and models"),
|
|
3657
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3658
|
-
className: "dwa-caret",
|
|
3659
|
-
"aria-hidden": true,
|
|
3660
|
-
children: open ? "▾" : "▸"
|
|
3661
|
-
})
|
|
3831
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3832
|
+
className: "dwa-agent-avatar",
|
|
3833
|
+
"aria-hidden": true,
|
|
3834
|
+
children: displayName.slice(0, 2).toUpperCase()
|
|
3662
3835
|
}),
|
|
3663
3836
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3664
3837
|
className: "dwa-agent-summary",
|
|
@@ -3672,7 +3845,7 @@ window.__ModuleLoader__.load({
|
|
|
3672
3845
|
children: displayName
|
|
3673
3846
|
}),
|
|
3674
3847
|
isDefault && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3675
|
-
className: "dwa-badge dwa-badge-
|
|
3848
|
+
className: "dwa-badge dwa-badge-info",
|
|
3676
3849
|
children: acp.label("默认", "Default")
|
|
3677
3850
|
}),
|
|
3678
3851
|
!isPreset && !newCustom && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -3699,7 +3872,7 @@ window.__ModuleLoader__.load({
|
|
|
3699
3872
|
configured && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [state !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3700
3873
|
className: "dwa-agent-meta-separator",
|
|
3701
3874
|
children: "·"
|
|
3702
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children:
|
|
3875
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: acp.label(`${String(selectedModelCount)} 个已选模型`, `${String(selectedModelCount)} selected models`) })] }),
|
|
3703
3876
|
!synthesized && !newCustom && !detected.detected && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3704
3877
|
style: { color: "var(--ntr-warn)" },
|
|
3705
3878
|
title: detected.description,
|
|
@@ -3718,24 +3891,31 @@ window.__ModuleLoader__.load({
|
|
|
3718
3891
|
]
|
|
3719
3892
|
}),
|
|
3720
3893
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3894
|
+
className: "dwa-row-actions",
|
|
3895
|
+
children: [
|
|
3896
|
+
configured && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3897
|
+
type: "button",
|
|
3898
|
+
className: "dwa-btn dwa-btn-quiet",
|
|
3899
|
+
"aria-expanded": open,
|
|
3900
|
+
"aria-label": acp.label(`${open ? "收起" : "管理"} ${displayName}`, `${open ? "Collapse" : "Manage"} ${displayName}`),
|
|
3901
|
+
onClick: () => setExpanded((value) => !value),
|
|
3902
|
+
children: open ? acp.label("收起", "Collapse") : acp.label("管理", "Manage")
|
|
3903
|
+
}),
|
|
3904
|
+
activeAgent?.state === "error" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3905
|
+
className: "dwa-btn",
|
|
3906
|
+
disabled: testing,
|
|
3907
|
+
onClick: () => void handleTest(),
|
|
3908
|
+
children: testing ? acp.label("测试中...", "Testing...") : acp.label("测试", "Test")
|
|
3909
|
+
}),
|
|
3910
|
+
configured && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowMenu, {
|
|
3911
|
+
acp,
|
|
3912
|
+
canStop: activeAgent !== void 0 && activeAgent.state !== "stopped",
|
|
3913
|
+
onStop: () => void acp.stopAgent(detected.id),
|
|
3914
|
+
onRemove: async () => {
|
|
3915
|
+
await acp.deleteAgent(detected.id).catch(() => {});
|
|
3916
|
+
}
|
|
3917
|
+
})
|
|
3918
|
+
]
|
|
3739
3919
|
})
|
|
3740
3920
|
]
|
|
3741
3921
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -3746,42 +3926,52 @@ window.__ModuleLoader__.load({
|
|
|
3746
3926
|
className: "dwa-stderr",
|
|
3747
3927
|
children: stderr.join("\n")
|
|
3748
3928
|
}),
|
|
3749
|
-
|
|
3929
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("nav", {
|
|
3930
|
+
className: "dwa-tabs dwa-detail-tabs",
|
|
3931
|
+
"aria-label": acp.label(`${displayName} 配置`, `${displayName} settings`),
|
|
3932
|
+
children: [
|
|
3933
|
+
configured && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3934
|
+
type: "button",
|
|
3935
|
+
"aria-pressed": detailPage === "models",
|
|
3936
|
+
onClick: () => setDetailPage("models"),
|
|
3937
|
+
children: acp.label("模型", "Models")
|
|
3938
|
+
}),
|
|
3939
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3940
|
+
type: "button",
|
|
3941
|
+
"aria-pressed": detailPage === "connection",
|
|
3942
|
+
onClick: () => setDetailPage("connection"),
|
|
3943
|
+
children: acp.label("连接", "Connection")
|
|
3944
|
+
}),
|
|
3945
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3946
|
+
type: "button",
|
|
3947
|
+
"aria-pressed": detailPage === "advanced",
|
|
3948
|
+
onClick: () => setDetailPage("advanced"),
|
|
3949
|
+
children: acp.label("高级", "Advanced")
|
|
3950
|
+
})
|
|
3951
|
+
]
|
|
3952
|
+
}),
|
|
3953
|
+
configured && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
|
|
3750
3954
|
className: "dwa-subsection",
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
|
|
3754
|
-
className: "dwa-subsection-title",
|
|
3755
|
-
children: acp.label("模型与默认值", "Models & defaults")
|
|
3756
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3757
|
-
className: "dwa-subsection-copy",
|
|
3758
|
-
children: acp.label("检测模型目录,并控制对话中可选择的模型。", "Detect the model catalog and choose what appears in conversations.")
|
|
3759
|
-
})] })
|
|
3760
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelCatalogBlock, {
|
|
3955
|
+
hidden: detailPage !== "models",
|
|
3956
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelCatalogBlock, {
|
|
3761
3957
|
agentId: detected.id,
|
|
3762
3958
|
detected,
|
|
3763
3959
|
acp,
|
|
3764
|
-
active: open,
|
|
3960
|
+
active: active && open && detailPage === "models",
|
|
3765
3961
|
exposed: form.exposed,
|
|
3766
3962
|
onExposedChange: (exposed) => patch({ exposed }),
|
|
3767
3963
|
autoDiscover: form.autoDiscoverModels,
|
|
3768
3964
|
onAutoDiscoverChange: (autoDiscoverModels) => patch({ autoDiscoverModels }),
|
|
3769
3965
|
isDefault
|
|
3770
|
-
})
|
|
3966
|
+
})
|
|
3771
3967
|
}),
|
|
3772
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3968
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
|
|
3773
3969
|
className: "dwa-subsection",
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
|
|
3777
|
-
className: "dwa-subsection-title",
|
|
3778
|
-
children: acp.label("连接配置", "Connection")
|
|
3779
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3780
|
-
className: "dwa-subsection-copy",
|
|
3781
|
-
children: acp.label("设置显示名与启动命令,高级选项按需展开。", "Set the display name and launch command; expand advanced options only when needed.")
|
|
3782
|
-
})] })
|
|
3783
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AgentDetails, {
|
|
3970
|
+
hidden: detailPage === "models",
|
|
3971
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AgentDetails, {
|
|
3784
3972
|
acp,
|
|
3973
|
+
advancedOpen: detailPage === "advanced",
|
|
3974
|
+
dirty,
|
|
3785
3975
|
detected,
|
|
3786
3976
|
form,
|
|
3787
3977
|
patch,
|
|
@@ -3802,7 +3992,7 @@ window.__ModuleLoader__.load({
|
|
|
3802
3992
|
onUseDefault: handleUseDefault,
|
|
3803
3993
|
onSave: () => void handleSave(),
|
|
3804
3994
|
onTest: () => void handleTest()
|
|
3805
|
-
})
|
|
3995
|
+
})
|
|
3806
3996
|
})
|
|
3807
3997
|
]
|
|
3808
3998
|
})]
|
|
@@ -3905,111 +4095,90 @@ window.__ModuleLoader__.load({
|
|
|
3905
4095
|
return payload;
|
|
3906
4096
|
}
|
|
3907
4097
|
/** The expanded body: connection form, workspace allow-list, env, actions. */
|
|
3908
|
-
function AgentDetails({ acp, detected, form, patch, isConfigured, newCustom, formIncomplete, idValid, idTaken, cwdInvalid, rootsInvalid, idleInvalid, mcpInvalid, saving, savedSuccess, testing, testResult, showSaveWarning, onUseDefault, onSave, onTest }) {
|
|
3909
|
-
useUi$1(acp);
|
|
3910
|
-
const [advancedOpen, setAdvancedOpen] = (0, react.useState)(false);
|
|
4098
|
+
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 }) {
|
|
3911
4099
|
const parsedCommand = splitCommandLine(form.commandLine);
|
|
3912
4100
|
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(" ")}`);
|
|
3913
4101
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
3914
|
-
newCustom && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3915
|
-
className: "dwa-form-row",
|
|
3916
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3917
|
-
className: "dwa-form-col",
|
|
3918
|
-
children: [
|
|
3919
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
3920
|
-
className: "dwa-form-label",
|
|
3921
|
-
children: acp.label("Agent ID(唯一标识,创建后不可改)", "Agent ID (unique, immutable after creation)")
|
|
3922
|
-
}),
|
|
3923
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3924
|
-
className: "dwa-input dwa-input-mono",
|
|
3925
|
-
value: form.agentId,
|
|
3926
|
-
onChange: (e) => patch({ agentId: e.target.value }),
|
|
3927
|
-
placeholder: "e.g. my-agent"
|
|
3928
|
-
}),
|
|
3929
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3930
|
-
className: idValid && !idTaken ? "dwa-hint" : "dwa-error",
|
|
3931
|
-
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.")
|
|
3932
|
-
})
|
|
3933
|
-
]
|
|
3934
|
-
})
|
|
3935
|
-
}),
|
|
3936
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3937
|
-
className: "dwa-form-row",
|
|
3938
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3939
|
-
className: "dwa-form-col",
|
|
3940
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
3941
|
-
className: "dwa-form-label",
|
|
3942
|
-
children: acp.label("显示名", "Display Name")
|
|
3943
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3944
|
-
className: "dwa-input",
|
|
3945
|
-
value: form.title,
|
|
3946
|
-
onChange: (e) => patch({ title: e.target.value }),
|
|
3947
|
-
placeholder: detected.name === "" ? acp.label("我的 Agent", "My Agent") : detected.name
|
|
3948
|
-
})]
|
|
3949
|
-
})
|
|
3950
|
-
}),
|
|
3951
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3952
|
-
className: "dwa-form-row",
|
|
3953
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3954
|
-
className: "dwa-form-col",
|
|
3955
|
-
children: [
|
|
3956
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
3957
|
-
className: "dwa-form-label",
|
|
3958
|
-
children: acp.label("启动命令(程序 + 参数)", "Launch Command (program + arguments)")
|
|
3959
|
-
}),
|
|
3960
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3961
|
-
className: "dwa-input dwa-input-mono",
|
|
3962
|
-
value: form.commandLine,
|
|
3963
|
-
onChange: (e) => patch({ commandLine: e.target.value }),
|
|
3964
|
-
placeholder: detected.defaultCommand === "" ? "e.g. codebuddy --acp" : formatCommandLine(detected.defaultCommand, detected.defaultArgs)
|
|
3965
|
-
}),
|
|
3966
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3967
|
-
className: "dwa-hint",
|
|
3968
|
-
children: commandPreview
|
|
3969
|
-
}),
|
|
3970
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3971
|
-
className: "dwa-hint",
|
|
3972
|
-
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.")
|
|
3973
|
-
})
|
|
3974
|
-
]
|
|
3975
|
-
})
|
|
3976
|
-
}),
|
|
3977
4102
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3978
|
-
|
|
3979
|
-
display: "flex",
|
|
3980
|
-
alignItems: "center",
|
|
3981
|
-
gap: 8,
|
|
3982
|
-
marginTop: 12,
|
|
3983
|
-
flexWrap: "wrap"
|
|
3984
|
-
},
|
|
4103
|
+
hidden: advancedOpen,
|
|
3985
4104
|
children: [
|
|
3986
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4105
|
+
newCustom && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4106
|
+
className: "dwa-form-row",
|
|
4107
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4108
|
+
className: "dwa-form-col",
|
|
4109
|
+
children: [
|
|
4110
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
4111
|
+
className: "dwa-form-label",
|
|
4112
|
+
children: acp.label("Agent ID(唯一标识,创建后不可改)", "Agent ID (unique, immutable after creation)")
|
|
4113
|
+
}),
|
|
4114
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4115
|
+
className: "dwa-input dwa-input-mono",
|
|
4116
|
+
"aria-label": acp.label("Agent ID", "Agent ID"),
|
|
4117
|
+
value: form.agentId,
|
|
4118
|
+
onChange: (e) => patch({ agentId: e.target.value }),
|
|
4119
|
+
placeholder: "e.g. my-agent"
|
|
4120
|
+
}),
|
|
4121
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4122
|
+
className: idValid && !idTaken ? "dwa-hint" : "dwa-error",
|
|
4123
|
+
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.")
|
|
4124
|
+
})
|
|
4125
|
+
]
|
|
4126
|
+
})
|
|
4000
4127
|
}),
|
|
4001
|
-
|
|
4002
|
-
className: "dwa-
|
|
4003
|
-
children:
|
|
4128
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4129
|
+
className: "dwa-form-row",
|
|
4130
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4131
|
+
className: "dwa-form-col",
|
|
4132
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
4133
|
+
className: "dwa-form-label",
|
|
4134
|
+
children: acp.label("显示名", "Display Name")
|
|
4135
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4136
|
+
className: "dwa-input",
|
|
4137
|
+
"aria-label": acp.label("显示名", "Display Name"),
|
|
4138
|
+
value: form.title,
|
|
4139
|
+
onChange: (e) => patch({ title: e.target.value }),
|
|
4140
|
+
placeholder: detected.name === "" ? acp.label("我的 Agent", "My Agent") : detected.name
|
|
4141
|
+
})]
|
|
4142
|
+
})
|
|
4004
4143
|
}),
|
|
4005
|
-
|
|
4006
|
-
className: "dwa-
|
|
4007
|
-
children:
|
|
4144
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4145
|
+
className: "dwa-form-row",
|
|
4146
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4147
|
+
className: "dwa-form-col",
|
|
4148
|
+
children: [
|
|
4149
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
4150
|
+
className: "dwa-form-label",
|
|
4151
|
+
children: acp.label("启动命令(程序 + 参数)", "Launch Command (program + arguments)")
|
|
4152
|
+
}),
|
|
4153
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4154
|
+
className: "dwa-input dwa-input-mono",
|
|
4155
|
+
"aria-label": acp.label("启动命令(程序 + 参数)", "Launch Command (program + arguments)"),
|
|
4156
|
+
value: form.commandLine,
|
|
4157
|
+
onChange: (e) => patch({ commandLine: e.target.value }),
|
|
4158
|
+
placeholder: detected.defaultCommand === "" ? "e.g. codebuddy --acp" : formatCommandLine(detected.defaultCommand, detected.defaultArgs)
|
|
4159
|
+
}),
|
|
4160
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4161
|
+
className: "dwa-hint",
|
|
4162
|
+
children: commandPreview
|
|
4163
|
+
}),
|
|
4164
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4165
|
+
className: "dwa-hint",
|
|
4166
|
+
children: acp.label("含空格的程序路径请加引号。", "Quote the program path if it contains spaces.")
|
|
4167
|
+
})
|
|
4168
|
+
]
|
|
4169
|
+
})
|
|
4170
|
+
}),
|
|
4171
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkspaceBlock, {
|
|
4172
|
+
acp,
|
|
4173
|
+
form,
|
|
4174
|
+
patch,
|
|
4175
|
+
cwdInvalid,
|
|
4176
|
+
rootsInvalid
|
|
4008
4177
|
})
|
|
4009
4178
|
]
|
|
4010
4179
|
}),
|
|
4011
4180
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4012
|
-
|
|
4181
|
+
hidden: !advancedOpen,
|
|
4013
4182
|
children: [
|
|
4014
4183
|
!newCustom && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4015
4184
|
className: "dwa-default-hint",
|
|
@@ -4022,7 +4191,7 @@ window.__ModuleLoader__.load({
|
|
|
4022
4191
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("code", {
|
|
4023
4192
|
className: "dwa-input-mono",
|
|
4024
4193
|
style: {
|
|
4025
|
-
background: "#0000000a",
|
|
4194
|
+
background: "var(--dsw-alias-markdown-inline-code, #0000000a)",
|
|
4026
4195
|
padding: "2px 6px",
|
|
4027
4196
|
borderRadius: 4
|
|
4028
4197
|
},
|
|
@@ -4054,13 +4223,6 @@ window.__ModuleLoader__.load({
|
|
|
4054
4223
|
})]
|
|
4055
4224
|
})
|
|
4056
4225
|
}),
|
|
4057
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkspaceBlock, {
|
|
4058
|
-
acp,
|
|
4059
|
-
form,
|
|
4060
|
-
patch,
|
|
4061
|
-
cwdInvalid,
|
|
4062
|
-
rootsInvalid
|
|
4063
|
-
}),
|
|
4064
4226
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4065
4227
|
className: "dwa-form-row",
|
|
4066
4228
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -4072,19 +4234,14 @@ window.__ModuleLoader__.load({
|
|
|
4072
4234
|
}),
|
|
4073
4235
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4074
4236
|
className: "dwa-input dwa-input-mono",
|
|
4237
|
+
"aria-label": acp.label("空闲释放(毫秒)", "Idle Release (ms)"),
|
|
4075
4238
|
value: form.idleStr,
|
|
4076
4239
|
onChange: (e) => patch({ idleStr: e.target.value }),
|
|
4077
4240
|
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)`)
|
|
4078
4241
|
}),
|
|
4079
4242
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4080
4243
|
className: idleInvalid ? "dwa-error" : "dwa-hint",
|
|
4081
|
-
children: idleInvalid ? acp.label("必须是 0(永不释放)或 [1000, 86400000] 之间的整数毫秒。", "Must be 0 (never release) or an integer in [1000, 86400000] ms.") : /* @__PURE__ */ (0, react_jsx_runtime.
|
|
4082
|
-
acp.label("空闲超过此时长就挂起进程(会话保留,下一条消息自动恢复)。", "The process is parked once it has been idle this long (the session is kept and resumes on the next message)."),
|
|
4083
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("br", {}),
|
|
4084
|
-
acp.label("0 = 永不释放;回合在跑、取消未结算或审批待答时不释放。", "0 = never; a process with a running turn, an unsettled cancel, or a pending approval is never released."),
|
|
4085
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("br", {}),
|
|
4086
|
-
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.")
|
|
4087
|
-
] })
|
|
4244
|
+
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.") })
|
|
4088
4245
|
})
|
|
4089
4246
|
]
|
|
4090
4247
|
})
|
|
@@ -4174,6 +4331,7 @@ window.__ModuleLoader__.load({
|
|
|
4174
4331
|
minHeight: 96,
|
|
4175
4332
|
resize: "vertical"
|
|
4176
4333
|
},
|
|
4334
|
+
"aria-label": acp.label("MCP 服务器(JSON)", "MCP Servers (JSON)"),
|
|
4177
4335
|
value: form.mcpText,
|
|
4178
4336
|
onChange: (e) => patch({ mcpText: e.target.value }),
|
|
4179
4337
|
spellCheck: false,
|
|
@@ -4185,15 +4343,29 @@ window.__ModuleLoader__.load({
|
|
|
4185
4343
|
}),
|
|
4186
4344
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4187
4345
|
className: "dwa-hint",
|
|
4188
|
-
children: acp.label("
|
|
4346
|
+
children: acp.label("额外追加给智能体的 MCP 服务器,不影响其已有配置。", "Additional MCP servers for the agent; its own configuration is unchanged.")
|
|
4189
4347
|
})
|
|
4190
4348
|
]
|
|
4191
4349
|
})
|
|
4192
4350
|
]
|
|
4193
4351
|
}),
|
|
4352
|
+
!advancedOpen && (mcpInvalid || idleInvalid) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4353
|
+
className: "dwa-error",
|
|
4354
|
+
role: "alert",
|
|
4355
|
+
children: acp.label("请检查「高级」中的无效配置。", "Check the invalid settings in Advanced.")
|
|
4356
|
+
}),
|
|
4357
|
+
advancedOpen && (!idValid || idTaken || cwdInvalid || rootsInvalid || parsedCommand.command === "") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4358
|
+
className: "dwa-error",
|
|
4359
|
+
role: "alert",
|
|
4360
|
+
children: acp.label("请检查「连接」中的未完成或无效配置。", "Check the incomplete or invalid settings in Connection.")
|
|
4361
|
+
}),
|
|
4194
4362
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4195
4363
|
className: "dwa-form-actions",
|
|
4196
4364
|
children: [
|
|
4365
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4366
|
+
className: "dwa-hint",
|
|
4367
|
+
children: isConfigured ? dirty ? acp.label("有未保存的更改", "Unsaved changes") : acp.label("配置已保存", "Settings saved") : ""
|
|
4368
|
+
}),
|
|
4197
4369
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4198
4370
|
className: "dwa-btn",
|
|
4199
4371
|
onClick: onTest,
|
|
@@ -4204,8 +4376,8 @@ window.__ModuleLoader__.load({
|
|
|
4204
4376
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4205
4377
|
className: "dwa-btn dwa-btn-primary",
|
|
4206
4378
|
onClick: onSave,
|
|
4207
|
-
disabled: saving || testing || formIncomplete,
|
|
4208
|
-
children: saving ? acp.label("保存中...", "Saving...") : savedSuccess ? acp.label("✓ 已保存", "✓ Saved") : isConfigured ? acp.label("
|
|
4379
|
+
disabled: saving || testing || formIncomplete || isConfigured && !dirty,
|
|
4380
|
+
children: saving ? acp.label("保存中...", "Saving...") : savedSuccess ? acp.label("✓ 已保存", "✓ Saved") : isConfigured ? acp.label("保存更改", "Save changes") : acp.label("保存并启用", "Save & Enable")
|
|
4209
4381
|
}),
|
|
4210
4382
|
showSaveWarning && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4211
4383
|
className: "dwa-hint",
|
|
@@ -4221,7 +4393,7 @@ window.__ModuleLoader__.load({
|
|
|
4221
4393
|
fontSize: 12,
|
|
4222
4394
|
whiteSpace: "pre-wrap",
|
|
4223
4395
|
wordBreak: "break-all",
|
|
4224
|
-
color: testResult.ok ? "
|
|
4396
|
+
color: testResult.ok ? "var(--ntr-success)" : "var(--ntr-danger)"
|
|
4225
4397
|
},
|
|
4226
4398
|
children: [testResult.ok ? "✓ " : "✕ ", testResult.text]
|
|
4227
4399
|
})
|
|
@@ -4281,7 +4453,7 @@ window.__ModuleLoader__.load({
|
|
|
4281
4453
|
}),
|
|
4282
4454
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4283
4455
|
className: "dwa-hint",
|
|
4284
|
-
children: acp.label("
|
|
4456
|
+
children: acp.label("聊天使用会话工作区;此处用于直连会话或宿主未提供工作区时。", "Chats use their session workspace; this applies to direct sessions or when the host provides no workspace.")
|
|
4285
4457
|
}),
|
|
4286
4458
|
!form.rootsOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4287
4459
|
className: "dwa-hint",
|
|
@@ -4610,7 +4782,7 @@ window.__ModuleLoader__.load({
|
|
|
4610
4782
|
onChange: (e) => void toggleAutoDiscover(e.target.checked),
|
|
4611
4783
|
style: {
|
|
4612
4784
|
margin: 0,
|
|
4613
|
-
accentColor: "#2563eb"
|
|
4785
|
+
accentColor: "var(--dsw-alias-state-business-primary, #2563eb)"
|
|
4614
4786
|
}
|
|
4615
4787
|
}), acp.label("自动发现新模型", "Auto-discover new models")]
|
|
4616
4788
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -4650,7 +4822,7 @@ window.__ModuleLoader__.load({
|
|
|
4650
4822
|
fontWeight: 400
|
|
4651
4823
|
},
|
|
4652
4824
|
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."),
|
|
4653
|
-
children: acp.label("
|
|
4825
|
+
children: acp.label("仅影响菜单可见性", "Menu visibility only")
|
|
4654
4826
|
})]
|
|
4655
4827
|
}),
|
|
4656
4828
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -4672,6 +4844,7 @@ window.__ModuleLoader__.load({
|
|
|
4672
4844
|
children: probing ? acp.label("模型检测中...", "Probing models...") : acp.label("检测可用模型", "Detect available models")
|
|
4673
4845
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4674
4846
|
className: "dwa-input dwa-model-search",
|
|
4847
|
+
"aria-label": acp.label("搜索模型", "Search models"),
|
|
4675
4848
|
value: search,
|
|
4676
4849
|
onChange: (e) => setSearch(e.target.value),
|
|
4677
4850
|
placeholder: acp.label("搜索模型…", "Search models…")
|
|
@@ -4789,7 +4962,7 @@ window.__ModuleLoader__.load({
|
|
|
4789
4962
|
className: "dwa-model-list",
|
|
4790
4963
|
children: [selectedChoices.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4791
4964
|
className: "dwa-hint dwa-model-empty",
|
|
4792
|
-
children: acp.label("
|
|
4965
|
+
children: acp.label("尚未选择模型,从「全部模型」中加入。", "No models selected. Add from All models.")
|
|
4793
4966
|
}), selectedChoices.map((choice) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
4794
4967
|
type: "button",
|
|
4795
4968
|
className: "dwa-model-row is-on",
|
|
@@ -5088,10 +5261,10 @@ window.__ModuleLoader__.load({
|
|
|
5088
5261
|
* the entry point for conversations no agent has served.
|
|
5089
5262
|
*/
|
|
5090
5263
|
const STATE_COLORS = {
|
|
5091
|
-
ready: "#22c55e",
|
|
5092
|
-
starting: "#eab308",
|
|
5093
|
-
error: "#ef4444",
|
|
5094
|
-
stopped: "#9ca3af"
|
|
5264
|
+
ready: "var(--dsw-alias-state-success-primary, #22c55e)",
|
|
5265
|
+
starting: "var(--dsw-alias-state-warn-primary, #eab308)",
|
|
5266
|
+
error: "var(--dsw-alias-state-error-primary, #ef4444)",
|
|
5267
|
+
stopped: "var(--dsw-alias-state-idle-primary, #9ca3af)"
|
|
5095
5268
|
};
|
|
5096
5269
|
function agentStateText(acp, state) {
|
|
5097
5270
|
switch (state) {
|
|
@@ -6465,6 +6638,130 @@ window.__ModuleLoader__.load({
|
|
|
6465
6638
|
});
|
|
6466
6639
|
}
|
|
6467
6640
|
//#endregion
|
|
6641
|
+
//#region src/client/permission-dock.tsx
|
|
6642
|
+
/**
|
|
6643
|
+
* Pending ACP permission asks for the staged DSH conversation, rendered as
|
|
6644
|
+
* composer-width entries above the composer card (`conversation.input.dock`).
|
|
6645
|
+
* The slot itself spans the conversation column; the dock mirrors the host's
|
|
6646
|
+
* InputBar width formula so the cards line up with the input box.
|
|
6647
|
+
*
|
|
6648
|
+
* The host broadcasts every ask as `permission/request`, carrying the DSH chat
|
|
6649
|
+
* session id when the ask belongs to a conversation. This dock is the primary
|
|
6650
|
+
* answer surface: it renders exactly the asks whose `dshSessionId` is the
|
|
6651
|
+
* conversation it was mounted for, and nothing otherwise. There is no
|
|
6652
|
+
* ACP-mode gate — the frame set itself is the gate, so an ordinary
|
|
6653
|
+
* conversation shows this card if and only if it actually has an ask.
|
|
6654
|
+
*
|
|
6655
|
+
* The ask's description and options are the agent's own: buttons appear in the
|
|
6656
|
+
* agent's order with the agent's names (including "Always Allow"), and
|
|
6657
|
+
* `kind` is not rendered. A separate cancel button answers with no option,
|
|
6658
|
+
* which the host forwards as `cancelled`. No Enter/Escape handlers: the
|
|
6659
|
+
* composer owns its keyboard, and these are ordinary focusable buttons.
|
|
6660
|
+
*
|
|
6661
|
+
* Multiple asks stack in ARRIVAL order, oldest first: the question ignored
|
|
6662
|
+
* longest stays at the top. The list is capped in height by CSS and scrolls.
|
|
6663
|
+
* Asks without a chat identity never appear here — they stay in the
|
|
6664
|
+
* settings-panel ledger, the cross-session mirror.
|
|
6665
|
+
*/
|
|
6666
|
+
/** Tick interval for the countdown (seconds are all the label shows). */
|
|
6667
|
+
const COUNTDOWN_TICK_MS = 1e3;
|
|
6668
|
+
function PermissionDock({ acp, sessionId }) {
|
|
6669
|
+
ensureAcpStyle();
|
|
6670
|
+
const ui = useUi$2(acp);
|
|
6671
|
+
const dshSessionId = String(sessionId);
|
|
6672
|
+
const pending = permissionsForSession(ui.permissions, dshSessionId);
|
|
6673
|
+
const counting = pending.some((ask) => ask.timeoutMode !== "wait" && ask.deadlineAt !== void 0);
|
|
6674
|
+
const [now, setNow] = (0, react.useState)(() => Date.now());
|
|
6675
|
+
(0, react.useEffect)(() => {
|
|
6676
|
+
if (!counting) return;
|
|
6677
|
+
setNow(Date.now());
|
|
6678
|
+
const timer = setInterval(() => {
|
|
6679
|
+
setNow(Date.now());
|
|
6680
|
+
}, COUNTDOWN_TICK_MS);
|
|
6681
|
+
return () => {
|
|
6682
|
+
clearInterval(timer);
|
|
6683
|
+
};
|
|
6684
|
+
}, [counting]);
|
|
6685
|
+
if (pending.length === 0) return null;
|
|
6686
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6687
|
+
className: "ntr-permission-dock",
|
|
6688
|
+
role: "region",
|
|
6689
|
+
"aria-label": acp.label("待处理的权限请求", "Pending permission requests"),
|
|
6690
|
+
children: pending.map((permission) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PermissionAskCard, {
|
|
6691
|
+
acp,
|
|
6692
|
+
permission,
|
|
6693
|
+
now
|
|
6694
|
+
}, permission.requestId))
|
|
6695
|
+
});
|
|
6696
|
+
}
|
|
6697
|
+
function PermissionAskCard(props) {
|
|
6698
|
+
const { acp, permission, now } = props;
|
|
6699
|
+
const [busy, setBusy] = (0, react.useState)(false);
|
|
6700
|
+
const [error, setError] = (0, react.useState)();
|
|
6701
|
+
const remaining = deadlineRemainingLabel(permission.deadlineAt, now, permission.timeoutMode);
|
|
6702
|
+
const expired = remaining === PERMISSION_DEADLINE_EXPIRED;
|
|
6703
|
+
const respond = (optionId) => {
|
|
6704
|
+
if (busy) return;
|
|
6705
|
+
setBusy(true);
|
|
6706
|
+
setError(void 0);
|
|
6707
|
+
acp.respondPermission(permission.requestId, optionId).catch((failure) => {
|
|
6708
|
+
setError(failure instanceof Error ? failure.message : String(failure));
|
|
6709
|
+
}).finally(() => {
|
|
6710
|
+
setBusy(false);
|
|
6711
|
+
});
|
|
6712
|
+
};
|
|
6713
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6714
|
+
className: "ntr-permission-card",
|
|
6715
|
+
children: [
|
|
6716
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6717
|
+
className: "ntr-permission-head",
|
|
6718
|
+
children: [
|
|
6719
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6720
|
+
className: "ntr-permission-tool",
|
|
6721
|
+
children: permission.toolName
|
|
6722
|
+
}),
|
|
6723
|
+
permission.reason !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6724
|
+
className: "ntr-permission-reason",
|
|
6725
|
+
title: permission.reason,
|
|
6726
|
+
children: permission.reason
|
|
6727
|
+
}),
|
|
6728
|
+
remaining !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6729
|
+
className: `ntr-permission-deadline${expired ? " is-expired" : ""}`,
|
|
6730
|
+
children: expired ? acp.label("已超时", "expired") : acp.label(`剩余 ${remaining}`, `${remaining} left`)
|
|
6731
|
+
})
|
|
6732
|
+
]
|
|
6733
|
+
}),
|
|
6734
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6735
|
+
className: "ntr-permission-actions",
|
|
6736
|
+
children: [permission.options.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6737
|
+
type: "button",
|
|
6738
|
+
className: "ntr-permission-option",
|
|
6739
|
+
disabled: busy,
|
|
6740
|
+
title: option.name,
|
|
6741
|
+
onClick: () => {
|
|
6742
|
+
respond(option.optionId);
|
|
6743
|
+
},
|
|
6744
|
+
children: option.name
|
|
6745
|
+
}, option.optionId)), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6746
|
+
type: "button",
|
|
6747
|
+
className: "ntr-permission-cancel",
|
|
6748
|
+
disabled: busy,
|
|
6749
|
+
title: acp.label("取消这次询问(不选择任何选项)", "Cancel this ask without choosing an option"),
|
|
6750
|
+
onClick: () => {
|
|
6751
|
+
respond();
|
|
6752
|
+
},
|
|
6753
|
+
children: acp.label("取消", "Cancel")
|
|
6754
|
+
})]
|
|
6755
|
+
}),
|
|
6756
|
+
error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6757
|
+
className: "ntr-permission-error",
|
|
6758
|
+
role: "alert",
|
|
6759
|
+
children: error
|
|
6760
|
+
})
|
|
6761
|
+
]
|
|
6762
|
+
});
|
|
6763
|
+
}
|
|
6764
|
+
//#endregion
|
|
6468
6765
|
//#region src/client/model-seat.tsx
|
|
6469
6766
|
/** Exact key of the composer's model seat (a `single`, session-scoped slot). */
|
|
6470
6767
|
const MODEL_SEAT_KEY = "conversation.input.model";
|
|
@@ -7125,6 +7422,12 @@ window.__ModuleLoader__.load({
|
|
|
7125
7422
|
order: 5,
|
|
7126
7423
|
inject: (sessionId) => chatFace(sessionId)
|
|
7127
7424
|
}, AcpComposerAgentTag)), "dsh-ntr: composer agent tag");
|
|
7425
|
+
ctx.effect(() => ctx.slots.inject("conversation.input.dock", () => ctx.slots.register({
|
|
7426
|
+
name: "conversation.input.dock",
|
|
7427
|
+
id: "acp-permissions",
|
|
7428
|
+
order: 10,
|
|
7429
|
+
inject: (sessionId) => chatFace(sessionId)
|
|
7430
|
+
}, PermissionDock)), "dsh-ntr: conversation permission dock");
|
|
7128
7431
|
/**
|
|
7129
7432
|
* The client runtime's session list store, read structurally. Used to find
|
|
7130
7433
|
* the session the composer is staged on and whether it runs the ACP preset —
|