@plmbr/notebook-intelligence 5.0.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.
Files changed (137) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +412 -0
  3. package/lib/api.d.ts +288 -0
  4. package/lib/api.js +927 -0
  5. package/lib/cell-output-bundle.d.ts +25 -0
  6. package/lib/cell-output-bundle.js +129 -0
  7. package/lib/cell-output-toolbar.d.ts +26 -0
  8. package/lib/cell-output-toolbar.js +188 -0
  9. package/lib/chat-progress-feedback.d.ts +3 -0
  10. package/lib/chat-progress-feedback.js +27 -0
  11. package/lib/chat-sidebar.d.ts +92 -0
  12. package/lib/chat-sidebar.js +3452 -0
  13. package/lib/command-ids.d.ts +39 -0
  14. package/lib/command-ids.js +44 -0
  15. package/lib/components/ask-user-question.d.ts +2 -0
  16. package/lib/components/ask-user-question.js +85 -0
  17. package/lib/components/checkbox.d.ts +2 -0
  18. package/lib/components/checkbox.js +30 -0
  19. package/lib/components/claude-mcp-panel.d.ts +2 -0
  20. package/lib/components/claude-mcp-panel.js +275 -0
  21. package/lib/components/claude-mcp-paste.d.ts +7 -0
  22. package/lib/components/claude-mcp-paste.js +104 -0
  23. package/lib/components/claude-session-picker.d.ts +8 -0
  24. package/lib/components/claude-session-picker.js +127 -0
  25. package/lib/components/form-dialog.d.ts +25 -0
  26. package/lib/components/form-dialog.js +35 -0
  27. package/lib/components/launcher-picker.d.ts +6 -0
  28. package/lib/components/launcher-picker.js +135 -0
  29. package/lib/components/mcp-util.d.ts +2 -0
  30. package/lib/components/mcp-util.js +37 -0
  31. package/lib/components/notebook-generation-popover.d.ts +7 -0
  32. package/lib/components/notebook-generation-popover.js +60 -0
  33. package/lib/components/pill.d.ts +2 -0
  34. package/lib/components/pill.js +5 -0
  35. package/lib/components/plugins-panel.d.ts +3 -0
  36. package/lib/components/plugins-panel.js +466 -0
  37. package/lib/components/settings-panel.d.ts +11 -0
  38. package/lib/components/settings-panel.js +742 -0
  39. package/lib/components/skills-panel.d.ts +2 -0
  40. package/lib/components/skills-panel.js +1264 -0
  41. package/lib/handler.d.ts +8 -0
  42. package/lib/handler.js +36 -0
  43. package/lib/icons.d.ts +45 -0
  44. package/lib/icons.js +54 -0
  45. package/lib/index.d.ts +8 -0
  46. package/lib/index.js +2079 -0
  47. package/lib/markdown-renderer.d.ts +10 -0
  48. package/lib/markdown-renderer.js +64 -0
  49. package/lib/notebook-generation-toolbar.d.ts +16 -0
  50. package/lib/notebook-generation-toolbar.js +197 -0
  51. package/lib/notebook-generation.d.ts +8 -0
  52. package/lib/notebook-generation.js +12 -0
  53. package/lib/open-file-refresh-watcher-env.d.ts +4 -0
  54. package/lib/open-file-refresh-watcher-env.js +33 -0
  55. package/lib/open-file-refresh-watcher.d.ts +97 -0
  56. package/lib/open-file-refresh-watcher.js +190 -0
  57. package/lib/shell-utils.d.ts +6 -0
  58. package/lib/shell-utils.js +9 -0
  59. package/lib/task-target-notebook.d.ts +2 -0
  60. package/lib/task-target-notebook.js +28 -0
  61. package/lib/terminal-drag-format.d.ts +9 -0
  62. package/lib/terminal-drag-format.js +23 -0
  63. package/lib/terminal-drag.d.ts +12 -0
  64. package/lib/terminal-drag.js +268 -0
  65. package/lib/tokens.d.ts +149 -0
  66. package/lib/tokens.js +88 -0
  67. package/lib/tour/tour-anchors.d.ts +18 -0
  68. package/lib/tour/tour-anchors.js +18 -0
  69. package/lib/tour/tour-config.d.ts +66 -0
  70. package/lib/tour/tour-config.js +99 -0
  71. package/lib/tour/tour-defaults.json +58 -0
  72. package/lib/tour/tour-events.d.ts +19 -0
  73. package/lib/tour/tour-events.js +30 -0
  74. package/lib/tour/tour-overlay.d.ts +6 -0
  75. package/lib/tour/tour-overlay.js +350 -0
  76. package/lib/tour/tour-state.d.ts +20 -0
  77. package/lib/tour/tour-state.js +81 -0
  78. package/lib/tour/tour-steps.d.ts +33 -0
  79. package/lib/tour/tour-steps.js +216 -0
  80. package/lib/utils.d.ts +53 -0
  81. package/lib/utils.js +385 -0
  82. package/package.json +258 -0
  83. package/schema/plugin.json +42 -0
  84. package/src/api.ts +1424 -0
  85. package/src/cell-output-bundle.ts +176 -0
  86. package/src/cell-output-toolbar.ts +232 -0
  87. package/src/chat-progress-feedback.ts +35 -0
  88. package/src/chat-sidebar.tsx +5147 -0
  89. package/src/command-ids.ts +67 -0
  90. package/src/components/ask-user-question.tsx +151 -0
  91. package/src/components/checkbox.tsx +62 -0
  92. package/src/components/claude-mcp-panel.tsx +543 -0
  93. package/src/components/claude-mcp-paste.ts +132 -0
  94. package/src/components/claude-session-picker.tsx +214 -0
  95. package/src/components/form-dialog.tsx +75 -0
  96. package/src/components/launcher-picker.tsx +237 -0
  97. package/src/components/mcp-util.ts +53 -0
  98. package/src/components/notebook-generation-popover.tsx +127 -0
  99. package/src/components/pill.tsx +15 -0
  100. package/src/components/plugins-panel.tsx +774 -0
  101. package/src/components/settings-panel.tsx +1631 -0
  102. package/src/components/skills-panel.tsx +2084 -0
  103. package/src/handler.ts +51 -0
  104. package/src/icons.ts +71 -0
  105. package/src/index.ts +2583 -0
  106. package/src/markdown-renderer.tsx +153 -0
  107. package/src/notebook-generation-toolbar.tsx +281 -0
  108. package/src/notebook-generation.ts +23 -0
  109. package/src/open-file-refresh-watcher-env.ts +52 -0
  110. package/src/open-file-refresh-watcher.ts +260 -0
  111. package/src/shell-utils.ts +10 -0
  112. package/src/svg.d.ts +4 -0
  113. package/src/task-target-notebook.ts +37 -0
  114. package/src/terminal-drag-format.ts +29 -0
  115. package/src/terminal-drag.ts +382 -0
  116. package/src/tokens.ts +171 -0
  117. package/src/tour/tour-anchors.ts +21 -0
  118. package/src/tour/tour-config.ts +160 -0
  119. package/src/tour/tour-events.ts +34 -0
  120. package/src/tour/tour-overlay.tsx +474 -0
  121. package/src/tour/tour-state.ts +87 -0
  122. package/src/tour/tour-steps.ts +281 -0
  123. package/src/utils.ts +455 -0
  124. package/style/base.css +3238 -0
  125. package/style/icons/cell-toolbar-bug.svg +5 -0
  126. package/style/icons/cell-toolbar-chat.svg +5 -0
  127. package/style/icons/cell-toolbar-sparkle.svg +5 -0
  128. package/style/icons/claude.svg +1 -0
  129. package/style/icons/copilot-warning.svg +1 -0
  130. package/style/icons/copilot.svg +1 -0
  131. package/style/icons/copy.svg +1 -0
  132. package/style/icons/openai.svg +1 -0
  133. package/style/icons/opencode.svg +1 -0
  134. package/style/icons/sparkles-warning.svg +5 -0
  135. package/style/icons/sparkles.svg +1 -0
  136. package/style/index.css +1 -0
  137. package/style/index.js +1 -0
