dsh-ntr 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,73 @@
1
+ /**
2
+ * The NTR settings dialog, opened from the agent base's empty-roster menu.
3
+ *
4
+ * WHY A DIALOG OF OUR OWN: the host settings shell owns its open state and
5
+ * exposes no programmatic way in. The sidebar seat that receives `openSettings`
6
+ * (`settings.launcher`) is a single-occupant slot already held by the account
7
+ * menu, and `openSection` is only handed to `settings.onboarding` registrants —
8
+ * so a conversation surface cannot drive the shell's modal. This dialog mounts
9
+ * the SAME `AcpSettingsSection` the shell mounts, on the frame's overlay layer
10
+ * (`shell.overlay`): one settings surface, two entrances, no duplicated
11
+ * configuration logic.
12
+ *
13
+ * The trigger (composer model seat) and this dialog (root overlay) live in
14
+ * unrelated slot trees, so the open state is the module-level store in
15
+ * `acp-ui.tsx` (`openAcpSettingsDialog`).
16
+ */
17
+
18
+ import { useEffect } from 'react'
19
+ import { AcpSettingsSection } from './panel.tsx'
20
+ import {
21
+ closeAcpSettingsDialog,
22
+ ensureAcpStyle,
23
+ useAcpSettingsDialogOpen,
24
+ } from './acp-ui.tsx'
25
+ import type { AcpStore } from './store.ts'
26
+
27
+ /** The root overlay entry's inject face. */
28
+ export interface AcpSettingsDialogProps {
29
+ acp: AcpStore
30
+ }
31
+
32
+ /** Frame-wide NTR settings surface; renders nothing while closed. */
33
+ export function AcpSettingsDialog(props: AcpSettingsDialogProps) {
34
+ ensureAcpStyle()
35
+ const { acp } = props
36
+ const open = useAcpSettingsDialogOpen()
37
+ useEffect(() => {
38
+ if (!open) return
39
+ const onKey = (event: KeyboardEvent): void => {
40
+ if (event.key !== 'Escape') return
41
+ event.preventDefault()
42
+ event.stopPropagation()
43
+ closeAcpSettingsDialog()
44
+ }
45
+ document.addEventListener('keydown', onKey, true)
46
+ return () => { document.removeEventListener('keydown', onKey, true) }
47
+ }, [open])
48
+ if (!open) return null
49
+ const title = acp.label('NTR 设置', 'NTR settings')
50
+ return (
51
+ <div className="ntr-acp-dialog-layer">
52
+ <div className="ntr-acp-dialog-mask" aria-hidden onClick={closeAcpSettingsDialog} />
53
+ <div className="ntr-acp-dialog" role="dialog" aria-modal="true" aria-label={title}>
54
+ <div className="ntr-acp-dialog-head">
55
+ <span className="ntr-acp-dialog-title">{title}</span>
56
+ <button
57
+ type="button"
58
+ className="ntr-acp-dialog-close"
59
+ title={acp.label('关闭', 'Close')}
60
+ aria-label={acp.label('关闭 NTR 设置', 'Close NTR settings')}
61
+ autoFocus
62
+ onClick={closeAcpSettingsDialog}
63
+ >
64
+ ✕
65
+ </button>
66
+ </div>
67
+ <div className="ntr-acp-dialog-body">
68
+ <AcpSettingsSection acp={acp} />
69
+ </div>
70
+ </div>
71
+ </div>
72
+ )
73
+ }
@@ -91,6 +91,12 @@ export interface UiState {
91
91
  localeRev: number
92
92
  stream: 'init' | 'live' | 'down'
93
93
  agents: AgentView[]
94
+ /**
95
+ * Whether the host has answered `agents/list` at least once in this page.
96
+ * `agents: []` alone cannot tell "no agent configured" from "not read yet";
97
+ * a surface that offers a setup entry on an empty roster must wait for this.
98
+ */
99
+ agentsLoaded: boolean
94
100
  sessions: SessionView[]
95
101
  activeSessionId?: string
96
102
  blocks: Block[]
@@ -515,6 +521,7 @@ export class AcpStore {
515
521
  localeRev: 0,
516
522
  stream: 'init',
517
523
  agents: [],
524
+ agentsLoaded: false,
518
525
  sessions: [],
519
526
  blocks: [],
520
527
  permissions: [],
@@ -744,6 +751,7 @@ export class AcpStore {
744
751
  // Absent on an older host: keep the settings-panel card (degraded path).
745
752
  this.mutate({
746
753
  agents,
754
+ agentsLoaded: true,
747
755
  sessions,
748
756
  defaultAgent: defaultAgentInfo?.agentId,
749
757
  detectedAgents,