@xingjisoft/neutrino 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/web/index.html CHANGED
@@ -1,442 +1,465 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, interactive-widget=resizes-content" />
6
- <meta name="color-scheme" content="dark" />
7
- <meta name="theme-color" content="#151517" />
8
- <script>
9
- // Switching to the Pro workspace navigates only once the #151515 curtain
10
- // is opaque. Cover the page here, before the first paint, so a slow
11
- // module load cannot flash the freshly loaded /pro page before app.js
12
- // takes the curtain over. app.js removes the class; the timer is a
13
- // safety net for when the module cannot run at all.
14
- try {
15
- var proPath = location.pathname === "/pro" || location.pathname.startsWith("/pro/");
16
- var proStart = Number(sessionStorage.getItem("neutrino.pro.transition")) || 0;
17
- if (proPath && proStart && Date.now() - proStart < 8000) {
18
- document.documentElement.classList.add("pro-transitioning");
19
- setTimeout(function () {
20
- document.documentElement.classList.remove("pro-transitioning");
21
- }, 8000);
22
- }
23
- } catch (error) { /* Storage may be blocked; the page still works. */ }
24
- </script>
25
- <title>Neutrino</title>
26
- <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f9fafb' stroke-width='1.7'%3E%3Cellipse cx='12' cy='12' rx='9.4' ry='3.8' transform='rotate(-30 12 12)'/%3E%3Ccircle cx='12' cy='12' r='3.1'/%3E%3C/svg%3E" />
27
- <link rel="stylesheet" href="style.css" />
28
- </head>
29
- <body>
30
- <div id="app">
31
- <aside id="sidebar">
32
- <header class="brand">
33
- <button id="brand-logo" class="logo brand-logo" type="button" title="Switch to Pro mode" aria-label="Switch to Pro mode" data-i18n-title="Switch to Pro mode" data-i18n-aria-label="Switch to Pro mode">
34
- <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
35
- <ellipse cx="12" cy="12" rx="9.4" ry="3.8" transform="rotate(-30 12 12)" stroke="currentColor" stroke-width="1.7" />
36
- <circle cx="12" cy="12" r="3.1" stroke="currentColor" stroke-width="1.7" />
37
- </svg>
38
- </button>
39
- <div class="brand-text">
40
- <strong id="brand-name">Neutrino</strong>
41
- <span id="status" class="status">connecting…</span>
42
- </div>
43
- <div class="brand-actions">
44
- <button id="refresh" class="icon-btn" type="button" title="Refresh conversations" aria-label="Refresh conversations" data-i18n-title="Refresh conversations" data-i18n-aria-label="Refresh conversations">
45
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12a9 9 0 1 1-2.64-6.36" /><path d="M21 3v6h-6" /></svg>
46
- </button>
47
- <button id="settings-open" class="icon-btn" type="button" title="Settings" aria-label="Settings" data-i18n-title="Settings" data-i18n-aria-label="Settings">
48
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z" /><circle cx="12" cy="12" r="3" /></svg>
49
- </button>
50
- </div>
51
- </header>
52
- <div id="pro-tip" class="pro-tip hidden" role="note">
53
- <span data-i18n="Click the badge to switch to Pro mode">Click the badge to switch to Pro mode</span>
54
- <button id="pro-tip-close" class="pro-tip-close" type="button" title="Dismiss" aria-label="Dismiss" data-i18n-title="Dismiss" data-i18n-aria-label="Dismiss">
55
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12" /></svg>
56
- </button>
57
- </div>
58
-
59
- <div class="sidebar-tools">
60
- <button id="new-chat" class="new-chat" type="button" title="New conversation" data-i18n-title="New conversation">
61
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14" /></svg>
62
- <span data-i18n="New conversation">New conversation</span>
63
- </button>
64
- <button id="workspace-button" class="workspace-button" type="button" title="Working directory" data-i18n-title="Working directory">
65
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 7.5A2.5 2.5 0 0 1 5.5 5H9l2 2.5h7.5A2.5 2.5 0 0 1 21 10v7a2.5 2.5 0 0 1-2.5 2.5h-13A2.5 2.5 0 0 1 3 17z" /></svg>
66
- <span id="workspace-label" class="workspace-label" data-i18n="All directories">All directories</span>
67
- <svg class="workspace-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 18 6-6-6-6" /></svg>
68
- </button>
69
- <button id="agents-open" class="workspace-button" type="button" title="Other agents" data-i18n-title="Other agents">
70
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12a9 9 0 1 0 3-6.7" /><path d="M3 4v5h5" /><path d="M12 7v5l3 2" /></svg>
71
- <span class="workspace-label" data-i18n="Other agents">Other agents</span>
72
- <svg class="workspace-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 18 6-6-6-6" /></svg>
73
- </button>
74
- </div>
75
-
76
- <div id="sessions" class="sessions"></div>
77
- <footer class="sidebar-foot">
78
- <span class="foot-note" data-i18n="Local agent console">Local agent console</span>
79
- <label class="language-picker" title="Interface language" data-i18n-title="Interface language">
80
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9" /><path d="M3 12h18M12 3c2.5 2.6 3.8 5.6 3.8 9S14.5 18.4 12 21c-2.5-2.6-3.8-5.6-3.8-9S9.5 5.6 12 3z" /></svg>
81
- <select id="language-select" aria-label="Interface language" data-i18n-aria-label="Interface language">
82
- <option value="en">English</option>
83
- <option value="zh">简体中文</option>
84
- </select>
85
- </label>
86
- </footer>
87
- </aside>
88
-
89
- <main id="main">
90
- <header id="main-header" class="main-header">
91
- <button id="back-to-menu" class="icon-btn back-to-menu" type="button" title="Back to conversations" aria-label="Back to conversations" data-i18n-title="Back to conversations" data-i18n-aria-label="Back to conversations" aria-controls="sidebar">
92
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m12 5-7 7 7 7M5 12h14" /></svg>
93
- </button>
94
- <div class="main-title">
95
- <h1 id="session-title" data-i18n="Select a conversation">Select a conversation</h1>
96
- <div id="session-sub" class="sub"></div>
97
- </div>
98
- <div id="controls" class="controls"></div>
99
- <button id="pro-exit" class="control pro-exit hidden" type="button" title="Exit Pro mode" aria-label="Exit Pro mode" data-i18n-title="Exit Pro mode" data-i18n-aria-label="Exit Pro mode">
100
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m12 5-7 7 7 7M5 12h14" /></svg>
101
- <span data-i18n="Exit Pro mode">Exit Pro mode</span>
102
- </button>
103
- </header>
104
-
105
- <aside id="plan-card" class="plan-card hidden" aria-live="polite"></aside>
106
-
107
- <section id="messages" class="messages">
108
- <div class="empty">
109
- <span class="empty-mark" aria-hidden="true">
110
- <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
111
- <ellipse cx="12" cy="12" rx="9.4" ry="3.8" transform="rotate(-30 12 12)" stroke="currentColor" stroke-width="1.7" />
112
- <circle cx="12" cy="12" r="3.1" stroke="currentColor" stroke-width="1.7" />
113
- </svg>
114
- </span>
115
- <strong data-i18n="No conversation open">No conversation open</strong>
116
- <span data-i18n="Choose a conversation from the sidebar to view it.">Choose a conversation from the sidebar to view it.</span>
117
- <button id="empty-new-chat" class="control primary" type="button" data-i18n="New conversation">New conversation</button>
118
- </div>
119
- </section>
120
-
121
- <div id="approval" class="approval hidden" role="alert" aria-live="assertive"></div>
122
-
123
- <footer id="agent-actions" class="agent-actions hidden">
124
- <p id="agent-migrate-feedback" class="form-feedback error" role="status" aria-live="polite"></p>
125
- <button id="agent-migrate" class="control primary" type="button" data-i18n="Migrate session" title="Copy this history into a new Neutrino conversation in the same folder" data-i18n-title="Copy this history into a new Neutrino conversation in the same folder">Migrate session</button>
126
- </footer>
127
-
128
- <footer id="composer" class="composer hidden">
129
- <div class="composer-inner">
130
- <div class="composer-card">
131
- <textarea id="input" rows="1" placeholder="Message Neutrino…" aria-label="Message" data-i18n-placeholder="Message Neutrino…"></textarea>
132
- <details id="model-picker" class="model-picker pro-preset-control hidden">
133
- <summary id="model-picker-summary" aria-label="Conversation model" data-i18n-aria-label="Conversation model"><span id="model-picker-label"></span><svg class="pro-preset-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m7 10 5 5 5-5" /></svg></summary>
134
- <div class="pro-preset-card model-picker-card">
135
- <div class="pro-preset-heading"><span data-i18n="Conversation model">Conversation model</span><strong id="model-intensity-label"></strong></div>
136
- <div class="model-picker-fields">
137
- <label><span data-i18n="Provider">Provider</span><select id="model-provider"></select></label>
138
- <label><span data-i18n="Model">Model</span><select id="model-name"></select></label>
139
- </div>
140
- <label class="pro-slider-label" for="model-intensity" data-i18n="Thinking intensity">Thinking intensity</label>
141
- <div id="model-intensity-slider" class="pro-preset-slider">
142
- <div class="pro-slider-track" aria-hidden="true"><div class="pro-slider-fill"></div></div>
143
- <div id="model-intensity-stops" class="pro-slider-stops" aria-hidden="true"></div>
144
- <input id="model-intensity" type="range" min="0" max="0" step="1" value="0" aria-label="Thinking intensity" data-i18n-aria-label="Thinking intensity" />
145
- </div>
146
- <div id="model-intensity-ticks" class="pro-preset-ticks"></div>
147
- <p id="model-feedback" class="form-feedback" role="status" aria-live="polite"></p>
148
- </div>
149
- </details>
150
- <details id="pro-preset-control" class="pro-preset-control hidden">
151
- <summary aria-label="Pro preset" data-i18n-aria-label="Pro preset"><span id="pro-preset-label">Pro</span><svg class="pro-preset-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m7 10 5 5 5-5" /></svg></summary>
152
- <div class="pro-preset-card">
153
- <div class="pro-preset-heading"><span data-i18n="Neutrino Pro">Neutrino Pro</span><strong id="pro-preset-name"></strong></div>
154
- <label class="pro-slider-label" for="pro-preset-range" data-i18n="Preset">Preset</label>
155
- <div id="pro-preset-slider" class="pro-preset-slider">
156
- <div class="pro-slider-track" aria-hidden="true">
157
- <div class="pro-slider-fill"></div>
158
- <div class="pro-slider-meteors">
159
- <span class="pro-slider-meteor"></span><span class="pro-slider-meteor"></span><span class="pro-slider-meteor"></span><span class="pro-slider-meteor"></span>
160
- </div>
161
- </div>
162
- <div id="pro-slider-stops" class="pro-slider-stops" aria-hidden="true"></div>
163
- <input id="pro-preset-range" type="range" min="0" max="0" step="1" value="0" aria-label="Pro preset" data-i18n-aria-label="Pro preset" />
164
- </div>
165
- <div id="pro-preset-ticks" class="pro-preset-ticks"></div>
166
- <details class="pro-model-details" id="pro-model-details">
167
- <summary><span data-i18n="Model details">Model details</span><svg class="pro-model-details-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m7 10 5 5 5-5" /></svg></summary>
168
- <div id="pro-preset-models" class="pro-preset-models"></div>
169
- </details>
170
- <p id="pro-preset-note" class="settings-note"></p>
171
- <p id="pro-preset-feedback" class="form-feedback error" role="status" aria-live="polite"></p>
172
- </div>
173
- </details>
174
- <button id="send" class="primary" type="button" title="Send message" aria-label="Send message" data-i18n-title="Send message" data-i18n-aria-label="Send message">
175
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path class="send-icon" d="M12 19V5M5 12l7-7 7 7" /><rect class="pause-icon" x="5" y="5" width="14" height="14" rx="2" fill="currentColor" stroke="none" /></svg>
176
- </button>
177
- </div>
178
- <div class="composer-hint">
179
- <span><kbd>Enter</kbd> <span data-i18n="to send">to send</span></span>
180
- <span class="hint-sep">·</span>
181
- <span><kbd>Shift</kbd> + <kbd>Enter</kbd> <span data-i18n="for a new line">for a new line</span></span>
182
- </div>
183
- </div>
184
- </footer>
185
- </main>
186
- </div>
187
-
188
- <dialog id="settings-dialog" class="settings-dialog" aria-labelledby="settings-title">
189
- <form id="settings-form">
190
- <header class="settings-header">
191
- <div>
192
- <h2 id="settings-title" data-i18n="Settings">Settings</h2>
193
- <p class="settings-sub" data-i18n="Models, approvals, and console access.">Models, approvals, and console access.</p>
194
- </div>
195
- <button id="settings-close" class="icon-btn" type="button" aria-label="Close settings" data-i18n-aria-label="Close settings">
196
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12" /></svg>
197
- </button>
198
- </header>
199
- <div class="settings-fields">
200
- <h3 data-i18n="Interface">Interface</h3>
201
- <div class="settings-grid">
202
- <label><span data-i18n="Language">Language</span>
203
- <select id="settings-language">
204
- <option value="en">English</option>
205
- <option value="zh">简体中文</option>
206
- </select>
207
- </label>
208
- <label><span data-i18n="Default approval mode">Default approval mode</span>
209
- <select id="settings-approval">
210
- <option value="request" data-i18n="Request Approval">Request Approval</option>
211
- <option value="auto" data-i18n="Auto Approval">Auto Approval</option>
212
- </select>
213
- </label>
214
- </div>
215
- <label class="checkbox-label standard-only"><input id="settings-plan" type="checkbox" /> <span data-i18n="Plan-first turns">Plan-first turns</span></label>
216
- <p class="settings-note standard-only" data-i18n="Split multi-step requests into a plan before answering.">Split multi-step requests into a plan before answering.</p>
217
- <h3 class="standard-only" data-i18n="Defaults for new conversations">Defaults for new conversations</h3>
218
- <div class="settings-grid standard-only">
219
- <label><span data-i18n="Provider">Provider</span><select id="default-provider"></select></label>
220
- <label><span data-i18n="Model">Model</span><select id="default-model"></select></label>
221
- <label><span data-i18n="Thinking intensity">Thinking intensity</span><select id="default-intensity"></select></label>
222
- </div>
223
- <section id="settings-pro" class="hidden">
224
- <h3 data-i18n="Pro orchestration">Pro orchestration</h3>
225
- <div class="settings-grid">
226
- <label><span data-i18n="Default Pro preset">Default Pro preset</span><select id="settings-pro-preset"></select></label>
227
- <label><span data-i18n="Maximum delegation depth">Maximum delegation depth</span><input id="settings-pro-depth" type="number" min="1" max="100" step="1" value="10" /></label>
228
- </div>
229
- <p class="settings-note" data-i18n="Every Pro task is planned first. All roles share the regular provider configuration. Image generation is reserved.">Every Pro task is planned first. All roles share the regular provider configuration. Image generation is reserved.</p>
230
- <p class="settings-note" data-i18n="Edit role models, intensity and context windows in ~/.neutrino/pro/model.json. Default delegation depth: 10.">Edit role models, intensity and context windows in ~/.neutrino/pro/model.json. Default delegation depth: 10.</p>
231
- </section>
232
- <h3 data-i18n="Conversation and approvals">Conversation and approvals</h3>
233
- <label class="standard-only"><span data-i18n="Model context window (tokens)">Model context window (tokens)</span><input id="settings-context" type="number" min="1" max="9007199254740991" step="1" required /></label>
234
- <p id="settings-compress-note" class="settings-note standard-only" data-i18n="Auto-compress at 80% of this model's context window. Default: 1,000,000 tokens.">Auto-compress at 80% of this model's context window. Default: 1,000,000 tokens.</p>
235
- <label class="standard-only"><span data-i18n="Approval reviewer model">Approval reviewer model</span><select id="settings-reviewer"></select></label>
236
- <label class="checkbox-label"><input id="settings-extreme" type="checkbox" /> <span data-i18n="Extreme-risk auto-approval (del class, 3 separate review rounds)">Extreme-risk auto-approval (del class, 3 separate review rounds)</span></label>
237
- <label class="checkbox-label"><input id="settings-sound" type="checkbox" /> <span data-i18n="Sound alerts (turn finished, approval waiting)">Sound alerts (turn finished, approval waiting)</span></label>
238
- <label class="checkbox-label"><input id="settings-web-console" type="checkbox" /> <span data-i18n="Start the Web console with the terminal">Start the Web console with the terminal</span></label>
239
- <p class="settings-note" data-i18n="Safety determines automatic approval; task relevance only blocks unanimously confirmed, extreme mismatches. Delete-class automatic approval also requires this setting.">Safety determines automatic approval; task relevance only blocks unanimously confirmed, extreme mismatches. Delete-class automatic approval also requires this setting.</p>
240
- <h3 data-i18n="Background residency">Background residency</h3>
241
- <label class="checkbox-label"><input id="settings-background" type="checkbox" /> <span data-i18n="Run the Web console in the background and keep browser tasks alive after the CLI exits">Run the Web console in the background and keep browser tasks alive after the CLI exits</span></label>
242
- <p class="settings-note" data-i18n="Off by default. Changes take effect immediately, including for running browser tasks. The regular and Pro workspaces share this setting. Terminal conversations still end when the terminal closes.">Off by default. Changes take effect immediately, including for running browser tasks. The regular and Pro workspaces share this setting. Terminal conversations still end when the terminal closes.</p>
243
- <h3 data-i18n="Web access">Web access</h3>
244
- <label class="checkbox-label"><input id="settings-web-lan" type="checkbox" /> <span data-i18n="Allow access from other devices (LAN, 0.0.0.0)">Allow access from other devices (LAN, 0.0.0.0)</span></label>
245
- <p class="settings-note" data-i18n="Binds the Web console to 0.0.0.0 so other devices on your network can open it, like --lan. Takes effect immediately; turning it off returns the console to 127.0.0.1. Keep the Web password on: anyone who can reach this port can drive the agent.">Binds the Web console to 0.0.0.0 so other devices on your network can open it, like --lan. Takes effect immediately; turning it off returns the console to 127.0.0.1. Keep the Web password on: anyone who can reach this port can drive the agent.</p>
246
- <div class="settings-grid">
247
- <label><span data-i18n="New Web password">New Web password</span><input id="settings-password" type="password" autocomplete="new-password" maxlength="256" placeholder="Leave blank to keep current password" data-i18n-placeholder="Leave blank to keep current password" /></label>
248
- <label><span data-i18n="Confirm password">Confirm password</span><input id="settings-password-confirm" type="password" autocomplete="new-password" maxlength="256" placeholder="Repeat new password" data-i18n-placeholder="Repeat new password" /></label>
249
- </div>
250
- <p class="settings-note" data-i18n="The password is permanent and survives restarts. Default: 114514. Saving a new password signs out other browsers.">The password is permanent and survives restarts. Default: 114514. Saving a new password signs out other browsers.</p>
251
- <p id="settings-feedback" class="form-feedback" role="status" aria-live="polite"></p>
252
- </div>
253
- <footer class="settings-actions">
254
- <button id="settings-cancel" class="control" type="button" data-i18n="Cancel">Cancel</button>
255
- <button id="settings-save" class="primary" type="submit" data-i18n="Save changes">Save changes</button>
256
- </footer>
257
- </form>
258
- </dialog>
259
-
260
- <dialog id="background-dialog" class="sheet-dialog background-dialog" aria-labelledby="background-title">
261
- <div class="sheet background-sheet">
262
- <header class="sheet-header background-header">
263
- <span class="background-mark" aria-hidden="true">
264
- <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
265
- <ellipse cx="12" cy="12" rx="9.4" ry="3.8" transform="rotate(-30 12 12)" stroke="currentColor" stroke-width="1.7" />
266
- <circle cx="12" cy="12" r="3.1" stroke="currentColor" stroke-width="1.7" />
267
- </svg>
268
- </span>
269
- <div class="background-copy">
270
- <h2 id="background-title" data-i18n="Enable background residency to avoid accidentally interrupting tasks">Enable background residency to avoid accidentally interrupting tasks</h2>
271
- </div>
272
- </header>
273
- <p id="background-feedback" class="form-feedback background-feedback" role="status" aria-live="polite"></p>
274
- <footer class="sheet-actions background-actions">
275
- <button id="background-cancel" class="control" type="button" data-i18n="Cancel">Cancel</button>
276
- <button id="background-enable" class="primary" type="button" data-i18n="Enable" autofocus>Enable</button>
277
- </footer>
278
- </div>
279
- </dialog>
280
-
281
- <dialog id="new-chat-dialog" class="sheet-dialog" aria-labelledby="new-chat-title">
282
- <form id="new-chat-form" class="sheet">
283
- <header class="sheet-header">
284
- <div>
285
- <h2 id="new-chat-title" data-i18n="New conversation">New conversation</h2>
286
- <p class="sheet-sub standard-only" data-i18n="Choose a working directory and a model.">Choose a working directory and a model.</p>
287
- <p class="sheet-sub pro-only" data-i18n="Choose a working directory and a professional team preset.">Choose a working directory and a professional team preset.</p>
288
- </div>
289
- <button id="new-chat-close" class="icon-btn" type="button" aria-label="Close" data-i18n-aria-label="Close">
290
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12" /></svg>
291
- </button>
292
- </header>
293
- <div class="sheet-body">
294
- <section class="field-group">
295
- <h3 data-i18n="Working directory">Working directory</h3>
296
- <div class="path-row">
297
- <input id="new-chat-cwd" class="path-input" type="text" spellcheck="false" autocomplete="off" placeholder="C:\path\to\project" aria-label="Working directory" data-i18n-aria-label="Working directory" />
298
- <button id="new-chat-browse" class="control" type="button" data-i18n="Browse…">Browse…</button>
299
- </div>
300
- <p class="settings-note" data-i18n="This working directory is used for the conversation's tools.">This working directory is used for the conversation's tools.</p>
301
- <h4 class="recent-title" data-i18n="Recent folders">Recent folders</h4>
302
- <div id="new-chat-recents" class="workspace-recents"></div>
303
- </section>
304
- <section class="field-group">
305
- <h3 class="standard-only" data-i18n="Model">Model</h3>
306
- <div class="settings-grid standard-only">
307
- <label><span data-i18n="Provider">Provider</span><select id="new-chat-provider"></select></label>
308
- <label><span data-i18n="Model">Model</span><select id="new-chat-model"></select></label>
309
- <label><span data-i18n="Thinking">Thinking</span><select id="new-chat-intensity"></select></label>
310
- </div>
311
- <label class="pro-only"><span data-i18n="Pro preset">Pro preset</span><select id="new-chat-pro-preset"></select></label>
312
- <label><span data-i18n="Default approval mode">Default approval mode</span>
313
- <select id="new-chat-approval">
314
- <option value="request" data-i18n="Request Approval">Request Approval</option>
315
- <option value="auto" data-i18n="Auto Approval">Auto Approval</option>
316
- </select>
317
- </label>
318
- <p id="new-chat-note" class="settings-note standard-only"></p>
319
- </section>
320
- <p id="new-chat-feedback" class="form-feedback" role="status" aria-live="polite"></p>
321
- </div>
322
- <footer class="sheet-actions">
323
- <button id="new-chat-cancel" class="control" type="button" data-i18n="Cancel">Cancel</button>
324
- <button id="new-chat-start" class="primary" type="submit" data-i18n="Start conversation">Start conversation</button>
325
- </footer>
326
- </form>
327
- </dialog>
328
-
329
- <dialog id="folder-dialog" class="sheet-dialog" aria-labelledby="folder-title">
330
- <div class="sheet folder-sheet">
331
- <header class="sheet-header">
332
- <div>
333
- <h2 id="folder-title" data-i18n="Open working directory">Open working directory</h2>
334
- <p class="sheet-sub" data-i18n="Choose a folder to open as the working directory.">Choose a folder to open as the working directory.</p>
335
- </div>
336
- <button id="folder-close" class="icon-btn" type="button" aria-label="Close" data-i18n-aria-label="Close">
337
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12" /></svg>
338
- </button>
339
- </header>
340
- <div class="folder-toolbar">
341
- <button id="folder-up" class="icon-btn" type="button" title="Up" aria-label="Up" data-i18n-title="Up" data-i18n-aria-label="Up">
342
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m18 15-6-6-6 6" /></svg>
343
- </button>
344
- <input id="folder-path" class="path-input" type="text" spellcheck="false" autocomplete="off" aria-label="Working directory" data-i18n-aria-label="Working directory" />
345
- <button id="folder-go" class="control" type="button" data-i18n="Open">Open</button>
346
- </div>
347
- <div id="folder-roots" class="folder-roots"></div>
348
- <div id="folder-list" class="folder-list" role="listbox" aria-label="Folders"></div>
349
- <div id="folder-new" class="folder-new hidden">
350
- <input id="folder-new-name" class="path-input" type="text" maxlength="255" placeholder="Folder name" aria-label="Folder name" data-i18n-placeholder="Folder name" data-i18n-aria-label="Folder name" />
351
- <button id="folder-new-create" class="primary" type="button" data-i18n="Create">Create</button>
352
- <button id="folder-new-cancel" class="control" type="button" data-i18n="Cancel">Cancel</button>
353
- </div>
354
- <p id="folder-feedback" class="form-feedback" role="status" aria-live="polite"></p>
355
- <footer class="sheet-actions folder-actions">
356
- <button id="folder-mkdir" class="control" type="button" data-i18n="New folder">New folder</button>
357
- <span class="sheet-spacer"></span>
358
- <button id="folder-cancel" class="control" type="button" data-i18n="Cancel">Cancel</button>
359
- <button id="folder-use" class="primary" type="button" data-i18n="Use this folder">Use this folder</button>
360
- </footer>
361
- </div>
362
- </dialog>
363
-
364
- <dialog id="agents-dialog" class="sheet-dialog" aria-labelledby="agents-title">
365
- <div class="sheet">
366
- <header class="sheet-header">
367
- <div>
368
- <h2 id="agents-title" data-i18n="Other agents">Other agents</h2>
369
- <p class="sheet-sub" data-i18n="Read-only sessions recorded by other coding agents in this working directory.">Read-only sessions recorded by other coding agents in this working directory.</p>
370
- </div>
371
- <button id="agents-close" class="icon-btn" type="button" aria-label="Close" data-i18n-aria-label="Close">
372
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12" /></svg>
373
- </button>
374
- </header>
375
- <div id="agents-list" class="agents-list"></div>
376
- <p id="agents-feedback" class="form-feedback" role="status" aria-live="polite"></p>
377
- <footer class="sheet-actions">
378
- <span id="agents-cwd" class="agents-cwd"></span>
379
- <span class="sheet-spacer"></span>
380
- </footer>
381
- </div>
382
- </dialog>
383
-
384
- <dialog id="workspace-dialog" class="sheet-dialog" aria-labelledby="workspace-title">
385
- <div class="sheet">
386
- <header class="sheet-header">
387
- <div>
388
- <h2 id="workspace-title" data-i18n="Working directories">Working directories</h2>
389
- <p class="sheet-sub" data-i18n="Choose a working directory to browse and start conversations in.">Choose a working directory to browse and start conversations in.</p>
390
- </div>
391
- <button id="workspace-close" class="icon-btn" type="button" aria-label="Close" data-i18n-aria-label="Close">
392
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12" /></svg>
393
- </button>
394
- </header>
395
- <div id="workspace-list" class="workspace-list"></div>
396
- <p id="workspace-feedback" class="form-feedback" role="status" aria-live="polite"></p>
397
- <footer class="sheet-actions">
398
- <button id="workspace-all" class="control" type="button" data-i18n="All directories">All directories</button>
399
- <span class="sheet-spacer"></span>
400
- <button id="workspace-add" class="primary" type="button" data-i18n="Open folder…">Open folder…</button>
401
- </footer>
402
- </div>
403
- </dialog>
404
-
405
- <dialog id="pro-fallback-dialog" class="sheet-dialog pro-fallback-dialog" aria-labelledby="pro-fallback-title">
406
- <div class="sheet">
407
- <header class="sheet-header"><h2 id="pro-fallback-title" data-i18n="Professional model availability">Professional model availability</h2></header>
408
- <div class="sheet-body">
409
- <p class="settings-note" data-i18n="These model substitutions apply only to this task in this conversation. Your preset configuration is unchanged.">These model substitutions apply only to this task in this conversation. Your preset configuration is unchanged.</p>
410
- <div id="pro-fallback-rows" class="pro-fallback-rows"></div>
411
- <p id="pro-fallback-error" class="form-feedback error hidden" role="alert"></p>
412
- </div>
413
- <footer class="sheet-actions"><button id="pro-fallback-close" class="primary" type="button" data-i18n="Got it">Got it</button></footer>
414
- </div>
415
- </dialog>
416
-
417
- <dialog id="update-dialog" class="sheet-dialog" aria-labelledby="update-title">
418
- <div class="sheet">
419
- <header class="sheet-header">
420
- <div>
421
- <h2 id="update-title" data-i18n="A new version is available">A new version is available</h2>
422
- <p id="update-versions" class="sheet-sub"></p>
423
- </div>
424
- <button id="update-close" class="icon-btn" type="button" aria-label="Close" data-i18n-aria-label="Close">
425
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12" /></svg>
426
- </button>
427
- </header>
428
- <div class="sheet-body">
429
- <p id="update-note" class="settings-note" data-i18n="Neutrino updates itself with npm. Restart it afterwards to use the new version.">Neutrino updates itself with npm. Restart it afterwards to use the new version.</p>
430
- <p id="update-command-block" class="settings-note hidden"><span data-i18n="Update by hand with:">Update by hand with:</span> <code id="update-command">npm install -g @xingjisoft/neutrino</code></p>
431
- <p id="update-feedback" class="form-feedback" role="status" aria-live="polite"></p>
432
- </div>
433
- <footer class="sheet-actions">
434
- <button id="update-later" class="control" type="button" data-i18n="Later">Later</button>
435
- <button id="update-now" class="primary" type="button" data-i18n="Update now" autofocus>Update now</button>
436
- </footer>
437
- </div>
438
- </dialog>
439
-
440
- <script src="app.js" type="module"></script>
441
- </body>
442
- </html>
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, interactive-widget=resizes-content" />
6
+ <meta name="color-scheme" content="dark" />
7
+ <meta name="theme-color" content="#151517" />
8
+ <script>
9
+ // Switching to the Pro workspace navigates only once the #151515 curtain
10
+ // is opaque. Cover the page here, before the first paint, so a slow
11
+ // module load cannot flash the freshly loaded /pro page before app.js
12
+ // takes the curtain over. app.js removes the class; the timer is a
13
+ // safety net for when the module cannot run at all.
14
+ try {
15
+ var proPath = location.pathname === "/pro" || location.pathname.startsWith("/pro/");
16
+ var proStart = Number(sessionStorage.getItem("neutrino.pro.transition")) || 0;
17
+ if (proPath && proStart && Date.now() - proStart < 8000) {
18
+ document.documentElement.classList.add("pro-transitioning");
19
+ setTimeout(function () {
20
+ document.documentElement.classList.remove("pro-transitioning");
21
+ }, 8000);
22
+ }
23
+ } catch (error) { /* Storage may be blocked; the page still works. */ }
24
+ </script>
25
+ <title>Neutrino</title>
26
+ <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f9fafb' stroke-width='1.7'%3E%3Cellipse cx='12' cy='12' rx='9.4' ry='3.8' transform='rotate(-30 12 12)'/%3E%3Ccircle cx='12' cy='12' r='3.1'/%3E%3C/svg%3E" />
27
+ <link rel="stylesheet" href="style.css" />
28
+ </head>
29
+ <body>
30
+ <div id="app">
31
+ <aside id="sidebar">
32
+ <header class="brand">
33
+ <button id="brand-logo" class="logo brand-logo" type="button" title="Switch to Pro mode" aria-label="Switch to Pro mode" data-i18n-title="Switch to Pro mode" data-i18n-aria-label="Switch to Pro mode">
34
+ <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
35
+ <ellipse cx="12" cy="12" rx="9.4" ry="3.8" transform="rotate(-30 12 12)" stroke="currentColor" stroke-width="1.7" />
36
+ <circle cx="12" cy="12" r="3.1" stroke="currentColor" stroke-width="1.7" />
37
+ </svg>
38
+ </button>
39
+ <div class="brand-text">
40
+ <strong id="brand-name">Neutrino</strong>
41
+ <span id="status" class="status">connecting…</span>
42
+ </div>
43
+ <div class="brand-actions">
44
+ <button id="refresh" class="icon-btn" type="button" title="Refresh conversations" aria-label="Refresh conversations" data-i18n-title="Refresh conversations" data-i18n-aria-label="Refresh conversations">
45
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12a9 9 0 1 1-2.64-6.36" /><path d="M21 3v6h-6" /></svg>
46
+ </button>
47
+ <button id="settings-open" class="icon-btn" type="button" title="Settings" aria-label="Settings" data-i18n-title="Settings" data-i18n-aria-label="Settings">
48
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z" /><circle cx="12" cy="12" r="3" /></svg>
49
+ </button>
50
+ </div>
51
+ </header>
52
+ <div id="pro-tip" class="pro-tip hidden" role="note">
53
+ <span data-i18n="Click the badge to switch to Pro mode">Click the badge to switch to Pro mode</span>
54
+ <button id="pro-tip-close" class="pro-tip-close" type="button" title="Dismiss" aria-label="Dismiss" data-i18n-title="Dismiss" data-i18n-aria-label="Dismiss">
55
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12" /></svg>
56
+ </button>
57
+ </div>
58
+
59
+ <div class="sidebar-tools">
60
+ <button id="new-chat" class="new-chat" type="button" title="New conversation" data-i18n-title="New conversation">
61
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14" /></svg>
62
+ <span data-i18n="New conversation">New conversation</span>
63
+ </button>
64
+ <button id="workspace-button" class="workspace-button" type="button" title="Working directory" data-i18n-title="Working directory">
65
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 7.5A2.5 2.5 0 0 1 5.5 5H9l2 2.5h7.5A2.5 2.5 0 0 1 21 10v7a2.5 2.5 0 0 1-2.5 2.5h-13A2.5 2.5 0 0 1 3 17z" /></svg>
66
+ <span id="workspace-label" class="workspace-label" data-i18n="All directories">All directories</span>
67
+ <svg class="workspace-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 18 6-6-6-6" /></svg>
68
+ </button>
69
+ <button id="agents-open" class="workspace-button" type="button" title="Other agents" data-i18n-title="Other agents">
70
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12a9 9 0 1 0 3-6.7" /><path d="M3 4v5h5" /><path d="M12 7v5l3 2" /></svg>
71
+ <span class="workspace-label" data-i18n="Other agents">Other agents</span>
72
+ <svg class="workspace-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 18 6-6-6-6" /></svg>
73
+ </button>
74
+ </div>
75
+
76
+ <div id="sessions" class="sessions"></div>
77
+ <footer class="sidebar-foot">
78
+ <span class="foot-note" data-i18n="Local agent console">Local agent console</span>
79
+ <label class="language-picker" title="Interface language" data-i18n-title="Interface language">
80
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9" /><path d="M3 12h18M12 3c2.5 2.6 3.8 5.6 3.8 9S14.5 18.4 12 21c-2.5-2.6-3.8-5.6-3.8-9S9.5 5.6 12 3z" /></svg>
81
+ <select id="language-select" aria-label="Interface language" data-i18n-aria-label="Interface language">
82
+ <option value="en">English</option>
83
+ <option value="zh">简体中文</option>
84
+ </select>
85
+ </label>
86
+ </footer>
87
+ </aside>
88
+
89
+ <main id="main">
90
+ <header id="main-header" class="main-header">
91
+ <button id="back-to-menu" class="icon-btn back-to-menu" type="button" title="Back to conversations" aria-label="Back to conversations" data-i18n-title="Back to conversations" data-i18n-aria-label="Back to conversations" aria-controls="sidebar">
92
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m12 5-7 7 7 7M5 12h14" /></svg>
93
+ </button>
94
+ <div class="main-title">
95
+ <h1 id="session-title" data-i18n="Select a conversation">Select a conversation</h1>
96
+ <div id="session-sub" class="sub"></div>
97
+ </div>
98
+ <div id="controls" class="controls"></div>
99
+ <button id="pro-exit" class="control pro-exit hidden" type="button" title="Exit Pro mode" aria-label="Exit Pro mode" data-i18n-title="Exit Pro mode" data-i18n-aria-label="Exit Pro mode">
100
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m12 5-7 7 7 7M5 12h14" /></svg>
101
+ <span data-i18n="Exit Pro mode">Exit Pro mode</span>
102
+ </button>
103
+ </header>
104
+
105
+ <aside id="plan-card" class="plan-card hidden" aria-live="polite"></aside>
106
+
107
+ <section id="messages" class="messages">
108
+ <div class="empty">
109
+ <span class="empty-mark" aria-hidden="true">
110
+ <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
111
+ <ellipse cx="12" cy="12" rx="9.4" ry="3.8" transform="rotate(-30 12 12)" stroke="currentColor" stroke-width="1.7" />
112
+ <circle cx="12" cy="12" r="3.1" stroke="currentColor" stroke-width="1.7" />
113
+ </svg>
114
+ </span>
115
+ <strong data-i18n="No conversation open">No conversation open</strong>
116
+ <span data-i18n="Choose a conversation from the sidebar to view it.">Choose a conversation from the sidebar to view it.</span>
117
+ <button id="empty-new-chat" class="control primary" type="button" data-i18n="New conversation">New conversation</button>
118
+ </div>
119
+ </section>
120
+
121
+ <div id="approval" class="approval hidden" role="alert" aria-live="assertive"></div>
122
+
123
+ <footer id="agent-actions" class="agent-actions hidden">
124
+ <p id="agent-migrate-feedback" class="form-feedback error" role="status" aria-live="polite"></p>
125
+ <button id="agent-migrate" class="control primary" type="button" data-i18n="Migrate session" title="Copy this history into a new Neutrino conversation in the same folder" data-i18n-title="Copy this history into a new Neutrino conversation in the same folder">Migrate session</button>
126
+ </footer>
127
+
128
+ <footer id="composer" class="composer hidden">
129
+ <div class="composer-inner">
130
+ <div class="composer-card">
131
+ <textarea id="input" rows="1" placeholder="Message Neutrino…" aria-label="Message" data-i18n-placeholder="Message Neutrino…"></textarea>
132
+ <details id="agent-mode-picker" class="agent-mode-picker">
133
+ <summary aria-label="Agent mode" data-i18n-aria-label="Agent mode"><strong id="agent-mode-label" data-i18n="Standard mode">Standard mode</strong><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true"><path d="m7 10 5 5 5-5" /></svg></summary>
134
+ <div class="agent-mode-menu" role="menu" aria-label="Agent mode" data-i18n-aria-label="Agent mode">
135
+ <button type="button" role="menuitemradio" aria-checked="true" data-agent-mode="standard"><span><strong data-i18n="Standard mode">Standard mode</strong><small data-i18n="Full-featured Agent for every scenario">Full-featured Agent for every scenario</small></span><svg class="agent-mode-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m5 12 4 4L19 6" /></svg></button>
136
+ <button type="button" role="menuitemradio" aria-checked="false" data-agent-mode="ptc"><span><strong data-i18n="PTC mode">PTC mode</strong><small data-i18n="All standard capabilities, with code-based planning to save tokens">All standard capabilities, with code-based planning to save tokens</small></span><svg class="agent-mode-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m5 12 4 4L19 6" /></svg></button>
137
+ <button type="button" role="menuitemradio" aria-checked="false" data-agent-mode="fast"><span><strong data-i18n="Fast mode">Fast mode</strong><small data-i18n="Less thinking and fewer calls for quick answers">Less thinking and fewer calls for quick answers</small></span><svg class="agent-mode-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m5 12 4 4L19 6" /></svg></button>
138
+ <button type="button" role="menuitemradio" aria-checked="false" data-agent-mode="pro"><span><strong data-i18n="Professional mode">Professional mode</strong><small data-i18n="Assign tasks to the best-suited models so multiple models complement each other">Assign tasks to the best-suited models so multiple models complement each other</small></span><svg class="agent-mode-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m5 12 4 4L19 6" /></svg></button>
139
+ </div>
140
+ <p id="agent-mode-feedback" class="agent-mode-feedback" role="status" aria-live="polite"></p>
141
+ </details>
142
+ <details id="model-picker" class="model-picker pro-preset-control hidden">
143
+ <summary id="model-picker-summary" aria-label="Conversation model" data-i18n-aria-label="Conversation model"><span id="model-picker-label"></span><svg class="pro-preset-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m7 10 5 5 5-5" /></svg></summary>
144
+ <div class="pro-preset-card model-picker-card">
145
+ <div class="pro-preset-heading"><span data-i18n="Conversation model">Conversation model</span><strong id="model-intensity-label"></strong></div>
146
+ <div class="model-picker-fields">
147
+ <label><span data-i18n="Provider">Provider</span><select id="model-provider"></select></label>
148
+ <label><span data-i18n="Model">Model</span><select id="model-name"></select></label>
149
+ </div>
150
+ <label class="pro-slider-label" for="model-intensity" data-i18n="Thinking intensity">Thinking intensity</label>
151
+ <div id="model-intensity-slider" class="pro-preset-slider">
152
+ <div class="pro-slider-track" aria-hidden="true"><div class="pro-slider-fill"></div></div>
153
+ <div id="model-intensity-stops" class="pro-slider-stops" aria-hidden="true"></div>
154
+ <input id="model-intensity" type="range" min="0" max="0" step="1" value="0" aria-label="Thinking intensity" data-i18n-aria-label="Thinking intensity" />
155
+ </div>
156
+ <div id="model-intensity-ticks" class="pro-preset-ticks"></div>
157
+ <p id="model-feedback" class="form-feedback" role="status" aria-live="polite"></p>
158
+ </div>
159
+ </details>
160
+ <details id="pro-preset-control" class="pro-preset-control hidden">
161
+ <summary aria-label="Pro preset" data-i18n-aria-label="Pro preset"><span id="pro-preset-label">Pro</span><svg class="pro-preset-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m7 10 5 5 5-5" /></svg></summary>
162
+ <div class="pro-preset-card">
163
+ <div class="pro-preset-heading"><span data-i18n="Neutrino Pro">Neutrino Pro</span><strong id="pro-preset-name"></strong></div>
164
+ <label class="pro-slider-label" for="pro-preset-range" data-i18n="Preset">Preset</label>
165
+ <div id="pro-preset-slider" class="pro-preset-slider">
166
+ <div class="pro-slider-track" aria-hidden="true">
167
+ <div class="pro-slider-fill"></div>
168
+ <div class="pro-slider-meteors">
169
+ <span class="pro-slider-meteor"></span><span class="pro-slider-meteor"></span><span class="pro-slider-meteor"></span><span class="pro-slider-meteor"></span>
170
+ </div>
171
+ </div>
172
+ <div id="pro-slider-stops" class="pro-slider-stops" aria-hidden="true"></div>
173
+ <input id="pro-preset-range" type="range" min="0" max="0" step="1" value="0" aria-label="Pro preset" data-i18n-aria-label="Pro preset" />
174
+ </div>
175
+ <div id="pro-preset-ticks" class="pro-preset-ticks"></div>
176
+ <details class="pro-model-details" id="pro-model-details">
177
+ <summary><span data-i18n="Model details">Model details</span><svg class="pro-model-details-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m7 10 5 5 5-5" /></svg></summary>
178
+ <div id="pro-preset-models" class="pro-preset-models"></div>
179
+ </details>
180
+ <p id="pro-preset-note" class="settings-note"></p>
181
+ <p id="pro-preset-feedback" class="form-feedback error" role="status" aria-live="polite"></p>
182
+ </div>
183
+ </details>
184
+ <button id="send" class="primary" type="button" title="Send message" aria-label="Send message" data-i18n-title="Send message" data-i18n-aria-label="Send message">
185
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path class="send-icon" d="M12 19V5M5 12l7-7 7 7" /><rect class="pause-icon" x="5" y="5" width="14" height="14" rx="2" fill="currentColor" stroke="none" /></svg>
186
+ </button>
187
+ </div>
188
+ <div class="composer-hint">
189
+ <span><kbd>Enter</kbd> <span data-i18n="to send">to send</span></span>
190
+ <span class="hint-sep">·</span>
191
+ <span><kbd>Shift</kbd> + <kbd>Enter</kbd> <span data-i18n="for a new line">for a new line</span></span>
192
+ </div>
193
+ </div>
194
+ </footer>
195
+ </main>
196
+ </div>
197
+
198
+ <dialog id="settings-dialog" class="settings-dialog" aria-labelledby="settings-title">
199
+ <form id="settings-form">
200
+ <header class="settings-header">
201
+ <div>
202
+ <h2 id="settings-title" data-i18n="Settings">Settings</h2>
203
+ <p class="settings-sub" data-i18n="Models, approvals, and console access.">Models, approvals, and console access.</p>
204
+ </div>
205
+ <button id="settings-close" class="icon-btn" type="button" aria-label="Close settings" data-i18n-aria-label="Close settings">
206
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12" /></svg>
207
+ </button>
208
+ </header>
209
+ <div class="settings-fields">
210
+ <h3 data-i18n="Interface">Interface</h3>
211
+ <div class="settings-grid">
212
+ <label><span data-i18n="Language">Language</span>
213
+ <select id="settings-language">
214
+ <option value="en">English</option>
215
+ <option value="zh">简体中文</option>
216
+ </select>
217
+ </label>
218
+ <label><span data-i18n="Default approval mode">Default approval mode</span>
219
+ <select id="settings-approval">
220
+ <option value="request" data-i18n="Request Approval">Request Approval</option>
221
+ <option value="auto" data-i18n="Auto Approval">Auto Approval</option>
222
+ </select>
223
+ </label>
224
+ </div>
225
+ <label class="checkbox-label standard-only"><input id="settings-plan" type="checkbox" /> <span data-i18n="Plan-first turns">Plan-first turns</span></label>
226
+ <p class="settings-note standard-only" data-i18n="Split multi-step requests into a plan before answering.">Split multi-step requests into a plan before answering.</p>
227
+ <h3 class="standard-only" data-i18n="Defaults for new conversations">Defaults for new conversations</h3>
228
+ <div class="settings-grid standard-only">
229
+ <label><span data-i18n="Provider">Provider</span><select id="default-provider"></select></label>
230
+ <label><span data-i18n="Model">Model</span><select id="default-model"></select></label>
231
+ <label><span data-i18n="Thinking intensity">Thinking intensity</span><select id="default-intensity"></select></label>
232
+ </div>
233
+ <section id="settings-pro" class="hidden">
234
+ <h3 data-i18n="Pro orchestration">Pro orchestration</h3>
235
+ <div class="settings-grid">
236
+ <label><span data-i18n="Default Pro preset">Default Pro preset</span><select id="settings-pro-preset"></select></label>
237
+ <label><span data-i18n="Maximum delegation depth">Maximum delegation depth</span><input id="settings-pro-depth" type="number" min="1" max="100" step="1" value="10" /></label>
238
+ </div>
239
+ <p class="settings-note" data-i18n="Every Pro task is planned first. All roles share the regular provider configuration. Image generation is reserved.">Every Pro task is planned first. All roles share the regular provider configuration. Image generation is reserved.</p>
240
+ <p class="settings-note" data-i18n="Edit role models, intensity and context windows in ~/.neutrino/pro/model.json. Default delegation depth: 10.">Edit role models, intensity and context windows in ~/.neutrino/pro/model.json. Default delegation depth: 10.</p>
241
+ </section>
242
+ <h3 data-i18n="Conversation and approvals">Conversation and approvals</h3>
243
+ <label class="standard-only"><span data-i18n="Model context window (tokens)">Model context window (tokens)</span><input id="settings-context" type="number" min="1" max="9007199254740991" step="1" required /></label>
244
+ <p id="settings-compress-note" class="settings-note standard-only" data-i18n="Auto-compress at 80% of this model's context window. Default: 1,000,000 tokens.">Auto-compress at 80% of this model's context window. Default: 1,000,000 tokens.</p>
245
+ <label class="standard-only"><span data-i18n="Approval reviewer model">Approval reviewer model</span><select id="settings-reviewer"></select></label>
246
+ <label class="checkbox-label"><input id="settings-extreme" type="checkbox" /> <span data-i18n="Extreme-risk auto-approval (del class, 3 separate review rounds)">Extreme-risk auto-approval (del class, 3 separate review rounds)</span></label>
247
+ <label class="checkbox-label"><input id="settings-sound" type="checkbox" /> <span data-i18n="Sound alerts (turn finished, approval waiting)">Sound alerts (turn finished, approval waiting)</span></label>
248
+ <label class="checkbox-label"><input id="settings-web-console" type="checkbox" /> <span data-i18n="Start the Web console with the terminal">Start the Web console with the terminal</span></label>
249
+ <p class="settings-note" data-i18n="Safety determines automatic approval; task relevance only blocks unanimously confirmed, extreme mismatches. Delete-class automatic approval also requires this setting.">Safety determines automatic approval; task relevance only blocks unanimously confirmed, extreme mismatches. Delete-class automatic approval also requires this setting.</p>
250
+ <h3 data-i18n="Background residency">Background residency</h3>
251
+ <label class="checkbox-label"><input id="settings-background" type="checkbox" /> <span data-i18n="Run the Web console in the background and keep browser tasks alive after the CLI exits">Run the Web console in the background and keep browser tasks alive after the CLI exits</span></label>
252
+ <p class="settings-note" data-i18n="Off by default. Changes take effect immediately, including for running browser tasks. The regular and Pro workspaces share this setting. Terminal conversations still end when the terminal closes.">Off by default. Changes take effect immediately, including for running browser tasks. The regular and Pro workspaces share this setting. Terminal conversations still end when the terminal closes.</p>
253
+ <h3 data-i18n="Web access">Web access</h3>
254
+ <label class="checkbox-label"><input id="settings-web-lan" type="checkbox" /> <span data-i18n="Allow access from other devices (LAN, 0.0.0.0)">Allow access from other devices (LAN, 0.0.0.0)</span></label>
255
+ <p class="settings-note" data-i18n="Binds the Web console to 0.0.0.0 so other devices on your network can open it, like --lan. Takes effect immediately; turning it off returns the console to 127.0.0.1. Keep the Web password on: anyone who can reach this port can drive the agent.">Binds the Web console to 0.0.0.0 so other devices on your network can open it, like --lan. Takes effect immediately; turning it off returns the console to 127.0.0.1. Keep the Web password on: anyone who can reach this port can drive the agent.</p>
256
+ <div class="settings-grid">
257
+ <label><span data-i18n="New Web password">New Web password</span><input id="settings-password" type="password" autocomplete="new-password" maxlength="256" placeholder="Leave blank to keep current password" data-i18n-placeholder="Leave blank to keep current password" /></label>
258
+ <label><span data-i18n="Confirm password">Confirm password</span><input id="settings-password-confirm" type="password" autocomplete="new-password" maxlength="256" placeholder="Repeat new password" data-i18n-placeholder="Repeat new password" /></label>
259
+ </div>
260
+ <p class="settings-note" data-i18n="The password is permanent and survives restarts. Default: 114514. Saving a new password signs out other browsers.">The password is permanent and survives restarts. Default: 114514. Saving a new password signs out other browsers.</p>
261
+ <h3 data-i18n="Updates">Updates</h3>
262
+ <div class="settings-update-row">
263
+ <button id="settings-check-update" class="control" type="button" data-i18n="Check for updates">Check for updates</button>
264
+ <p id="settings-update-feedback" class="form-feedback" role="status" aria-live="polite"></p>
265
+ </div>
266
+ <p class="settings-note" data-i18n="Neutrino checks npm for new releases every 30 minutes. Both workspaces share that check.">Neutrino checks npm for new releases every 30 minutes. Both workspaces share that check.</p>
267
+ <p id="settings-feedback" class="form-feedback" role="status" aria-live="polite"></p>
268
+ </div>
269
+ <footer class="settings-actions">
270
+ <button id="settings-cancel" class="control" type="button" data-i18n="Cancel">Cancel</button>
271
+ <button id="settings-save" class="primary" type="submit" data-i18n="Save changes">Save changes</button>
272
+ </footer>
273
+ </form>
274
+ </dialog>
275
+
276
+ <dialog id="background-dialog" class="sheet-dialog background-dialog" aria-labelledby="background-title">
277
+ <div class="sheet background-sheet">
278
+ <header class="sheet-header background-header">
279
+ <span class="background-mark" aria-hidden="true">
280
+ <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
281
+ <ellipse cx="12" cy="12" rx="9.4" ry="3.8" transform="rotate(-30 12 12)" stroke="currentColor" stroke-width="1.7" />
282
+ <circle cx="12" cy="12" r="3.1" stroke="currentColor" stroke-width="1.7" />
283
+ </svg>
284
+ </span>
285
+ <div class="background-copy">
286
+ <h2 id="background-title" data-i18n="Enable background residency to avoid accidentally interrupting tasks">Enable background residency to avoid accidentally interrupting tasks</h2>
287
+ </div>
288
+ </header>
289
+ <p id="background-feedback" class="form-feedback background-feedback" role="status" aria-live="polite"></p>
290
+ <footer class="sheet-actions background-actions">
291
+ <button id="background-cancel" class="control" type="button" data-i18n="Cancel">Cancel</button>
292
+ <button id="background-enable" class="primary" type="button" data-i18n="Enable" autofocus>Enable</button>
293
+ </footer>
294
+ </div>
295
+ </dialog>
296
+
297
+ <dialog id="new-chat-dialog" class="sheet-dialog" aria-labelledby="new-chat-title">
298
+ <form id="new-chat-form" class="sheet">
299
+ <header class="sheet-header">
300
+ <div>
301
+ <h2 id="new-chat-title" data-i18n="New conversation">New conversation</h2>
302
+ <p class="sheet-sub standard-only" data-i18n="Choose a working directory and a model.">Choose a working directory and a model.</p>
303
+ <p class="sheet-sub pro-only" data-i18n="Choose a working directory and a professional team preset.">Choose a working directory and a professional team preset.</p>
304
+ </div>
305
+ <button id="new-chat-close" class="icon-btn" type="button" aria-label="Close" data-i18n-aria-label="Close">
306
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12" /></svg>
307
+ </button>
308
+ </header>
309
+ <div class="sheet-body">
310
+ <section class="field-group">
311
+ <h3 data-i18n="Working directory">Working directory</h3>
312
+ <div class="path-row">
313
+ <input id="new-chat-cwd" class="path-input" type="text" spellcheck="false" autocomplete="off" placeholder="C:\path\to\project" aria-label="Working directory" data-i18n-aria-label="Working directory" />
314
+ <button id="new-chat-browse" class="control" type="button" data-i18n="Browse…">Browse…</button>
315
+ </div>
316
+ <p class="settings-note" data-i18n="This working directory is used for the conversation's tools.">This working directory is used for the conversation's tools.</p>
317
+ <h4 class="recent-title" data-i18n="Recent folders">Recent folders</h4>
318
+ <div id="new-chat-recents" class="workspace-recents"></div>
319
+ </section>
320
+ <section class="field-group">
321
+ <h3 class="standard-only" data-i18n="Model">Model</h3>
322
+ <div class="settings-grid standard-only">
323
+ <label><span data-i18n="Provider">Provider</span><select id="new-chat-provider"></select></label>
324
+ <label><span data-i18n="Model">Model</span><select id="new-chat-model"></select></label>
325
+ <label><span data-i18n="Thinking">Thinking</span><select id="new-chat-intensity"></select></label>
326
+ </div>
327
+ <label class="pro-only"><span data-i18n="Pro preset">Pro preset</span><select id="new-chat-pro-preset"></select></label>
328
+ <label><span data-i18n="Default approval mode">Default approval mode</span>
329
+ <select id="new-chat-approval">
330
+ <option value="request" data-i18n="Request Approval">Request Approval</option>
331
+ <option value="auto" data-i18n="Auto Approval">Auto Approval</option>
332
+ </select>
333
+ </label>
334
+ <p id="new-chat-note" class="settings-note standard-only"></p>
335
+ </section>
336
+ <p id="new-chat-feedback" class="form-feedback" role="status" aria-live="polite"></p>
337
+ </div>
338
+ <footer class="sheet-actions">
339
+ <button id="new-chat-cancel" class="control" type="button" data-i18n="Cancel">Cancel</button>
340
+ <button id="new-chat-start" class="primary" type="submit" data-i18n="Start conversation">Start conversation</button>
341
+ </footer>
342
+ </form>
343
+ </dialog>
344
+
345
+ <dialog id="folder-dialog" class="sheet-dialog" aria-labelledby="folder-title">
346
+ <div class="sheet folder-sheet">
347
+ <header class="sheet-header">
348
+ <div>
349
+ <h2 id="folder-title" data-i18n="Open working directory">Open working directory</h2>
350
+ <p class="sheet-sub" data-i18n="Choose a folder to open as the working directory.">Choose a folder to open as the working directory.</p>
351
+ </div>
352
+ <button id="folder-close" class="icon-btn" type="button" aria-label="Close" data-i18n-aria-label="Close">
353
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12" /></svg>
354
+ </button>
355
+ </header>
356
+ <div class="folder-toolbar">
357
+ <button id="folder-up" class="icon-btn" type="button" title="Up" aria-label="Up" data-i18n-title="Up" data-i18n-aria-label="Up">
358
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m18 15-6-6-6 6" /></svg>
359
+ </button>
360
+ <input id="folder-path" class="path-input" type="text" spellcheck="false" autocomplete="off" aria-label="Working directory" data-i18n-aria-label="Working directory" />
361
+ <button id="folder-go" class="control" type="button" data-i18n="Open">Open</button>
362
+ </div>
363
+ <div id="folder-roots" class="folder-roots"></div>
364
+ <div id="folder-list" class="folder-list" role="listbox" aria-label="Folders"></div>
365
+ <div id="folder-new" class="folder-new hidden">
366
+ <input id="folder-new-name" class="path-input" type="text" maxlength="255" placeholder="Folder name" aria-label="Folder name" data-i18n-placeholder="Folder name" data-i18n-aria-label="Folder name" />
367
+ <button id="folder-new-create" class="primary" type="button" data-i18n="Create">Create</button>
368
+ <button id="folder-new-cancel" class="control" type="button" data-i18n="Cancel">Cancel</button>
369
+ </div>
370
+ <p id="folder-feedback" class="form-feedback" role="status" aria-live="polite"></p>
371
+ <footer class="sheet-actions folder-actions">
372
+ <button id="folder-mkdir" class="control" type="button" data-i18n="New folder">New folder</button>
373
+ <span class="sheet-spacer"></span>
374
+ <button id="folder-cancel" class="control" type="button" data-i18n="Cancel">Cancel</button>
375
+ <button id="folder-use" class="primary" type="button" data-i18n="Use this folder">Use this folder</button>
376
+ </footer>
377
+ </div>
378
+ </dialog>
379
+
380
+ <dialog id="agents-dialog" class="sheet-dialog" aria-labelledby="agents-title">
381
+ <div class="sheet">
382
+ <header class="sheet-header">
383
+ <div>
384
+ <h2 id="agents-title" data-i18n="Other agents">Other agents</h2>
385
+ <p class="sheet-sub" data-i18n="Read-only sessions recorded by other coding agents in this working directory.">Read-only sessions recorded by other coding agents in this working directory.</p>
386
+ </div>
387
+ <button id="agents-close" class="icon-btn" type="button" aria-label="Close" data-i18n-aria-label="Close">
388
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12" /></svg>
389
+ </button>
390
+ </header>
391
+ <div id="agents-list" class="agents-list"></div>
392
+ <p id="agents-feedback" class="form-feedback" role="status" aria-live="polite"></p>
393
+ <footer class="sheet-actions">
394
+ <span id="agents-cwd" class="agents-cwd"></span>
395
+ <span class="sheet-spacer"></span>
396
+ </footer>
397
+ </div>
398
+ </dialog>
399
+
400
+ <dialog id="workspace-dialog" class="sheet-dialog" aria-labelledby="workspace-title">
401
+ <div class="sheet">
402
+ <header class="sheet-header">
403
+ <div>
404
+ <h2 id="workspace-title" data-i18n="Working directories">Working directories</h2>
405
+ <p class="sheet-sub" data-i18n="Choose a working directory to browse and start conversations in.">Choose a working directory to browse and start conversations in.</p>
406
+ </div>
407
+ <button id="workspace-close" class="icon-btn" type="button" aria-label="Close" data-i18n-aria-label="Close">
408
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12" /></svg>
409
+ </button>
410
+ </header>
411
+ <div id="workspace-list" class="workspace-list"></div>
412
+ <p id="workspace-feedback" class="form-feedback" role="status" aria-live="polite"></p>
413
+ <footer class="sheet-actions">
414
+ <button id="workspace-all" class="control" type="button" data-i18n="All directories">All directories</button>
415
+ <span class="sheet-spacer"></span>
416
+ <button id="workspace-add" class="primary" type="button" data-i18n="Open folder…">Open folder…</button>
417
+ </footer>
418
+ </div>
419
+ </dialog>
420
+
421
+ <dialog id="pro-fallback-dialog" class="sheet-dialog pro-fallback-dialog" aria-labelledby="pro-fallback-title">
422
+ <div class="sheet">
423
+ <header class="sheet-header"><h2 id="pro-fallback-title" data-i18n="Professional model availability">Professional model availability</h2></header>
424
+ <div class="sheet-body">
425
+ <p class="settings-note" data-i18n="These model substitutions apply only to this task in this conversation. Your preset configuration is unchanged.">These model substitutions apply only to this task in this conversation. Your preset configuration is unchanged.</p>
426
+ <div id="pro-fallback-rows" class="pro-fallback-rows"></div>
427
+ <p id="pro-fallback-error" class="form-feedback error hidden" role="alert"></p>
428
+ </div>
429
+ <footer class="sheet-actions"><button id="pro-fallback-close" class="primary" type="button" data-i18n="Got it">Got it</button></footer>
430
+ </div>
431
+ </dialog>
432
+
433
+ <!-- A known release keeps this disc in the corner: the notice asks once, the
434
+ reminder stays until the release is installed. Both workspaces serve
435
+ this page, so Pro draws it too. -->
436
+ <button id="update-badge" class="update-badge hidden" type="button" title="A new version is available" aria-label="A new version is available" data-i18n-title="A new version is available" data-i18n-aria-label="A new version is available">
437
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 4v10" /><path d="m7.5 9.5 4.5 4.5 4.5-4.5" /><path d="M5 19h14" /></svg>
438
+ </button>
439
+
440
+ <dialog id="update-dialog" class="sheet-dialog" aria-labelledby="update-title">
441
+ <div class="sheet">
442
+ <header class="sheet-header">
443
+ <div>
444
+ <h2 id="update-title" data-i18n="A new version is available">A new version is available</h2>
445
+ <p id="update-versions" class="sheet-sub"></p>
446
+ </div>
447
+ <button id="update-close" class="icon-btn" type="button" aria-label="Close" data-i18n-aria-label="Close">
448
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12" /></svg>
449
+ </button>
450
+ </header>
451
+ <div class="sheet-body">
452
+ <p id="update-note" class="settings-note" data-i18n="Neutrino updates itself with npm. Restart it afterwards to use the new version.">Neutrino updates itself with npm. Restart it afterwards to use the new version.</p>
453
+ <p id="update-command-block" class="settings-note hidden"><span data-i18n="Update by hand with:">Update by hand with:</span> <code id="update-command">npm install -g @xingjisoft/neutrino</code></p>
454
+ <p id="update-feedback" class="form-feedback" role="status" aria-live="polite"></p>
455
+ </div>
456
+ <footer class="sheet-actions">
457
+ <button id="update-later" class="control" type="button" data-i18n="Later">Later</button>
458
+ <button id="update-now" class="primary" type="button" data-i18n="Update now" autofocus>Update now</button>
459
+ </footer>
460
+ </div>
461
+ </dialog>
462
+
463
+ <script src="app.js" type="module"></script>
464
+ </body>
465
+ </html>