@@ -0,0 +1,742 @@
1
+ // Copyright (c) Mehmet Bektas <mbektasgh@outlook.com>
2
+ import React, { useEffect, useRef, useState } from 'react';
3
+ import { ReactWidget } from '@jupyterlab/apputils';
4
+ import { VscWarning } from '../icons';
5
+ import * as path from 'path';
6
+ import copySvgstr from '../../style/icons/copy.svg';
7
+ import claudeSvgStr from '../../style/icons/claude.svg';
8
+ import { ClaudeModelType, ClaudeToolType, NBIAPI } from '../api';
9
+ import { CheckBoxItem } from './checkbox';
10
+ import { PillItem } from './pill';
11
+ import { mcpServerSettingsToEnabledState } from './mcp-util';
12
+ import { SettingsPanelComponentSkills } from './skills-panel';
13
+ import { SettingsPanelComponentClaudeMCP } from './claude-mcp-panel';
14
+ import { SettingsPanelComponentPlugins } from './plugins-panel';
15
+ import { writeTextToClipboard } from '../utils';
16
+ const lockedTip = (locked) => locked ? 'Locked by your administrator' : '';
17
+ // Stable id helper so the tab and its panel agree on aria-controls /
18
+ // aria-labelledby without scattering string concatenation through the
19
+ // component.
20
+ const tabId = (prefix, id) => `${prefix}-${id}`;
21
+ // WAI-ARIA tablist arrow-key navigation. Same shape for both the
22
+ // vertical (Up/Down) main tabs and the horizontal (Left/Right) Claude
23
+ // subtabs — the orientation flag picks which keys move the cursor.
24
+ // Returns an ``onKeyDown`` for the tablist container; callers decide
25
+ // what to do with each id (typically: select + focus).
26
+ function useTablistArrowKeys(tabs, activeId, onSelect, orientation, domIdFor) {
27
+ return (e) => {
28
+ var _a;
29
+ const key = e.key;
30
+ const prevKey = orientation === 'vertical' ? 'ArrowUp' : 'ArrowLeft';
31
+ const nextKey = orientation === 'vertical' ? 'ArrowDown' : 'ArrowRight';
32
+ if (key !== prevKey && key !== nextKey && key !== 'Home' && key !== 'End') {
33
+ return;
34
+ }
35
+ e.preventDefault();
36
+ const idx = tabs.findIndex(t => t.id === activeId);
37
+ let next = idx;
38
+ if (key === nextKey) {
39
+ next = (idx + 1) % tabs.length;
40
+ }
41
+ else if (key === prevKey) {
42
+ next = (idx - 1 + tabs.length) % tabs.length;
43
+ }
44
+ else if (key === 'Home') {
45
+ next = 0;
46
+ }
47
+ else if (key === 'End') {
48
+ next = tabs.length - 1;
49
+ }
50
+ onSelect(tabs[next].id);
51
+ (_a = document.getElementById(domIdFor(tabs[next].id))) === null || _a === void 0 ? void 0 : _a.focus();
52
+ };
53
+ }
54
+ // When a boolean policy is locked the panel shows the policy-resolved value;
55
+ // otherwise it shows the user's local toggle state.
56
+ const checkedValue = (policy, userValue) => (policy.locked ? policy.enabled : userValue);
57
+ function useNbiPolicies() {
58
+ const [featurePolicies, setFeaturePolicies] = useState(NBIAPI.config.featurePolicies);
59
+ const [settingLocks, setSettingLocks] = useState(NBIAPI.config.settingLocks);
60
+ useEffect(() => {
61
+ const handler = () => {
62
+ setFeaturePolicies(NBIAPI.config.featurePolicies);
63
+ setSettingLocks(NBIAPI.config.settingLocks);
64
+ };
65
+ NBIAPI.configChanged.connect(handler);
66
+ return () => {
67
+ NBIAPI.configChanged.disconnect(handler);
68
+ };
69
+ }, []);
70
+ return { featurePolicies, settingLocks };
71
+ }
72
+ const OPENAI_COMPATIBLE_CHAT_MODEL_ID = 'openai-compatible-chat-model';
73
+ const LITELLM_COMPATIBLE_CHAT_MODEL_ID = 'litellm-compatible-chat-model';
74
+ const OPENAI_COMPATIBLE_INLINE_COMPLETION_MODEL_ID = 'openai-compatible-inline-completion-model';
75
+ const LITELLM_COMPATIBLE_INLINE_COMPLETION_MODEL_ID = 'litellm-compatible-inline-completion-model';
76
+ export class SettingsPanel extends ReactWidget {
77
+ constructor(options) {
78
+ super();
79
+ this._onSave = options.onSave;
80
+ this._onEditMCPConfigClicked = options.onEditMCPConfigClicked;
81
+ }
82
+ render() {
83
+ return (React.createElement(SettingsPanelComponent, { onSave: this._onSave, onEditMCPConfigClicked: this._onEditMCPConfigClicked }));
84
+ }
85
+ }
86
+ const TABS = [
87
+ {
88
+ id: 'general',
89
+ label: 'General',
90
+ visible: () => true,
91
+ render: props => (React.createElement(SettingsPanelComponentGeneral, { onSave: props.onSave, onEditMCPConfigClicked: props.onEditMCPConfigClicked }))
92
+ },
93
+ {
94
+ id: 'claude',
95
+ label: 'Claude',
96
+ icon: () => (React.createElement("span", { className: "claude-icon", dangerouslySetInnerHTML: { __html: claudeSvgStr } })),
97
+ visible: () => true,
98
+ render: props => (React.createElement(SettingsPanelComponentClaude, { onEditMCPConfigClicked: props.onEditMCPConfigClicked }))
99
+ },
100
+ {
101
+ id: 'mcp-servers',
102
+ label: 'MCP Servers',
103
+ visible: ctx => !ctx.isInClaudeCodeMode,
104
+ render: props => (React.createElement(SettingsPanelComponentMCPServers, { onEditMCPConfigClicked: props.onEditMCPConfigClicked }))
105
+ },
106
+ {
107
+ id: 'claude-mcp',
108
+ label: 'Claude MCP',
109
+ visible: ctx => ctx.featurePolicies.claude_mcp_management.enabled &&
110
+ ctx.isInClaudeCodeMode &&
111
+ ctx.isClaudeCliAvailable,
112
+ render: () => React.createElement(SettingsPanelComponentClaudeMCP, null)
113
+ },
114
+ {
115
+ id: 'plugins',
116
+ label: 'Plugins',
117
+ visible: ctx => ctx.featurePolicies.claude_plugins_management.enabled &&
118
+ ctx.isInClaudeCodeMode &&
119
+ ctx.isClaudeCliAvailable,
120
+ render: () => React.createElement(SettingsPanelComponentPlugins, null)
121
+ },
122
+ {
123
+ id: 'skills',
124
+ label: 'Skills',
125
+ visible: ctx => ctx.featurePolicies.skills_management.enabled,
126
+ render: () => React.createElement(SettingsPanelComponentSkills, null)
127
+ }
128
+ ];
129
+ function SettingsPanelComponent(props) {
130
+ const [activeTab, setActiveTab] = useState('general');
131
+ const { featurePolicies } = useNbiPolicies();
132
+ const [isInClaudeCodeMode, setIsInClaudeCodeMode] = useState(NBIAPI.config.isInClaudeCodeMode);
133
+ const [isClaudeCliAvailable, setIsClaudeCliAvailable] = useState(NBIAPI.config.isClaudeCliAvailable);
134
+ useEffect(() => {
135
+ const handler = () => {
136
+ setIsInClaudeCodeMode(NBIAPI.config.isInClaudeCodeMode);
137
+ setIsClaudeCliAvailable(NBIAPI.config.isClaudeCliAvailable);
138
+ };
139
+ NBIAPI.configChanged.connect(handler);
140
+ return () => {
141
+ NBIAPI.configChanged.disconnect(handler);
142
+ };
143
+ }, []);
144
+ const ctx = {
145
+ featurePolicies,
146
+ isInClaudeCodeMode,
147
+ isClaudeCliAvailable
148
+ };
149
+ const visibleTabs = TABS.filter(t => t.visible(ctx));
150
+ const activeTabSpec = visibleTabs.find(t => t.id === activeTab);
151
+ // Bounce off a tab that just disappeared (admin policy flip, mode toggle).
152
+ useEffect(() => {
153
+ if (!activeTabSpec) {
154
+ setActiveTab('general');
155
+ }
156
+ }, [activeTabSpec]);
157
+ return (React.createElement("div", { className: "nbi-settings-panel" },
158
+ React.createElement(SettingsPanelTabsComponent, { tabs: visibleTabs, activeTab: activeTab, onTabSelected: setActiveTab }),
159
+ React.createElement("div", { className: "nbi-settings-panel-tab-content", role: "tabpanel", id: tabId('nbi-settings-tabpanel', activeTab), "aria-labelledby": tabId('nbi-settings-tab', activeTab) }, activeTabSpec && activeTabSpec.render(props))));
160
+ }
161
+ function SettingsPanelTabsComponent(props) {
162
+ const onKeyDown = useTablistArrowKeys(props.tabs, props.activeTab, props.onTabSelected, 'vertical', id => tabId('nbi-settings-tab', id));
163
+ return (React.createElement("div", { className: "nbi-settings-panel-tabs", role: "tablist", "aria-orientation": "vertical", "aria-label": "Settings sections", onKeyDown: onKeyDown }, props.tabs.map(tab => {
164
+ const selected = tab.id === props.activeTab;
165
+ return (React.createElement("button", { type: "button", key: tab.id, id: tabId('nbi-settings-tab', tab.id), className: `nbi-settings-panel-tab ${selected ? 'active' : ''}`, role: "tab", "aria-selected": selected, "aria-controls": tabId('nbi-settings-tabpanel', tab.id), tabIndex: selected ? 0 : -1, onClick: () => props.onTabSelected(tab.id) },
166
+ tab.icon && tab.icon(),
167
+ tab.label));
168
+ })));
169
+ }
170
+ function SettingsPanelComponentGeneral(props) {
171
+ const nbiConfig = NBIAPI.config;
172
+ const llmProviders = nbiConfig.llmProviders;
173
+ const [chatModels, setChatModels] = useState([]);
174
+ const [inlineCompletionModels, setInlineCompletionModels] = useState([]);
175
+ const isInClaudeCodeMode = nbiConfig.isInClaudeCodeMode;
176
+ const handleSaveSettings = async () => {
177
+ const config = {
178
+ default_chat_mode: defaultChatMode,
179
+ chat_model: {
180
+ provider: chatModelProvider,
181
+ model: chatModel,
182
+ properties: chatModelProperties
183
+ },
184
+ inline_completion_model: {
185
+ provider: inlineCompletionModelProvider,
186
+ model: inlineCompletionModel,
187
+ properties: inlineCompletionModelProperties
188
+ },
189
+ inline_completion_debouncer_delay: inlineCompletionDebouncerDelay
190
+ };
191
+ if (chatModelProvider === 'github-copilot' ||
192
+ inlineCompletionModelProvider === 'github-copilot') {
193
+ config.store_github_access_token = storeGitHubAccessToken;
194
+ }
195
+ await NBIAPI.setConfig(config);
196
+ props.onSave();
197
+ };
198
+ const handleRefreshOllamaModelListClick = async () => {
199
+ await NBIAPI.updateOllamaModelList();
200
+ updateModelOptionsForProvider(chatModelProvider, 'chat');
201
+ };
202
+ const [chatModelProvider, setChatModelProvider] = useState(nbiConfig.chatModel.provider || 'none');
203
+ const [inlineCompletionModelProvider, setInlineCompletionModelProvider] = useState(nbiConfig.inlineCompletionModel.provider || 'none');
204
+ const [defaultChatMode, setDefaultChatMode] = useState(nbiConfig.defaultChatMode);
205
+ const [chatModel, setChatModel] = useState(nbiConfig.chatModel.model);
206
+ const [chatModelProperties, setChatModelProperties] = useState([]);
207
+ const [inlineCompletionModelProperties, setInlineCompletionModelProperties] = useState([]);
208
+ const [inlineCompletionModel, setInlineCompletionModel] = useState(nbiConfig.inlineCompletionModel.model);
209
+ const [storeGitHubAccessToken, setStoreGitHubAccessToken] = useState(nbiConfig.storeGitHubAccessToken);
210
+ const [inlineCompletionDebouncerDelay, setInlineCompletionDebouncerDelay] = useState(nbiConfig.inlineCompletionDebouncerDelay);
211
+ const { featurePolicies, settingLocks } = useNbiPolicies();
212
+ const toggleExplainError = () => {
213
+ NBIAPI.setConfig({
214
+ enable_explain_error: !featurePolicies.explain_error.enabled
215
+ });
216
+ };
217
+ const toggleOutputFollowup = () => {
218
+ NBIAPI.setConfig({
219
+ enable_output_followup: !featurePolicies.output_followup.enabled
220
+ });
221
+ };
222
+ const toggleOutputToolbar = () => {
223
+ NBIAPI.setConfig({
224
+ enable_output_toolbar: !featurePolicies.output_toolbar.enabled
225
+ });
226
+ };
227
+ const toggleRefreshOpenFilesOnDiskChange = () => {
228
+ NBIAPI.setConfig({
229
+ refresh_open_files_on_disk_change: !featurePolicies.refresh_open_files_on_disk_change.enabled
230
+ });
231
+ };
232
+ const updateModelOptionsForProvider = (providerId, modelType) => {
233
+ if (modelType === 'chat') {
234
+ setChatModelProvider(providerId);
235
+ }
236
+ else {
237
+ setInlineCompletionModelProvider(providerId);
238
+ }
239
+ const models = modelType === 'chat'
240
+ ? nbiConfig.chatModels
241
+ : nbiConfig.inlineCompletionModels;
242
+ const selectedModelId = modelType === 'chat'
243
+ ? nbiConfig.chatModel.model
244
+ : nbiConfig.inlineCompletionModel.model;
245
+ const providerModels = models.filter((model) => model.provider === providerId);
246
+ if (modelType === 'chat') {
247
+ setChatModels(providerModels);
248
+ }
249
+ else {
250
+ setInlineCompletionModels(providerModels);
251
+ }
252
+ let selectedModel = providerModels.find((model) => model.id === selectedModelId);
253
+ if (!selectedModel) {
254
+ selectedModel = providerModels === null || providerModels === void 0 ? void 0 : providerModels[0];
255
+ }
256
+ if (selectedModel) {
257
+ if (modelType === 'chat') {
258
+ setChatModel(selectedModel.id);
259
+ setChatModelProperties(selectedModel.properties);
260
+ }
261
+ else {
262
+ setInlineCompletionModel(selectedModel.id);
263
+ setInlineCompletionModelProperties(selectedModel.properties);
264
+ }
265
+ }
266
+ else {
267
+ if (modelType === 'chat') {
268
+ setChatModelProperties([]);
269
+ }
270
+ else {
271
+ setInlineCompletionModelProperties([]);
272
+ }
273
+ }
274
+ };
275
+ const onModelPropertyChange = (modelType, propertyId, value) => {
276
+ const modelProperties = modelType === 'chat'
277
+ ? chatModelProperties
278
+ : inlineCompletionModelProperties;
279
+ const updatedProperties = modelProperties.map((property) => {
280
+ if (property.id === propertyId) {
281
+ return { ...property, value };
282
+ }
283
+ return property;
284
+ });
285
+ if (modelType === 'chat') {
286
+ setChatModelProperties(updatedProperties);
287
+ }
288
+ else {
289
+ setInlineCompletionModelProperties(updatedProperties);
290
+ }
291
+ };
292
+ useEffect(() => {
293
+ updateModelOptionsForProvider(chatModelProvider, 'chat');
294
+ updateModelOptionsForProvider(inlineCompletionModelProvider, 'inline-completion');
295
+ }, []);
296
+ useEffect(() => {
297
+ handleSaveSettings();
298
+ }, [
299
+ defaultChatMode,
300
+ chatModelProvider,
301
+ chatModel,
302
+ chatModelProperties,
303
+ inlineCompletionModelProvider,
304
+ inlineCompletionModel,
305
+ inlineCompletionModelProperties,
306
+ storeGitHubAccessToken,
307
+ inlineCompletionDebouncerDelay
308
+ ]);
309
+ return (React.createElement("div", { className: "config-dialog" },
310
+ React.createElement("div", { className: "config-dialog-body" },
311
+ !isInClaudeCodeMode && (React.createElement("div", { className: "model-config-section" },
312
+ React.createElement("div", { className: "model-config-section-header" }, "Default chat mode"),
313
+ React.createElement("div", { className: "model-config-section-body" },
314
+ React.createElement("div", { className: "model-config-section-row" },
315
+ React.createElement("div", { className: "model-config-section-column" },
316
+ React.createElement("div", null,
317
+ React.createElement("select", { className: "jp-mod-styled", value: defaultChatMode, onChange: event => setDefaultChatMode(event.target.value) },
318
+ React.createElement("option", { value: "ask" }, "Ask"),
319
+ React.createElement("option", { value: "agent" }, "Agent")))),
320
+ React.createElement("div", { className: "model-config-section-column" }, " "))))),
321
+ !isInClaudeCodeMode && (React.createElement("div", { className: "model-config-section" },
322
+ React.createElement("div", { className: "model-config-section-header" }, "Chat model"),
323
+ React.createElement("div", { className: "model-config-section-body" },
324
+ React.createElement("div", { className: "model-config-section-row" },
325
+ React.createElement("div", { className: "model-config-section-column" },
326
+ React.createElement("div", null, "Provider"),
327
+ React.createElement("div", { title: lockedTip(settingLocks.chat_model_provider.locked) },
328
+ React.createElement("select", { className: "jp-mod-styled", disabled: settingLocks.chat_model_provider.locked, onChange: event => updateModelOptionsForProvider(event.target.value, 'chat') },
329
+ llmProviders.map((provider, index) => (React.createElement("option", { key: index, value: provider.id, selected: provider.id === chatModelProvider }, provider.name))),
330
+ React.createElement("option", { key: -1, value: "none", selected: chatModelProvider === 'none' ||
331
+ !llmProviders.find(provider => provider.id === chatModelProvider) }, "None")))),
332
+ !['openai-compatible', 'litellm-compatible', 'none'].includes(chatModelProvider) &&
333
+ chatModels.length > 0 && (React.createElement("div", { className: "model-config-section-column" },
334
+ React.createElement("div", null, "Model"),
335
+ ![
336
+ OPENAI_COMPATIBLE_CHAT_MODEL_ID,
337
+ LITELLM_COMPATIBLE_CHAT_MODEL_ID
338
+ ].includes(chatModel) &&
339
+ chatModels.length > 0 && (React.createElement("div", { title: lockedTip(settingLocks.chat_model_id.locked) },
340
+ React.createElement("select", { className: "jp-mod-styled", disabled: settingLocks.chat_model_id.locked, onChange: event => setChatModel(event.target.value) }, chatModels.map((model, index) => (React.createElement("option", { key: index, value: model.id, selected: model.id === chatModel }, model.name))))))))),
341
+ React.createElement("div", { className: "model-config-section-row" },
342
+ React.createElement("div", { className: "model-config-section-column" }, chatModelProvider === 'ollama' &&
343
+ chatModels.length === 0 && (React.createElement("div", { className: "ollama-warning-message" },
344
+ "No Ollama models found! Make sure",
345
+ ' ',
346
+ React.createElement("a", { href: "https://ollama.com/", target: "_blank" }, "Ollama"),
347
+ ' ',
348
+ "is running and models are downloaded to your computer.",
349
+ ' ',
350
+ React.createElement("button", { type: "button", className: "link-button", onClick: handleRefreshOllamaModelListClick }, "Try again"),
351
+ ' ',
352
+ "once ready.")))),
353
+ React.createElement("div", { className: "model-config-section-row" },
354
+ React.createElement("div", { className: "model-config-section-column" }, chatModelProperties.map((property, index) => (React.createElement("div", { className: "form-field-row", key: index },
355
+ React.createElement("div", { className: "form-field-description" },
356
+ property.name,
357
+ " ",
358
+ property.optional ? '(optional)' : ''),
359
+ React.createElement("input", { name: "chat-model-id-input", placeholder: property.description, className: "jp-mod-styled", spellCheck: false, value: property.value, onChange: event => onModelPropertyChange('chat', property.id, event.target.value) }))))))))),
360
+ React.createElement("div", { className: "model-config-section" },
361
+ React.createElement("div", { className: "model-config-section-header" }, "Auto-complete model"),
362
+ React.createElement("div", { className: "model-config-section-body" },
363
+ React.createElement("div", { className: "model-config-section-row" },
364
+ React.createElement("div", { className: "model-config-section-column" },
365
+ React.createElement("div", null, "Provider"),
366
+ React.createElement("div", { title: lockedTip(settingLocks.inline_completion_model_provider.locked) },
367
+ React.createElement("select", { className: "jp-mod-styled", disabled: settingLocks.inline_completion_model_provider.locked, onChange: event => updateModelOptionsForProvider(event.target.value, 'inline-completion') },
368
+ llmProviders.map((provider, index) => (React.createElement("option", { key: index, value: provider.id, selected: provider.id === inlineCompletionModelProvider }, provider.name))),
369
+ React.createElement("option", { key: -1, value: "none", selected: inlineCompletionModelProvider === 'none' ||
370
+ !llmProviders.find(provider => provider.id === inlineCompletionModelProvider) }, "None")))),
371
+ !['openai-compatible', 'litellm-compatible', 'none'].includes(inlineCompletionModelProvider) && (React.createElement("div", { className: "model-config-section-column" },
372
+ React.createElement("div", null, "Model"),
373
+ ![
374
+ OPENAI_COMPATIBLE_INLINE_COMPLETION_MODEL_ID,
375
+ LITELLM_COMPATIBLE_INLINE_COMPLETION_MODEL_ID
376
+ ].includes(inlineCompletionModel) && (React.createElement("div", { title: lockedTip(settingLocks.inline_completion_model_id.locked) },
377
+ React.createElement("select", { className: "jp-mod-styled", disabled: settingLocks.inline_completion_model_id.locked, onChange: event => setInlineCompletionModel(event.target.value) }, inlineCompletionModels.map((model, index) => (React.createElement("option", { key: index, value: model.id, selected: model.id === inlineCompletionModel }, model.name))))))))),
378
+ React.createElement("div", { className: "model-config-section-row" },
379
+ React.createElement("div", { className: "model-config-section-column" }, inlineCompletionModelProperties.map((property, index) => (React.createElement("div", { className: "form-field-row", key: index },
380
+ React.createElement("div", { className: "form-field-description" },
381
+ property.name,
382
+ " ",
383
+ property.optional ? '(optional)' : ''),
384
+ React.createElement("input", { name: "inline-completion-model-id-input", placeholder: property.description, className: "jp-mod-styled", spellCheck: false, value: property.value, onChange: event => onModelPropertyChange('inline-completion', property.id, event.target.value) })))))))),
385
+ React.createElement("div", { className: "model-config-section-row", style: { width: '50%' } },
386
+ React.createElement("div", { className: "model-config-section-column" },
387
+ React.createElement("div", { className: "form-field-row", style: { paddingLeft: '10px' } },
388
+ React.createElement("div", { className: "form-field-description" }, "Auto-complete debouncer delay (ms)"),
389
+ React.createElement("input", { name: "inline-completion-debouncer-delay-input", placeholder: "Auto-complete debouncer delay (milliseconds)", className: "jp-mod-styled", spellCheck: false, value: inlineCompletionDebouncerDelay, type: "number", onChange: event => setInlineCompletionDebouncerDelay(Number(event.target.value)) })))),
390
+ !isInClaudeCodeMode &&
391
+ (chatModelProvider === 'github-copilot' ||
392
+ inlineCompletionModelProvider === 'github-copilot') && (React.createElement("div", { className: "model-config-section" },
393
+ React.createElement("div", { className: "model-config-section-header access-token-config-header" },
394
+ "GitHub Copilot login",
395
+ ' ',
396
+ React.createElement("a", { href: "https://github.com/plmbr/notebook-intelligence/blob/main/README.md#remembering-github-copilot-login", target: "_blank" },
397
+ ' ',
398
+ React.createElement(VscWarning, { className: "access-token-warning", title: "Click to learn more about security implications" }))),
399
+ React.createElement("div", { className: "model-config-section-body" },
400
+ React.createElement("div", { className: "model-config-section-row" },
401
+ React.createElement("div", { className: "model-config-section-column" },
402
+ React.createElement("label", { title: lockedTip(featurePolicies.store_github_access_token.locked) },
403
+ React.createElement("input", { type: "checkbox", checked: checkedValue(featurePolicies.store_github_access_token, storeGitHubAccessToken), disabled: featurePolicies.store_github_access_token.locked, onChange: event => {
404
+ setStoreGitHubAccessToken(event.target.checked);
405
+ } }),
406
+ "Remember my GitHub Copilot access token")))))),
407
+ React.createElement("div", { className: "model-config-section" },
408
+ React.createElement("div", { className: "model-config-section-header" }, "Cell output features"),
409
+ React.createElement("div", { className: "model-config-section-body" },
410
+ React.createElement("div", { className: "model-config-section-row" },
411
+ React.createElement("div", { className: "model-config-section-column" },
412
+ React.createElement(CheckBoxItem, { label: "Explain cell errors", title: "Show a 'Troubleshoot errors in output' context-menu item on failed cells", checked: featurePolicies.explain_error.enabled, disabled: featurePolicies.explain_error.locked, tooltip: lockedTip(featurePolicies.explain_error.locked), onClick: toggleExplainError }))),
413
+ React.createElement("div", { className: "model-config-section-row" },
414
+ React.createElement("div", { className: "model-config-section-column" },
415
+ React.createElement(CheckBoxItem, { label: "Ask about cell outputs", title: "Right-click a cell output to attach it to the chat", checked: featurePolicies.output_followup.enabled, disabled: featurePolicies.output_followup.locked, tooltip: lockedTip(featurePolicies.output_followup.locked), onClick: toggleOutputFollowup }))),
416
+ React.createElement("div", { className: "model-config-section-row" },
417
+ React.createElement("div", { className: "model-config-section-column" },
418
+ React.createElement(CheckBoxItem, { label: "Show output toolbar", title: "Show a hover toolbar over cell outputs with Explain / Ask / Troubleshoot buttons", checked: featurePolicies.output_toolbar.enabled, disabled: featurePolicies.output_toolbar.locked, tooltip: lockedTip(featurePolicies.output_toolbar.locked), onClick: toggleOutputToolbar }))))),
419
+ React.createElement("div", { className: "model-config-section" },
420
+ React.createElement("div", { className: "model-config-section-header" }, "External changes"),
421
+ React.createElement("div", { className: "model-config-section-body" },
422
+ React.createElement("div", { className: "model-config-section-row" },
423
+ React.createElement("div", { className: "model-config-section-column" },
424
+ React.createElement(CheckBoxItem, { label: "Refresh open files when changed on disk", title: "Automatically reload notebook and file editor tabs when an external process (terminal command, sync client, or AI agent) edits the file. Skipped when the tab has unsaved local edits.", checked: featurePolicies.refresh_open_files_on_disk_change.enabled, disabled: featurePolicies.refresh_open_files_on_disk_change.locked, tooltip: lockedTip(featurePolicies.refresh_open_files_on_disk_change.locked), onClick: toggleRefreshOpenFilesOnDiskChange }))))),
425
+ React.createElement("div", { className: "model-config-section" },
426
+ React.createElement("div", { className: "model-config-section-header" }, "Config file path"),
427
+ React.createElement("div", { className: "model-config-section-body" },
428
+ React.createElement("div", { className: "model-config-section-row" },
429
+ React.createElement("div", { className: "model-config-section-column" },
430
+ React.createElement("span", { className: "user-code-span", onClick: () => {
431
+ void writeTextToClipboard(path.join(NBIAPI.config.userConfigDir, 'config.json'));
432
+ return true;
433
+ } },
434
+ path.join(NBIAPI.config.userConfigDir, 'config.json'),
435
+ ' ',
436
+ React.createElement("span", { className: "copy-icon", dangerouslySetInnerHTML: { __html: copySvgstr } })))))))));
437
+ }
438
+ function SettingsPanelComponentMCPServers(props) {
439
+ const nbiConfig = NBIAPI.config;
440
+ const mcpServersRef = useRef(nbiConfig.toolConfig.mcpServers);
441
+ const mcpServerSettingsRef = useRef(nbiConfig.mcpServerSettings);
442
+ const [renderCount, setRenderCount] = useState(1);
443
+ const [mcpServerEnabledState, setMCPServerEnabledState] = useState(new Map(mcpServerSettingsToEnabledState(mcpServersRef.current, mcpServerSettingsRef.current)));
444
+ const mcpServerEnabledStateToMcpServerSettings = () => {
445
+ const mcpServerSettings = {};
446
+ for (const mcpServer of mcpServersRef.current) {
447
+ if (mcpServerEnabledState.has(mcpServer.id)) {
448
+ const disabledTools = [];
449
+ for (const tool of mcpServer.tools) {
450
+ if (!mcpServerEnabledState.get(mcpServer.id).has(tool.name)) {
451
+ disabledTools.push(tool.name);
452
+ }
453
+ }
454
+ mcpServerSettings[mcpServer.id] = {
455
+ disabled: false,
456
+ disabled_tools: disabledTools
457
+ };
458
+ }
459
+ else {
460
+ mcpServerSettings[mcpServer.id] = { disabled: true };
461
+ }
462
+ }
463
+ return mcpServerSettings;
464
+ };
465
+ const syncSettingsToServerState = () => {
466
+ NBIAPI.setConfig({
467
+ mcp_server_settings: mcpServerSettingsRef.current
468
+ });
469
+ };
470
+ const handleReloadMCPServersClick = async () => {
471
+ await NBIAPI.reloadMCPServers();
472
+ };
473
+ useEffect(() => {
474
+ syncSettingsToServerState();
475
+ }, [mcpServerSettingsRef.current]);
476
+ useEffect(() => {
477
+ mcpServerSettingsRef.current = mcpServerEnabledStateToMcpServerSettings();
478
+ setRenderCount(renderCount => renderCount + 1);
479
+ }, [mcpServerEnabledState]);
480
+ const setMCPServerEnabled = (serverId, enabled) => {
481
+ var _a;
482
+ const currentState = new Map(mcpServerEnabledState);
483
+ if (enabled) {
484
+ if (!(serverId in currentState)) {
485
+ currentState.set(serverId, new Set((_a = mcpServersRef.current
486
+ .find((server) => server.id === serverId)) === null || _a === void 0 ? void 0 : _a.tools.map((tool) => tool.name)));
487
+ }
488
+ }
489
+ else {
490
+ currentState.delete(serverId);
491
+ }
492
+ setMCPServerEnabledState(currentState);
493
+ };
494
+ const getMCPServerEnabled = (serverId) => {
495
+ return mcpServerEnabledState.has(serverId);
496
+ };
497
+ const getMCPServerToolEnabled = (serverId, toolName) => {
498
+ return (mcpServerEnabledState.has(serverId) &&
499
+ mcpServerEnabledState.get(serverId).has(toolName));
500
+ };
501
+ const setMCPServerToolEnabled = (serverId, toolName, enabled) => {
502
+ const currentState = new Map(mcpServerEnabledState);
503
+ const serverState = currentState.get(serverId);
504
+ if (enabled) {
505
+ serverState.add(toolName);
506
+ }
507
+ else {
508
+ serverState.delete(toolName);
509
+ }
510
+ setMCPServerEnabledState(currentState);
511
+ };
512
+ useEffect(() => {
513
+ const handler = () => {
514
+ mcpServersRef.current = nbiConfig.toolConfig.mcpServers;
515
+ mcpServerSettingsRef.current = nbiConfig.mcpServerSettings;
516
+ setRenderCount(renderCount => renderCount + 1);
517
+ };
518
+ NBIAPI.configChanged.connect(handler);
519
+ return () => {
520
+ NBIAPI.configChanged.disconnect(handler);
521
+ };
522
+ }, []);
523
+ return (React.createElement("div", { className: "config-dialog" },
524
+ React.createElement("div", { className: "config-dialog-body" },
525
+ React.createElement("div", { className: "model-config-section" },
526
+ React.createElement("div", { className: "model-config-section-header", style: { display: 'flex' } },
527
+ React.createElement("div", { style: { flexGrow: 1 } }, "MCP Servers"),
528
+ React.createElement("div", null,
529
+ React.createElement("button", { className: "jp-toast-button jp-mod-small jp-Button", onClick: handleReloadMCPServersClick },
530
+ React.createElement("div", { className: "jp-Dialog-buttonLabel" }, "Reload")))),
531
+ React.createElement("div", { className: "model-config-section-body" },
532
+ mcpServersRef.current.length === 0 && renderCount > 0 && (React.createElement("div", { className: "model-config-section-row" },
533
+ React.createElement("div", { className: "model-config-section-column" },
534
+ React.createElement("div", null, "No MCP servers found. Add MCP servers in the configuration file.")))),
535
+ mcpServersRef.current.length > 0 && renderCount > 0 && (React.createElement("div", { className: "model-config-section-row" },
536
+ React.createElement("div", { className: "model-config-section-column" }, mcpServersRef.current.map((server) => (React.createElement("div", { key: server.id },
537
+ React.createElement("div", { style: { display: 'flex', alignItems: 'center' } },
538
+ React.createElement(CheckBoxItem, { header: true, label: server.id, checked: getMCPServerEnabled(server.id), onClick: () => {
539
+ setMCPServerEnabled(server.id, !getMCPServerEnabled(server.id));
540
+ } }),
541
+ React.createElement("div", { className: `server-status-indicator ${server.status}`, title: server.status })),
542
+ getMCPServerEnabled(server.id) && (React.createElement("div", null,
543
+ server.tools.length > 0 && (React.createElement("div", { className: "mcp-server-tools" },
544
+ React.createElement("div", { className: "mcp-server-tools-header" }, "Tools"),
545
+ React.createElement("div", null, server.tools.map((tool) => (React.createElement(PillItem, { label: tool.name, title: tool.description, checked: getMCPServerToolEnabled(server.id, tool.name), onClick: () => {
546
+ setMCPServerToolEnabled(server.id, tool.name, !getMCPServerToolEnabled(server.id, tool.name));
547
+ } })))))),
548
+ server.prompts.length > 0 && (React.createElement("div", { className: "mcp-server-prompts" },
549
+ React.createElement("div", { className: "mcp-server-prompts-header" }, "Prompts"),
550
+ React.createElement("div", null, server.prompts.map((prompt) => (React.createElement(PillItem, { label: prompt.name, title: prompt.description, checked: true })))))))))))))),
551
+ React.createElement("div", { className: "model-config-section-row" },
552
+ React.createElement("div", { className: "model-config-section-column", style: { flexGrow: 'initial' } },
553
+ React.createElement("button", { className: "jp-Dialog-button jp-mod-accept jp-mod-styled", style: { width: 'max-content' }, onClick: props.onEditMCPConfigClicked },
554
+ React.createElement("div", { className: "jp-Dialog-buttonLabel" }, "Add / Edit")))))))));
555
+ }
556
+ function SettingsPanelComponentClaude(props) {
557
+ var _a, _b, _c, _d, _e, _f, _g;
558
+ const nbiConfig = NBIAPI.config;
559
+ const claudeSettingsRef = useRef(nbiConfig.claudeSettings);
560
+ const [_renderCount, setRenderCount] = useState(1);
561
+ const [claudeEnabled, setClaudeEnabled] = useState(nbiConfig.isInClaudeCodeMode);
562
+ const [chatModel, setChatModel] = useState((_a = nbiConfig.claudeSettings.chat_model) !== null && _a !== void 0 ? _a : ClaudeModelType.Default);
563
+ const [inlineCompletionModel, setInlineCompletionModel] = useState((_b = nbiConfig.claudeSettings.inline_completion_model) !== null && _b !== void 0 ? _b : ClaudeModelType.Default);
564
+ const [apiKey, setApiKey] = useState((_c = nbiConfig.claudeSettings.api_key) !== null && _c !== void 0 ? _c : '');
565
+ const [baseUrl, setBaseUrl] = useState((_d = nbiConfig.claudeSettings.base_url) !== null && _d !== void 0 ? _d : '');
566
+ const [settingSources, setSettingSources] = useState((_e = nbiConfig.claudeSettings.setting_sources) !== null && _e !== void 0 ? _e : []);
567
+ const [tools, setTools] = useState((_f = nbiConfig.claudeSettings.tools) !== null && _f !== void 0 ? _f : [
568
+ ClaudeToolType.ClaudeCodeTools,
569
+ ClaudeToolType.JupyterUITools
570
+ ]);
571
+ const [continueConversation, setContinueConversation] = useState((_g = nbiConfig.claudeSettings.continue_conversation) !== null && _g !== void 0 ? _g : false);
572
+ const [claudeModels, setClaudeModels] = useState(nbiConfig.claudeModels);
573
+ const [loadingModels, setLoadingModels] = useState(false);
574
+ const { featurePolicies, settingLocks } = useNbiPolicies();
575
+ useEffect(() => {
576
+ const handler = () => {
577
+ claudeSettingsRef.current = nbiConfig.claudeSettings;
578
+ setClaudeModels(nbiConfig.claudeModels);
579
+ setRenderCount(renderCount => renderCount + 1);
580
+ };
581
+ NBIAPI.configChanged.connect(handler);
582
+ return () => {
583
+ NBIAPI.configChanged.disconnect(handler);
584
+ };
585
+ }, []);
586
+ const refreshClaudeModels = async () => {
587
+ setLoadingModels(true);
588
+ try {
589
+ await NBIAPI.updateClaudeModelList();
590
+ const models = nbiConfig.claudeModels;
591
+ console.log('claude_models after refresh:', models);
592
+ setClaudeModels(models);
593
+ }
594
+ finally {
595
+ setLoadingModels(false);
596
+ }
597
+ };
598
+ const syncSettingsToServerState = () => {
599
+ NBIAPI.setConfig({
600
+ claude_settings: {
601
+ enabled: claudeEnabled,
602
+ chat_model: chatModel,
603
+ inline_completion_model: inlineCompletionModel,
604
+ api_key: apiKey,
605
+ base_url: baseUrl,
606
+ setting_sources: settingSources,
607
+ tools: tools,
608
+ continue_conversation: continueConversation
609
+ }
610
+ });
611
+ };
612
+ useEffect(() => {
613
+ syncSettingsToServerState();
614
+ }, [
615
+ claudeEnabled,
616
+ chatModel,
617
+ inlineCompletionModel,
618
+ apiKey,
619
+ baseUrl,
620
+ settingSources,
621
+ tools,
622
+ continueConversation
623
+ ]);
624
+ return (React.createElement("div", { className: "config-dialog claude-mode-config-dialog" },
625
+ React.createElement("div", { className: "config-dialog-body" },
626
+ React.createElement("div", { className: "model-config-section" },
627
+ React.createElement("div", { className: "model-config-section-header" }, "Enable Claude mode"),
628
+ React.createElement("div", { className: "model-config-section-body" },
629
+ React.createElement("div", { className: "model-config-section-row" },
630
+ React.createElement("span", null,
631
+ "This requires a",
632
+ ' ',
633
+ React.createElement("a", { href: "https://claude.ai", target: "_blank" }, "Claude"),
634
+ ' ',
635
+ "account and",
636
+ ' ',
637
+ React.createElement("a", { href: "https://code.claude.com/", target: "_blank" }, "Claude Code"),
638
+ ' ',
639
+ "installed in your system.")),
640
+ React.createElement("div", { className: "model-config-section-row" },
641
+ React.createElement("div", { className: "model-config-section-column" },
642
+ React.createElement("div", null,
643
+ React.createElement(CheckBoxItem, { header: true, label: "Enable Claude mode", checked: checkedValue(featurePolicies.claude_mode, claudeEnabled), disabled: featurePolicies.claude_mode.locked, tooltip: lockedTip(featurePolicies.claude_mode.locked), onClick: () => {
644
+ setClaudeEnabled(!claudeEnabled);
645
+ } })))))),
646
+ React.createElement("div", { className: "model-config-section" },
647
+ React.createElement("div", { className: "model-config-section-header", style: { display: 'flex' } },
648
+ React.createElement("div", { style: { flexGrow: 1 } }, "Models"),
649
+ React.createElement("div", null,
650
+ React.createElement("button", { className: "jp-toast-button jp-mod-small jp-Button", onClick: refreshClaudeModels, disabled: loadingModels },
651
+ React.createElement("div", { className: "jp-Dialog-buttonLabel" }, loadingModels ? 'Loading...' : 'Refresh')))),
652
+ React.createElement("div", { className: "model-config-section-body" },
653
+ React.createElement("div", { className: "model-config-section-row" },
654
+ React.createElement("div", { className: "model-config-section-column" },
655
+ React.createElement("div", { id: "nbi-claude-chat-model-label" }, "Chat model"),
656
+ React.createElement("div", { title: lockedTip(settingLocks.claude_chat_model.locked) },
657
+ React.createElement("select", { className: "jp-mod-styled", "aria-labelledby": "nbi-claude-chat-model-label", "aria-describedby": settingLocks.claude_chat_model.locked
658
+ ? 'nbi-claude-chat-model-lock-reason'
659
+ : undefined, disabled: settingLocks.claude_chat_model.locked, value: chatModel, onChange: event => setChatModel(event.target.value) },
660
+ React.createElement("option", { value: ClaudeModelType.Default }, "Default (recommended)"),
661
+ chatModel !== ClaudeModelType.Default &&
662
+ !claudeModels.some(m => m.id === chatModel) && (React.createElement("option", { key: chatModel, value: chatModel }, chatModel)),
663
+ claudeModels.map(model => (React.createElement("option", { key: model.id, value: model.id }, model.name)))),
664
+ settingLocks.claude_chat_model.locked && (React.createElement("span", { id: "nbi-claude-chat-model-lock-reason", className: "nbi-sr-only" }, "Locked by your administrator")))),
665
+ React.createElement("div", { className: "model-config-section-column" },
666
+ React.createElement("div", { id: "nbi-claude-inline-model-label" }, "Auto-complete model"),
667
+ React.createElement("div", { title: lockedTip(settingLocks.claude_inline_completion_model.locked) },
668
+ React.createElement("select", { className: "jp-mod-styled", "aria-labelledby": "nbi-claude-inline-model-label", "aria-describedby": settingLocks.claude_inline_completion_model.locked
669
+ ? 'nbi-claude-inline-model-lock-reason'
670
+ : undefined, disabled: settingLocks.claude_inline_completion_model.locked, value: inlineCompletionModel, onChange: event => setInlineCompletionModel(event.target.value) },
671
+ React.createElement("option", { value: ClaudeModelType.None }, "None"),
672
+ React.createElement("option", { value: ClaudeModelType.Inherit }, "Inherit from general settings"),
673
+ React.createElement("option", { value: ClaudeModelType.Default }, "Default (recommended)"),
674
+ ![
675
+ ClaudeModelType.None,
676
+ ClaudeModelType.Inherit,
677
+ ClaudeModelType.Default
678
+ ].includes(inlineCompletionModel) &&
679
+ !claudeModels.some(m => m.id === inlineCompletionModel) && (React.createElement("option", { key: inlineCompletionModel, value: inlineCompletionModel }, inlineCompletionModel)),
680
+ claudeModels.map(model => (React.createElement("option", { key: model.id, value: model.id }, model.name)))),
681
+ settingLocks.claude_inline_completion_model.locked && (React.createElement("span", { id: "nbi-claude-inline-model-lock-reason", className: "nbi-sr-only" }, "Locked by your administrator"))))))),
682
+ React.createElement("div", { className: "model-config-section" },
683
+ React.createElement("div", { className: "model-config-section-header" }, "Chat Agent setting sources"),
684
+ React.createElement("div", { className: "model-config-section-body" },
685
+ React.createElement("div", { className: "model-config-section-row" },
686
+ React.createElement("div", { className: "model-config-section-column" },
687
+ React.createElement("div", null,
688
+ React.createElement(CheckBoxItem, { header: true, label: "User", checked: checkedValue(featurePolicies.claude_setting_source_user, settingSources.includes('user')), disabled: featurePolicies.claude_setting_source_user.locked, tooltip: lockedTip(featurePolicies.claude_setting_source_user.locked), onClick: () => {
689
+ setSettingSources(settingSources.includes('user')
690
+ ? settingSources.filter((source) => source !== 'user')
691
+ : [...settingSources, 'user']);
692
+ } }))),
693
+ React.createElement("div", { className: "model-config-section-column" },
694
+ React.createElement("div", null,
695
+ React.createElement(CheckBoxItem, { header: true, label: "Project (Jupyter root directory)", checked: checkedValue(featurePolicies.claude_setting_source_project, settingSources.includes('project')), disabled: featurePolicies.claude_setting_source_project.locked, tooltip: lockedTip(featurePolicies.claude_setting_source_project.locked), onClick: () => {
696
+ setSettingSources(settingSources.includes('project')
697
+ ? settingSources.filter((source) => source !== 'project')
698
+ : [...settingSources, 'project']);
699
+ } })))))),
700
+ React.createElement("div", { className: "model-config-section" },
701
+ React.createElement("div", { className: "model-config-section-header" }, "Chat Agent tools"),
702
+ React.createElement("div", { className: "model-config-section-body" },
703
+ React.createElement("div", { className: "model-config-section-row" },
704
+ React.createElement("div", { className: "model-config-section-column" },
705
+ React.createElement("div", null,
706
+ React.createElement(CheckBoxItem, { header: true, label: "Claude Code tools", checked: checkedValue(featurePolicies.claude_code_tools, tools.includes(ClaudeToolType.ClaudeCodeTools)), disabled: true, tooltip: lockedTip(featurePolicies.claude_code_tools.locked), onClick: () => {
707
+ setTools(tools.includes(ClaudeToolType.ClaudeCodeTools)
708
+ ? tools.filter((tool) => tool !== ClaudeToolType.ClaudeCodeTools)
709
+ : [...tools, ClaudeToolType.ClaudeCodeTools]);
710
+ } }))),
711
+ React.createElement("div", { className: "model-config-section-column" },
712
+ React.createElement("div", null,
713
+ React.createElement(CheckBoxItem, { header: true, label: "Jupyter UI tools", checked: checkedValue(featurePolicies.claude_jupyter_ui_tools, tools.includes(ClaudeToolType.JupyterUITools)), disabled: featurePolicies.claude_jupyter_ui_tools.locked, tooltip: lockedTip(featurePolicies.claude_jupyter_ui_tools.locked), onClick: () => {
714
+ setTools(tools.includes(ClaudeToolType.JupyterUITools)
715
+ ? tools.filter((tool) => tool !== ClaudeToolType.JupyterUITools)
716
+ : [...tools, ClaudeToolType.JupyterUITools]);
717
+ } })))))),
718
+ React.createElement("div", { className: "model-config-section" },
719
+ React.createElement("div", { className: "model-config-section-header" }, "Conversation History"),
720
+ React.createElement("div", { className: "model-config-section-body" },
721
+ React.createElement("div", { className: "model-config-section-row" },
722
+ React.createElement("div", { className: "model-config-section-column" },
723
+ React.createElement("div", null,
724
+ React.createElement(CheckBoxItem, { header: true, label: "Remember conversation history", checked: checkedValue(featurePolicies.claude_continue_conversation, continueConversation), disabled: featurePolicies.claude_continue_conversation.locked, tooltip: lockedTip(featurePolicies.claude_continue_conversation.locked), onClick: () => {
725
+ setContinueConversation(!continueConversation);
726
+ } })))))),
727
+ React.createElement("div", { className: "model-config-section" },
728
+ React.createElement("div", { className: "model-config-section-header" }, "Claude account"),
729
+ React.createElement("div", { className: "model-config-section-body" },
730
+ React.createElement("div", { className: "model-config-section-row" },
731
+ React.createElement("div", { className: "model-config-section-column" },
732
+ React.createElement("div", { className: "form-field-row" },
733
+ React.createElement("div", { className: "form-field-description" }, "API Key (optional)"),
734
+ React.createElement("input", { name: "chat-model-id-input", placeholder: settingLocks.claude_api_key.locked
735
+ ? 'Locked by ANTHROPIC_API_KEY'
736
+ : 'API Key', className: "jp-mod-styled", spellCheck: false, value: settingLocks.claude_api_key.locked ? '' : apiKey, disabled: settingLocks.claude_api_key.locked, title: lockedTip(settingLocks.claude_api_key.locked), onChange: event => setApiKey(event.target.value) })),
737
+ React.createElement("div", { className: "form-field-row" },
738
+ React.createElement("div", { className: "form-field-description" }, "Base URL (optional)"),
739
+ React.createElement("input", { name: "chat-model-id-input", placeholder: settingLocks.claude_base_url.locked
740
+ ? 'Locked by ANTHROPIC_BASE_URL'
741
+ : 'https://api.anthropic.com', className: "jp-mod-styled", spellCheck: false, value: baseUrl, disabled: settingLocks.claude_base_url.locked, title: lockedTip(settingLocks.claude_base_url.locked), onChange: event => setBaseUrl(event.target.value) })))))))));
742
+ }