@researai/deepscientist 1.5.12 → 1.5.14

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 (99) hide show
  1. package/bin/ds.js +20 -3
  2. package/docs/en/00_QUICK_START.md +24 -5
  3. package/docs/en/01_SETTINGS_REFERENCE.md +4 -0
  4. package/docs/en/05_TUI_GUIDE.md +466 -96
  5. package/docs/en/09_DOCTOR.md +24 -5
  6. package/docs/en/15_CODEX_PROVIDER_SETUP.md +113 -15
  7. package/docs/en/README.md +2 -0
  8. package/docs/zh/00_QUICK_START.md +24 -5
  9. package/docs/zh/01_SETTINGS_REFERENCE.md +4 -0
  10. package/docs/zh/05_TUI_GUIDE.md +465 -82
  11. package/docs/zh/09_DOCTOR.md +24 -5
  12. package/docs/zh/15_CODEX_PROVIDER_SETUP.md +113 -15
  13. package/docs/zh/README.md +2 -0
  14. package/package.json +2 -1
  15. package/pyproject.toml +1 -1
  16. package/src/deepscientist/__init__.py +1 -1
  17. package/src/deepscientist/artifact/service.py +125 -2
  18. package/src/deepscientist/cli.py +3 -0
  19. package/src/deepscientist/codex_cli_compat.py +117 -0
  20. package/src/deepscientist/config/service.py +53 -6
  21. package/src/deepscientist/connector/lingzhu_support.py +23 -4
  22. package/src/deepscientist/daemon/app.py +111 -30
  23. package/src/deepscientist/mcp/server.py +161 -19
  24. package/src/deepscientist/prompts/builder.py +13 -54
  25. package/src/deepscientist/quest/service.py +99 -0
  26. package/src/deepscientist/quest/stage_views.py +134 -29
  27. package/src/deepscientist/runners/codex.py +11 -2
  28. package/src/deepscientist/runners/runtime_overrides.py +3 -0
  29. package/src/deepscientist/shared.py +6 -1
  30. package/src/prompts/system.md +220 -2065
  31. package/src/skills/baseline/SKILL.md +265 -994
  32. package/src/skills/baseline/references/artifact-payload-examples.md +39 -0
  33. package/src/skills/baseline/references/baseline-checklist-template.md +21 -32
  34. package/src/skills/baseline/references/baseline-plan-template.md +41 -57
  35. package/src/tui/dist/app/AppContainer.js +1442 -52
  36. package/src/tui/dist/components/Composer.js +1 -1
  37. package/src/tui/dist/components/ConfigScreen.js +190 -36
  38. package/src/tui/dist/components/GradientStatusText.js +1 -20
  39. package/src/tui/dist/components/InputPrompt.js +41 -32
  40. package/src/tui/dist/components/LoadingIndicator.js +1 -1
  41. package/src/tui/dist/components/Logo.js +61 -38
  42. package/src/tui/dist/components/MainContent.js +10 -3
  43. package/src/tui/dist/components/WelcomePanel.js +4 -12
  44. package/src/tui/dist/components/messages/AssistantMessage.js +1 -1
  45. package/src/tui/dist/components/messages/BashExecOperationMessage.js +3 -3
  46. package/src/tui/dist/components/messages/OperationMessage.js +1 -1
  47. package/src/tui/dist/index.js +28 -1
  48. package/src/tui/dist/layouts/DefaultAppLayout.js +3 -3
  49. package/src/tui/dist/lib/api.js +17 -0
  50. package/src/tui/dist/lib/connectorConfig.js +90 -0
  51. package/src/tui/dist/lib/connectors.js +261 -0
  52. package/src/tui/dist/lib/qr.js +21 -0
  53. package/src/tui/dist/semantic-colors.js +29 -19
  54. package/src/tui/package.json +2 -1
  55. package/src/ui/dist/assets/{AiManusChatView-CnJcXynW.js → AiManusChatView-DaF9Nge_.js} +12 -12
  56. package/src/ui/dist/assets/{AnalysisPlugin-DeyzPEhV.js → AnalysisPlugin-BSVx6dXE.js} +1 -1
  57. package/src/ui/dist/assets/{CliPlugin-CB1YODQn.js → CliPlugin-C9gzJX41.js} +9 -9
  58. package/src/ui/dist/assets/{CodeEditorPlugin-B-xicq1e.js → CodeEditorPlugin-DU9G0Tox.js} +8 -8
  59. package/src/ui/dist/assets/{CodeViewerPlugin-DT54ysXa.js → CodeViewerPlugin-DoX_fI9l.js} +5 -5
  60. package/src/ui/dist/assets/{DocViewerPlugin-DQtKT-VD.js → DocViewerPlugin-C4FWIXuU.js} +3 -3
  61. package/src/ui/dist/assets/{GitDiffViewerPlugin-hqHbCfnv.js → GitDiffViewerPlugin-BgfFMgtf.js} +20 -20
  62. package/src/ui/dist/assets/{ImageViewerPlugin-OcVo33jV.js → ImageViewerPlugin-tcPkfY_x.js} +5 -5
  63. package/src/ui/dist/assets/{LabCopilotPanel-DdGwhEUV.js → LabCopilotPanel-_dKV60Bf.js} +11 -11
  64. package/src/ui/dist/assets/{LabPlugin-Ciz1gDaX.js → LabPlugin-Bje0ayoC.js} +2 -2
  65. package/src/ui/dist/assets/{LatexPlugin-BhmjNQRC.js → LatexPlugin-CVsBzAln.js} +7 -7
  66. package/src/ui/dist/assets/{MarkdownViewerPlugin-BzdVH9Bx.js → MarkdownViewerPlugin-xjmrqv_8.js} +4 -4
  67. package/src/ui/dist/assets/{MarketplacePlugin-DmyHspXt.js → MarketplacePlugin-mMM2A8wP.js} +3 -3
  68. package/src/ui/dist/assets/{NotebookEditor-BTVYRGkm.js → NotebookEditor-3kVDSOBo.js} +11 -11
  69. package/src/ui/dist/assets/{NotebookEditor-BMXKrDRk.js → NotebookEditor-SoJ8X-MO.js} +1 -1
  70. package/src/ui/dist/assets/{PdfLoader-CvcjJHXv.js → PdfLoader-DElVuHl9.js} +1 -1
  71. package/src/ui/dist/assets/{PdfMarkdownPlugin-DW2ej8Vk.js → PdfMarkdownPlugin-Bq88XT4G.js} +2 -2
  72. package/src/ui/dist/assets/{PdfViewerPlugin-CmlDxbhU.js → PdfViewerPlugin-CsCXMo9S.js} +10 -10
  73. package/src/ui/dist/assets/{SearchPlugin-DAjQZPSv.js → SearchPlugin-oUPvy19k.js} +1 -1
  74. package/src/ui/dist/assets/{TextViewerPlugin-C-nVAZb_.js → TextViewerPlugin-CRkT9yNy.js} +5 -5
  75. package/src/ui/dist/assets/{VNCViewer-D7-dIYon.js → VNCViewer-BgbuvWhR.js} +10 -10
  76. package/src/ui/dist/assets/{bot-C_G4WtNI.js → bot-v_RASACv.js} +1 -1
  77. package/src/ui/dist/assets/{code-Cd7WfiWq.js → code-5hC9d0VH.js} +1 -1
  78. package/src/ui/dist/assets/{file-content-B57zsL9y.js → file-content-D1PxfOrp.js} +1 -1
  79. package/src/ui/dist/assets/{file-diff-panel-DVoheLFq.js → file-diff-panel-DG1oT_Hj.js} +1 -1
  80. package/src/ui/dist/assets/{file-socket-B5kXFxZP.js → file-socket-BmdFYQlk.js} +1 -1
  81. package/src/ui/dist/assets/{image-LLOjkMHF.js → image-Dqe2X2tW.js} +1 -1
  82. package/src/ui/dist/assets/{index-Dxa2eYMY.js → index-DVsMKK_y.js} +1 -1
  83. package/src/ui/dist/assets/{index-C3r2iGrp.js → index-Duvz8Ip0.js} +12 -12
  84. package/src/ui/dist/assets/{index-CLQauncb.js → index-Nt9hS4ck.js} +470 -165
  85. package/src/ui/dist/assets/{index-hOUOWbW2.js → index-RDlNXXx1.js} +2 -2
  86. package/src/ui/dist/assets/{monaco-BGGAEii3.js → monaco-DIXge1CP.js} +1 -1
  87. package/src/ui/dist/assets/{pdf-effect-queue-DlEr1_y5.js → pdf-effect-queue-BBTTQaO-.js} +1 -1
  88. package/src/ui/dist/assets/{popover-CWJbJuYY.js → popover-BWlolyxo.js} +1 -1
  89. package/src/ui/dist/assets/{project-sync-CRJiucYO.js → project-sync-BM5PkFH4.js} +1 -1
  90. package/src/ui/dist/assets/{select-CoHB7pvH.js → select-D4dAtrA8.js} +2 -2
  91. package/src/ui/dist/assets/{sigma-D5aJWR8J.js → sigma-CKbE5jJT.js} +1 -1
  92. package/src/ui/dist/assets/{square-check-big-DUK_mnkS.js → square-check-big-CZNGMgiB.js} +1 -1
  93. package/src/ui/dist/assets/{trash-ChU3SEE3.js → trash-DaB37xAz.js} +1 -1
  94. package/src/ui/dist/assets/{useCliAccess-BrJBV3tY.js → useCliAccess-C2OmAcWe.js} +1 -1
  95. package/src/ui/dist/assets/{useFileDiffOverlay-C2OQaVWc.js → useFileDiffOverlay-Dowd1Ij4.js} +1 -1
  96. package/src/ui/dist/assets/{wrap-text-C7Qqh-om.js → wrap-text-BGjAhAUq.js} +1 -1
  97. package/src/ui/dist/assets/{zoom-out-rtX0FKya.js → zoom-out-dMZQMXzc.js} +1 -1
  98. package/src/ui/dist/index.html +1 -1
  99. package/uv.lock +1 -1
@@ -403,11 +403,11 @@ export const BashExecOperationMessage = ({ label, content, toolName, toolCallId,
403
403
  : [];
404
404
  return (React.createElement(Box, { flexDirection: "row", width: width },
405
405
  React.createElement(Box, { width: prefixWidth },
406
- React.createElement(Text, { color: "white" }, BULLET_PREFIX)),
406
+ React.createElement(Text, { color: theme.text.response }, BULLET_PREFIX)),
407
407
  React.createElement(Box, { flexGrow: 1, flexDirection: "column", width: contentWidth },
408
408
  React.createElement(Text, { color: theme.text.link, bold: true }, header),
409
- React.createElement(Text, { color: "white" }, visibleCommand),
409
+ React.createElement(Text, { color: theme.text.response }, visibleCommand),
410
410
  metaParts.length > 0 ? (React.createElement(Box, { marginTop: 1 },
411
411
  React.createElement(Text, { color: theme.text.secondary }, metaParts.join(' · ')))) : null,
412
- renderedLogLines.length > 0 ? (React.createElement(Box, { marginTop: 1, flexDirection: "column" }, renderedLogLines.map((line, index) => (React.createElement(Text, { key: `${toolCallId || bashId || 'bash'}:${index}`, color: "white" }, line))))) : null)));
412
+ renderedLogLines.length > 0 ? (React.createElement(Box, { marginTop: 1, flexDirection: "column" }, renderedLogLines.map((line, index) => (React.createElement(Text, { key: `${toolCallId || bashId || 'bash'}:${index}`, color: theme.text.response }, line))))) : null)));
413
413
  };
@@ -19,7 +19,7 @@ const buildHeading = (content) => {
19
19
  export const OperationMessage = ({ label, content, toolName, toolCallId, status, subject, args, output, width = 80, }) => {
20
20
  const prefix = '• ';
21
21
  const prefixWidth = prefix.length;
22
- const contentColor = 'white';
22
+ const contentColor = theme.text.response;
23
23
  const keywordColor = theme.text.link;
24
24
  const contentWidth = Math.max(1, width - prefixWidth);
25
25
  const heading = buildHeading(content);
@@ -3,6 +3,8 @@ import { render } from 'ink';
3
3
  import { AppContainer } from './app/AppContainer.js';
4
4
  import { isAlternateBufferEnabled, isIncrementalRenderingEnabled } from './utils/terminal.js';
5
5
  const CLEAR_TO_END = '\x1b[0K';
6
+ const BRACKETED_PASTE_ENABLE = '\x1b[?2004h';
7
+ const BRACKETED_PASTE_DISABLE = '\x1b[?2004l';
6
8
  const withLineClearing = (stdout) => {
7
9
  const transform = (chunk) => {
8
10
  const text = Buffer.isBuffer(chunk) ? chunk.toString('utf8') : String(chunk);
@@ -31,7 +33,28 @@ const baseUrl = parseArg('--base-url') ?? 'http://0.0.0.0:20999';
31
33
  const questId = parseArg('--quest-id');
32
34
  const useAlternateBuffer = isAlternateBufferEnabled();
33
35
  const useIncrementalRendering = isIncrementalRenderingEnabled();
34
- render(React.createElement(AppContainer, { baseUrl: baseUrl, initialQuestId: questId }), {
36
+ const setBracketedPasteMode = (enabled) => {
37
+ if (!process.stdout.isTTY) {
38
+ return;
39
+ }
40
+ try {
41
+ process.stdout.write(enabled ? BRACKETED_PASTE_ENABLE : BRACKETED_PASTE_DISABLE);
42
+ }
43
+ catch {
44
+ // Ignore terminal write failures during startup or shutdown.
45
+ }
46
+ };
47
+ let bracketedPasteClosed = false;
48
+ const closeBracketedPasteMode = () => {
49
+ if (bracketedPasteClosed) {
50
+ return;
51
+ }
52
+ bracketedPasteClosed = true;
53
+ setBracketedPasteMode(false);
54
+ };
55
+ setBracketedPasteMode(true);
56
+ process.once('exit', closeBracketedPasteMode);
57
+ const instance = render(React.createElement(AppContainer, { baseUrl: baseUrl, initialQuestId: questId }), {
35
58
  stdout: withLineClearing(process.stdout),
36
59
  stderr: process.stderr,
37
60
  stdin: process.stdin,
@@ -40,3 +63,7 @@ render(React.createElement(AppContainer, { baseUrl: baseUrl, initialQuestId: que
40
63
  alternateBuffer: useAlternateBuffer,
41
64
  incrementalRendering: useIncrementalRendering,
42
65
  });
66
+ void instance.waitUntilExit().finally(() => {
67
+ closeBracketedPasteMode();
68
+ process.off('exit', closeBracketedPasteMode);
69
+ });
@@ -13,7 +13,7 @@ const estimateWrappedRows = (value, width) => {
13
13
  return count + Math.max(1, Math.ceil(measured / safeWidth));
14
14
  }, 0);
15
15
  };
16
- export const DefaultAppLayout = ({ baseUrl, quests, activeQuestId, browseQuestId, configMode, configItems, configIndex, configEditor, questPanelMode, questPanelQuests, questPanelIndex, snapshot, session, connectors, history, pendingHistoryItems, input, connectionState, statusLine, suggestions = [], onChange, onSubmit, onCancel, onQuestPanelMove, onQuestPanelConfirm, onQuestPanelCancel, }) => {
16
+ export const DefaultAppLayout = ({ baseUrl, quests, activeQuestId, browseQuestId, configMode, configPanel, questPanelMode, questPanelQuests, questPanelIndex, snapshot, session, connectors, history, pendingHistoryItems, input, connectionState, statusLine, suggestions = [], onChange, onSubmit, onCancel, onQuestPanelMove, onQuestPanelConfirm, onQuestPanelCancel, }) => {
17
17
  const { columns, rows } = useTerminalSize();
18
18
  const composerRef = useRef(null);
19
19
  const [composerHeight, setComposerHeight] = useState(0);
@@ -49,7 +49,7 @@ export const DefaultAppLayout = ({ baseUrl, quests, activeQuestId, browseQuestId
49
49
  : undefined;
50
50
  return (React.createElement(Box, { flexDirection: "column", width: columns, height: useAlternateBuffer ? safeRows : undefined },
51
51
  React.createElement(Box, { flexGrow: useAlternateBuffer ? 1 : 0, height: mainHeight, overflow: useAlternateBuffer ? 'hidden' : undefined },
52
- React.createElement(MainContent, { quests: quests, browseQuestId: browseQuestId, configMode: configMode, configItems: configItems, configIndex: configIndex, configEditor: configEditor, questPanelMode: questPanelMode, questPanelQuests: questPanelQuests, questPanelIndex: questPanelIndex, snapshot: snapshot, connectors: connectors, session: session, history: history, pendingHistoryItems: pendingHistoryItems, baseUrl: baseUrl, connectionState: connectionState, availableHeight: mainHeight, onQuestPanelMove: onQuestPanelMove, onQuestPanelConfirm: onQuestPanelConfirm, onQuestPanelCancel: onQuestPanelCancel })),
52
+ React.createElement(MainContent, { quests: quests, browseQuestId: browseQuestId, configMode: configMode, configPanel: configPanel, questPanelMode: questPanelMode, questPanelQuests: questPanelQuests, questPanelIndex: questPanelIndex, snapshot: snapshot, connectors: connectors, session: session, history: history, pendingHistoryItems: pendingHistoryItems, baseUrl: baseUrl, connectionState: connectionState, availableHeight: mainHeight, onQuestPanelMove: onQuestPanelMove, onQuestPanelConfirm: onQuestPanelConfirm, onQuestPanelCancel: onQuestPanelCancel })),
53
53
  gap > 0 ? React.createElement(Box, { height: gap, flexShrink: 0 }) : null,
54
54
  React.createElement(Box, { ref: composerRef, flexShrink: 0 },
55
55
  React.createElement(Composer, { input: input, statusLine: statusLine, suggestions: suggestions, configMode: configMode, selectionMode: questPanelMode, mode: activeQuestId ? 'quest' : 'home', activeQuestId: activeQuestId, connectionState: connectionState, isRunning: String(snapshot?.status || '') === 'running', questRoot: session?.snapshot?.quest_root || snapshot?.quest_root, modelLabel: typeof session?.snapshot?.runner === 'string'
@@ -57,7 +57,7 @@ export const DefaultAppLayout = ({ baseUrl, quests, activeQuestId, browseQuestId
57
57
  : undefined, sessionId: session?.acp_session?.session_id, onChange: onChange, onSubmit: onSubmit, onCancel: onCancel, placeholder: configMode === 'edit'
58
58
  ? 'Edit the config content, then press Enter to save'
59
59
  : configMode === 'browse'
60
- ? 'Use arrows to choose a config file, then press Enter'
60
+ ? 'Use arrows to choose a config item, then press Enter'
61
61
  : questPanelMode
62
62
  ? 'Use arrows to choose a quest, then press Enter'
63
63
  : activeQuestId
@@ -44,6 +44,15 @@ export const client = {
44
44
  body: JSON.stringify({ source: 'tui-ink' }),
45
45
  }),
46
46
  connectors: (baseUrl) => api(baseUrl, '/api/connectors'),
47
+ connectorsAvailability: (baseUrl) => api(baseUrl, '/api/connectors/availability'),
48
+ startWeixinQrLogin: (baseUrl, force = false) => api(baseUrl, '/api/connectors/weixin/login/qr/start', {
49
+ method: 'POST',
50
+ body: JSON.stringify({ force }),
51
+ }),
52
+ waitWeixinQrLogin: (baseUrl, sessionKey, timeoutMs = 1500) => api(baseUrl, '/api/connectors/weixin/login/qr/wait', {
53
+ method: 'POST',
54
+ body: JSON.stringify({ session_key: sessionKey, timeout_ms: timeoutMs }),
55
+ }),
47
56
  session: (baseUrl, questId) => api(baseUrl, `/api/quests/${questId}/session`),
48
57
  openDocument: (baseUrl, questId, documentId) => api(baseUrl, `/api/quests/${questId}/documents/open`, {
49
58
  method: 'POST',
@@ -188,4 +197,12 @@ export const client = {
188
197
  method: 'PUT',
189
198
  body: JSON.stringify({ content, revision }),
190
199
  }),
200
+ saveStructuredConfig: (baseUrl, name, structured, revision) => api(baseUrl, `/api/config/${name}`, {
201
+ method: 'PUT',
202
+ body: JSON.stringify({ structured, revision }),
203
+ }),
204
+ updateQuestBindings: (baseUrl, questId, payload) => api(baseUrl, `/api/quests/${questId}/bindings`, {
205
+ method: Array.isArray(payload.bindings) ? 'PUT' : 'POST',
206
+ body: JSON.stringify(payload),
207
+ }),
191
208
  };
@@ -0,0 +1,90 @@
1
+ export const CONNECTOR_ORDER = [
2
+ 'qq',
3
+ 'weixin',
4
+ 'lingzhu',
5
+ 'telegram',
6
+ 'discord',
7
+ 'slack',
8
+ 'feishu',
9
+ 'whatsapp',
10
+ ];
11
+ const CONNECTOR_LABELS = {
12
+ qq: 'QQ',
13
+ weixin: 'Weixin',
14
+ lingzhu: 'Lingzhu',
15
+ telegram: 'Telegram',
16
+ discord: 'Discord',
17
+ slack: 'Slack',
18
+ feishu: 'Feishu',
19
+ whatsapp: 'WhatsApp',
20
+ };
21
+ const CONNECTOR_SUBTITLES = {
22
+ qq: 'Save App ID and App Secret, then wait for the first private QQ message to discover the target.',
23
+ weixin: 'Start QR login, scan with WeChat, and let DeepScientist save the connector automatically.',
24
+ lingzhu: 'Generate the Rokid binding values here, then copy them into the Lingzhu platform and save once.',
25
+ telegram: 'Guided setup not added in TUI yet. Use raw connectors config if needed.',
26
+ discord: 'Guided setup not added in TUI yet. Use raw connectors config if needed.',
27
+ slack: 'Guided setup not added in TUI yet. Use raw connectors config if needed.',
28
+ feishu: 'Guided setup not added in TUI yet. Use raw connectors config if needed.',
29
+ whatsapp: 'Guided setup not added in TUI yet. Use raw connectors config if needed.',
30
+ };
31
+ const GUIDED_CONNECTORS = new Set(['qq', 'weixin', 'lingzhu']);
32
+ const LINGZHU_EXAMPLE_AUTH_AKS = new Set(['abcd1234-abcd-abcd-abcd-abcdefghijkl']);
33
+ export function connectorLabel(name) {
34
+ const normalized = String(name || '').trim().toLowerCase();
35
+ return CONNECTOR_LABELS[normalized] || (normalized ? normalized[0].toUpperCase() + normalized.slice(1) : 'Connector');
36
+ }
37
+ export function connectorSubtitle(name) {
38
+ const normalized = String(name || '').trim().toLowerCase();
39
+ return CONNECTOR_SUBTITLES[normalized] || 'Connector settings.';
40
+ }
41
+ export function supportsGuidedConnector(name) {
42
+ const normalized = String(name || '').trim().toLowerCase();
43
+ return GUIDED_CONNECTORS.has(normalized);
44
+ }
45
+ export function maskSecret(value) {
46
+ const text = String(value || '').trim();
47
+ if (!text) {
48
+ return '';
49
+ }
50
+ if (text.startsWith('$')) {
51
+ return text;
52
+ }
53
+ if (text.length <= 8) {
54
+ return '*'.repeat(text.length);
55
+ }
56
+ return `${text.slice(0, 4)}${'*'.repeat(Math.max(0, text.length - 8))}${text.slice(-4)}`;
57
+ }
58
+ export function createLingzhuAk() {
59
+ const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
60
+ const segments = [8, 4, 4, 4, 12];
61
+ const totalLength = segments.reduce((sum, size) => sum + size, 0);
62
+ const bytes = typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function'
63
+ ? crypto.getRandomValues(new Uint8Array(totalLength))
64
+ : Uint8Array.from({ length: totalLength }, () => Math.floor(Math.random() * 256));
65
+ let index = 0;
66
+ return segments
67
+ .map((size) => {
68
+ let segment = '';
69
+ for (let offset = 0; offset < size; offset += 1) {
70
+ segment += chars[bytes[index] % chars.length];
71
+ index += 1;
72
+ }
73
+ return segment;
74
+ })
75
+ .join('-');
76
+ }
77
+ export function resolveLingzhuAuthAk(value) {
78
+ const normalized = String(value || '').trim();
79
+ return LINGZHU_EXAMPLE_AUTH_AKS.has(normalized) ? '' : normalized;
80
+ }
81
+ export function looksLikeWeixinQrImageUrl(value) {
82
+ const text = String(value || '').trim();
83
+ if (!text) {
84
+ return false;
85
+ }
86
+ if (text.startsWith('data:image/') || text.startsWith('blob:')) {
87
+ return true;
88
+ }
89
+ return /^https?:\/\/.+\.(png|jpg|jpeg|gif|webp|svg)(?:$|[?#])/i.test(text);
90
+ }
@@ -0,0 +1,261 @@
1
+ const CONNECTOR_PROFILE_CHAT_ID_SEPARATOR = '::';
2
+ function defaultConversationLabel(chatType, chatId) {
3
+ return `${String(chatType || '').trim()} · ${String(chatId || '').trim()}`.trim();
4
+ }
5
+ function stripRepeatedProfilePrefix(profileLabel, label) {
6
+ const normalizedProfileLabel = String(profileLabel || '').trim();
7
+ let normalizedLabel = String(label || '').trim();
8
+ if (!normalizedProfileLabel || !normalizedLabel) {
9
+ return normalizedLabel;
10
+ }
11
+ const prefixed = `${normalizedProfileLabel} · `;
12
+ while (normalizedLabel === normalizedProfileLabel || normalizedLabel.startsWith(prefixed)) {
13
+ if (normalizedLabel === normalizedProfileLabel) {
14
+ return normalizedProfileLabel;
15
+ }
16
+ normalizedLabel = normalizedLabel.slice(prefixed.length).trim();
17
+ }
18
+ return normalizedLabel;
19
+ }
20
+ function baseTargetLabel(target) {
21
+ if (!target)
22
+ return '';
23
+ const fallback = defaultConversationLabel(target.chat_type, target.chat_id) || String(target.conversation_id || '').trim();
24
+ return stripRepeatedProfilePrefix(target.profile_label, target.label) || fallback;
25
+ }
26
+ function baseRecentConversationLabel(item) {
27
+ if (!item)
28
+ return '';
29
+ return stripRepeatedProfilePrefix(item.profile_label, item.label) || defaultConversationLabel(item.chat_type, item.chat_id);
30
+ }
31
+ function withProfileLabel(profileLabel, label) {
32
+ const normalizedProfileLabel = String(profileLabel || '').trim();
33
+ const normalizedLabel = stripRepeatedProfilePrefix(profileLabel, label);
34
+ if (!normalizedProfileLabel)
35
+ return normalizedLabel;
36
+ if (!normalizedLabel)
37
+ return normalizedProfileLabel;
38
+ if (normalizedLabel === normalizedProfileLabel)
39
+ return normalizedProfileLabel;
40
+ return `${normalizedProfileLabel} · ${normalizedLabel}`;
41
+ }
42
+ export function parseConversationId(value) {
43
+ const raw = String(value || '').trim();
44
+ const firstSeparator = raw.indexOf(':');
45
+ if (firstSeparator < 0)
46
+ return null;
47
+ const secondSeparator = raw.indexOf(':', firstSeparator + 1);
48
+ if (secondSeparator < 0)
49
+ return null;
50
+ const connector = raw.slice(0, firstSeparator);
51
+ const chatType = raw.slice(firstSeparator + 1, secondSeparator);
52
+ const chatId = raw.slice(secondSeparator + 1);
53
+ if (!connector || !chatType || !chatId)
54
+ return null;
55
+ const separatorIndex = chatId.indexOf(CONNECTOR_PROFILE_CHAT_ID_SEPARATOR);
56
+ const profileId = separatorIndex >= 0 ? chatId.slice(0, separatorIndex).trim() : '';
57
+ const resolvedChatId = separatorIndex >= 0 ? chatId.slice(separatorIndex + CONNECTOR_PROFILE_CHAT_ID_SEPARATOR.length).trim() : chatId;
58
+ return {
59
+ conversation_id: raw,
60
+ connector: connector.toLowerCase(),
61
+ chat_type: chatType.toLowerCase(),
62
+ chat_id: resolvedChatId,
63
+ chat_id_raw: chatId,
64
+ profile_id: profileId,
65
+ };
66
+ }
67
+ export function conversationIdentityKey(value) {
68
+ const parsed = parseConversationId(value);
69
+ if (!parsed)
70
+ return String(value || '').trim().toLowerCase();
71
+ return [parsed.connector, parsed.profile_id || '', parsed.chat_type, parsed.chat_id.toLowerCase()].filter(Boolean).join(':');
72
+ }
73
+ export function connectorTargetLabel(target) {
74
+ if (!target)
75
+ return '';
76
+ return withProfileLabel(target.profile_label, baseTargetLabel(target));
77
+ }
78
+ function sortTargets(left, right) {
79
+ const leftDefault = left.is_default ? 0 : 1;
80
+ const rightDefault = right.is_default ? 0 : 1;
81
+ if (leftDefault !== rightDefault)
82
+ return leftDefault - rightDefault;
83
+ const leftDirect = String(left.chat_type || '') === 'direct' ? 0 : 1;
84
+ const rightDirect = String(right.chat_type || '') === 'direct' ? 0 : 1;
85
+ if (leftDirect !== rightDirect)
86
+ return leftDirect - rightDirect;
87
+ const updatedCompare = String(right.updated_at || '').localeCompare(String(left.updated_at || ''));
88
+ if (updatedCompare !== 0)
89
+ return updatedCompare;
90
+ return String(left.conversation_id || '').localeCompare(String(right.conversation_id || ''));
91
+ }
92
+ function targetFromConversationId(conversationId, patch = {}) {
93
+ const parsed = parseConversationId(conversationId);
94
+ if (!parsed)
95
+ return null;
96
+ return {
97
+ ...parsed,
98
+ ...patch,
99
+ conversation_id: parsed.conversation_id,
100
+ connector: parsed.connector,
101
+ chat_type: parsed.chat_type,
102
+ chat_id: parsed.chat_id,
103
+ chat_id_raw: parsed.chat_id_raw,
104
+ profile_id: parsed.profile_id || null,
105
+ label: patch.label || `${parsed.chat_type} · ${parsed.chat_id}`,
106
+ };
107
+ }
108
+ function normalizeBindingTarget(binding) {
109
+ return targetFromConversationId(binding.conversation_id, {
110
+ source: 'quest_binding',
111
+ sources: ['quest_binding'],
112
+ profile_id: binding.profile_id || null,
113
+ profile_label: binding.profile_label || null,
114
+ bound_quest_id: binding.quest_id || null,
115
+ bound_quest_title: binding.quest_title || null,
116
+ is_bound: Boolean(binding.quest_id),
117
+ warning: binding.quest_id ? `Currently bound to ${binding.quest_id}` : null,
118
+ updated_at: binding.updated_at || null,
119
+ });
120
+ }
121
+ function normalizeRecentConversationTarget(item) {
122
+ return targetFromConversationId(item.conversation_id, {
123
+ source: item.source || 'recent_activity',
124
+ sources: [String(item.source || 'recent_activity')],
125
+ profile_id: item.profile_id || null,
126
+ profile_label: item.profile_label || null,
127
+ label: baseRecentConversationLabel(item),
128
+ updated_at: item.updated_at || null,
129
+ quest_id: item.quest_id || null,
130
+ });
131
+ }
132
+ function normalizeKnownTarget(target) {
133
+ const source = String(target.source || '').trim() || 'known_target';
134
+ const sources = Array.from(new Set([...(target.sources || []), source].map((item) => String(item || '').trim()).filter(Boolean)));
135
+ const boundQuestId = String(target.bound_quest_id || '').trim() || null;
136
+ return {
137
+ ...target,
138
+ source,
139
+ sources,
140
+ is_bound: Boolean(boundQuestId),
141
+ warning: boundQuestId ? target.warning || null : null,
142
+ };
143
+ }
144
+ function mergeTargetEntry(merged, target, options) {
145
+ if (!target?.conversation_id)
146
+ return;
147
+ const { defaultConversationId } = options;
148
+ const normalizedTarget = {
149
+ ...target,
150
+ label: baseTargetLabel(target),
151
+ selectable: target.selectable ?? true,
152
+ is_default: target.is_default || conversationIdentityKey(target.conversation_id) === conversationIdentityKey(defaultConversationId),
153
+ };
154
+ const key = conversationIdentityKey(normalizedTarget.conversation_id);
155
+ const existing = merged.get(key);
156
+ const normalizedBoundQuestId = String(normalizedTarget.bound_quest_id || '').trim() || null;
157
+ const normalizedBoundQuestTitle = normalizedBoundQuestId && String(normalizedTarget.bound_quest_title || '').trim()
158
+ ? String(normalizedTarget.bound_quest_title || '').trim()
159
+ : null;
160
+ const normalizedWarning = normalizedBoundQuestId && String(normalizedTarget.warning || '').trim() ? String(normalizedTarget.warning || '').trim() : null;
161
+ if (!existing) {
162
+ merged.set(key, {
163
+ ...normalizedTarget,
164
+ bound_quest_id: normalizedBoundQuestId,
165
+ bound_quest_title: normalizedBoundQuestTitle,
166
+ is_bound: Boolean(normalizedBoundQuestId),
167
+ warning: normalizedWarning,
168
+ });
169
+ return;
170
+ }
171
+ const nextSources = Array.from(new Set([...(existing.sources || []), ...(normalizedTarget.sources || []), existing.source, normalizedTarget.source].filter((item) => Boolean(item))));
172
+ const resolvedBoundQuestId = String(normalizedTarget.bound_quest_id || existing.bound_quest_id || '').trim() || null;
173
+ const resolvedBoundQuestTitle = resolvedBoundQuestId && String(normalizedTarget.bound_quest_title || existing.bound_quest_title || '').trim()
174
+ ? String(normalizedTarget.bound_quest_title || existing.bound_quest_title || '').trim()
175
+ : null;
176
+ const resolvedWarning = resolvedBoundQuestId && String(normalizedTarget.warning || existing.warning || '').trim()
177
+ ? String(normalizedTarget.warning || existing.warning || '').trim()
178
+ : null;
179
+ merged.set(key, {
180
+ ...existing,
181
+ ...normalizedTarget,
182
+ label: baseTargetLabel(existing) === defaultConversationLabel(existing.chat_type, existing.chat_id) && baseTargetLabel(normalizedTarget)
183
+ ? baseTargetLabel(normalizedTarget)
184
+ : baseTargetLabel(existing) || baseTargetLabel(normalizedTarget),
185
+ sources: nextSources.length ? nextSources : undefined,
186
+ is_default: Boolean(existing.is_default || normalizedTarget.is_default),
187
+ selectable: existing.selectable ?? normalizedTarget.selectable ?? true,
188
+ bound_quest_id: resolvedBoundQuestId,
189
+ bound_quest_title: resolvedBoundQuestTitle,
190
+ is_bound: Boolean(resolvedBoundQuestId),
191
+ warning: resolvedWarning,
192
+ updated_at: String(normalizedTarget.updated_at || '') >= String(existing.updated_at || '')
193
+ ? normalizedTarget.updated_at || existing.updated_at
194
+ : existing.updated_at || normalizedTarget.updated_at,
195
+ });
196
+ }
197
+ export function normalizeConnectorTargets(snapshot) {
198
+ const merged = new Map();
199
+ const defaultConversationId = String(snapshot.default_target?.conversation_id || '').trim() ||
200
+ (snapshot.name === 'qq' && String(snapshot.main_chat_id || '').trim() ? `qq:direct:${String(snapshot.main_chat_id || '').trim()}` : '') ||
201
+ '';
202
+ for (const target of snapshot.known_targets || []) {
203
+ mergeTargetEntry(merged, normalizeKnownTarget(target), { defaultConversationId });
204
+ }
205
+ for (const target of snapshot.discovered_targets || []) {
206
+ mergeTargetEntry(merged, target, { defaultConversationId });
207
+ }
208
+ mergeTargetEntry(merged, snapshot.default_target || null, { defaultConversationId });
209
+ for (const binding of snapshot.bindings || []) {
210
+ mergeTargetEntry(merged, normalizeBindingTarget(binding), { defaultConversationId });
211
+ }
212
+ for (const item of snapshot.recent_conversations || []) {
213
+ mergeTargetEntry(merged, normalizeRecentConversationTarget(item), { defaultConversationId });
214
+ }
215
+ if (snapshot.last_conversation_id) {
216
+ mergeTargetEntry(merged, targetFromConversationId(snapshot.last_conversation_id, {
217
+ source: 'last_conversation',
218
+ sources: ['last_conversation'],
219
+ }), { defaultConversationId });
220
+ }
221
+ if (snapshot.name === 'qq' && snapshot.main_chat_id) {
222
+ mergeTargetEntry(merged, targetFromConversationId(`qq:direct:${snapshot.main_chat_id}`, {
223
+ source: 'saved_main_chat',
224
+ sources: ['saved_main_chat'],
225
+ is_default: true,
226
+ }), { defaultConversationId });
227
+ }
228
+ return Array.from(merged.values()).sort(sortTargets);
229
+ }
230
+ export function qqProfileDisplayLabel(profile, snapshot) {
231
+ const snapshotLabel = String(snapshot?.label || '').trim();
232
+ if (snapshotLabel) {
233
+ return snapshotLabel;
234
+ }
235
+ const botName = String(profile.bot_name || '').trim();
236
+ const appId = String(profile.app_id || '').trim();
237
+ if (botName && appId) {
238
+ return `${botName} · ${appId}`;
239
+ }
240
+ return botName || appId || String(profile.profile_id || '').trim() || 'QQ';
241
+ }
242
+ export function selectQqProfileTarget(targets, mainChatId) {
243
+ const normalizedMainChatId = String(mainChatId || '').trim();
244
+ return (targets.find((item) => String(item.bound_quest_id || '').trim()) ||
245
+ (normalizedMainChatId
246
+ ? targets.find((item) => String(item.chat_id || '').trim() === normalizedMainChatId)
247
+ : undefined) ||
248
+ targets[0] ||
249
+ null);
250
+ }
251
+ export function qqProfileStatus(profileSnapshot, targets, mainChatId) {
252
+ const hasBinding = Number(profileSnapshot?.binding_count || 0) > 0 ||
253
+ targets.some((item) => Boolean(String(item.bound_quest_id || '').trim()));
254
+ if (hasBinding) {
255
+ return 'bound';
256
+ }
257
+ const hasDetectedTarget = Boolean(String(mainChatId || profileSnapshot?.main_chat_id || '').trim()) ||
258
+ Boolean(String(profileSnapshot?.last_conversation_id || '').trim()) ||
259
+ targets.length > 0;
260
+ return hasDetectedTarget ? 'ready' : 'waiting';
261
+ }
@@ -0,0 +1,21 @@
1
+ export async function renderQrAscii(content) {
2
+ const normalized = String(content || '').trim();
3
+ if (!normalized) {
4
+ return '';
5
+ }
6
+ const qrModule = (await import('qrcode'));
7
+ try {
8
+ return await qrModule.toString(normalized, {
9
+ type: 'utf8',
10
+ errorCorrectionLevel: 'M',
11
+ margin: 0,
12
+ });
13
+ }
14
+ catch {
15
+ return qrModule.toString(normalized, {
16
+ type: 'utf8',
17
+ errorCorrectionLevel: 'M',
18
+ margin: 2,
19
+ });
20
+ }
21
+ }
@@ -1,33 +1,43 @@
1
1
  export const theme = {
2
2
  text: {
3
- primary: '#E6E6E6',
4
- secondary: '#6C7086',
5
- link: '#89B4FA',
6
- accent: '#CBA6F7',
7
- mention: '#4AA5C8',
8
- response: '#E6E6E6',
9
- user: '#FF8A5C',
3
+ primary: '#E8EEF9',
4
+ secondary: '#8B9AB4',
5
+ link: '#A7C4FF',
6
+ accent: '#7FA9FF',
7
+ mention: '#9DBBFF',
8
+ response: '#E8EEF9',
9
+ user: '#B9D1FF',
10
10
  },
11
11
  background: {
12
- primary: '#1E1E2E',
12
+ primary: '#0F172A',
13
13
  diff: {
14
- added: '#28350B',
15
- removed: '#430000',
14
+ added: '#12263C',
15
+ removed: '#1C2338',
16
16
  },
17
17
  },
18
18
  border: {
19
- default: '#6C7086',
20
- focused: '#89B4FA',
19
+ default: '#41516D',
20
+ focused: '#7FA9FF',
21
21
  },
22
22
  ui: {
23
- comment: '#6C7086',
24
- symbol: '#6C7086',
25
- dark: '#3A3A4C',
26
- gradient: ['#4796E4', '#847ACE', '#C3677F'],
23
+ comment: '#6D7F9B',
24
+ symbol: '#6D7F9B',
25
+ dark: '#22304B',
26
+ gradient: ['#6D90F5', '#8BAEFF', '#B6D1FF'],
27
+ brand: {
28
+ strong: '#6D90F5',
29
+ medium: '#8BAEFF',
30
+ soft: '#B6D1FF',
31
+ subtle: '#5B7097',
32
+ },
33
+ cursor: {
34
+ background: '#8BAEFF',
35
+ text: '#0F172A',
36
+ },
27
37
  },
28
38
  status: {
29
- error: '#F38BA8',
30
- success: '#A6E3A1',
31
- warning: '#F9E2AF',
39
+ error: '#6E85B7',
40
+ success: '#9FC5FF',
41
+ warning: '#83A8F2',
32
42
  },
33
43
  };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepscientist-tui",
3
- "version": "1.5.12",
3
+ "version": "1.5.14",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -12,6 +12,7 @@
12
12
  "dependencies": {
13
13
  "ink": "npm:@jrichman/ink@6.4.6",
14
14
  "ink-gradient": "^3.0.0",
15
+ "qrcode": "^1.5.4",
15
16
  "react": "^19.2.0",
16
17
  "react-dom": "^19.2.0",
17
18
  "string-width": "^8.1.0"
@@ -1,14 +1,14 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/index-hOUOWbW2.js","assets/index-CLQauncb.js","assets/index-BQG-1s2o.css","assets/useCliAccess-BrJBV3tY.js","assets/VNCViewer-D7-dIYon.js","assets/file-content-B57zsL9y.js","assets/select-CoHB7pvH.js","assets/index-Dxa2eYMY.js","assets/file-jump-queue-r5XKgJEV.js","assets/pdf-effect-queue-DlEr1_y5.js","assets/file-diff-panel-DVoheLFq.js","assets/bot-C_G4WtNI.js","assets/NotebookEditor-BMXKrDRk.js","assets/NotebookEditor-C3VQ7ylN.css","assets/trash-ChU3SEE3.js"])))=>i.map(i=>d[i]);
2
- import { w as createLucideIcon, r as reactExports, ce as useIsomorphicLayoutEffect, cg as frame_1, d8 as LayoutGroupContext, d9 as nodeGroup_1, j as jsxRuntimeExports, cj as useConstant, t as apiClient, bE as isQuestRuntimeSurface, da as shouldUseQuestProject, bF as getApiBaseUrl, db as deriveMcpIdentity, dc as supportsProductApis, cV as axios, dd as getCachedValue, de as setCachedValue, df as recordRequestEvent, dg as redactSensitive, dh as sanitizeUrl, di as refreshAccessToken, aV as useChatSessionStore, cF as getMyToken, bG as redirectToLanding, Q as create$1, aA as useLabCopilotStore, bH as useCliStore, dj as EXPLORER_REFRESH_EVENT, n as useTabsStore, cX as buildCliFileId, dk as getCliFileName, cY as toCliResourcePath, aM as getPluginIdFromExtension, v as BUILTIN_PLUGINS, b as cn, dl as GripVertical, f as useFileTreeStore, W as toFilesResourcePath, aL as getPluginIdFromMimeType, T as TriangleAlert, dm as resolveMcpIdentity, dn as getToolArgsRecord, dp as getToolResultRecord, dq as getToolResultValue, dr as asString$2, ds as asRecord$4, dt as asStringArray, du as extractPathEntries, dv as BookOpenText, dw as Clock3, dx as truncateText, dy as ArrowUpRight, l as Search, dz as Database, dA as ArrowRightLeft, N as Sparkles, k as FileText, by as GitBranch, dB as asBoolean, dC as asNumber, dD as BASH_CARRIAGE_RETURN_PREFIX, aN as useQuery, br as CircleHelp, dE as Activity, bt as Clock, dF as truncateText$1, dG as listLabPendingQuestions, dH as listLabQuestionHistory, af as BookOpen, dI as ExternalLink, u as useI18n, dJ as GraduationCap, dK as normalizeWebSearchPayload, dL as WebSearchQueryPills, dM as WebSearchResults, P as EnhancedTerminal, h as dynamic, _ as __vitePreload, dN as BashToolView, ac as Terminal, o as useToast, dO as getMimeTypeFromExtension, dP as getFileTextPreview, c2 as createFileObjectUrl, c as copyToClipboard, cp as ChevronLeft, cs as Folder, m as ChevronDown, X as X$1, L as LoaderCircle, aJ as FileIcon, dQ as formatFileSize, E as Eye, e as Copy, ba as Dialog, bb as DialogContent, co as ChevronRight, dR as ConfirmModal, dS as RotatingText, d as Check, aS as useReducedMotion, dT as useTokenStream, dU as McpBashExecView, dV as PngIcon, dW as Brain, dX as BRAND_LOGO_SMALL_SRC, dY as BRAND_LOGO_SMALL_SRC_INVERTED, dZ as CircleX, b0 as motion, bd as DialogTitle, ct as DialogDescription, bT as DropdownMenu, bU as DropdownMenuTrigger, b8 as Ellipsis, bV as DropdownMenuContent, bX as DropdownMenuItem, cB as DropdownMenuSeparator, cq as GlareHover, cA as SpotlightCard, d4 as Noise, b9 as Plus, ai as Info, a2 as Play, d_ as getWorkspaceContentTone, a$ as AnimatePresence, ab as useOpenFile, a as useWorkspaceSurfaceStore, z as useAuthStore, d$ as useSearchParams, e0 as useAgentRegistryStore, e1 as PanelLeft, e2 as parseCliFileId, c0 as getFile, bL as getProject, cI as refreshCliServerStatus, e3 as COPILOT_FILES_ENABLED, a0 as listLatexBuilds, a6 as getLatexBuildLogText, $ as compileLatex, e4 as ThinkingIndicator, e5 as assetUrl, e6 as VariableSizeList, bs as OrbitLogoStatus, aR as reactDomExports, e7 as ChatScrollProvider, bc as DialogHeader, be as DialogFooter } from './index-CLQauncb.js';
3
- import { u as useFileContentStore } from './file-content-B57zsL9y.js';
4
- import { n as normalizePath$1, j as joinPath, s as splitPath, e as Server, L as Layers, S as Select, a as SelectTrigger, c as SelectContent, d as SelectItem } from './select-CoHB7pvH.js';
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/index-RDlNXXx1.js","assets/index-Nt9hS4ck.js","assets/index-BQG-1s2o.css","assets/useCliAccess-C2OmAcWe.js","assets/VNCViewer-BgbuvWhR.js","assets/file-content-D1PxfOrp.js","assets/select-D4dAtrA8.js","assets/index-DVsMKK_y.js","assets/file-jump-queue-r5XKgJEV.js","assets/pdf-effect-queue-BBTTQaO-.js","assets/file-diff-panel-DG1oT_Hj.js","assets/bot-v_RASACv.js","assets/NotebookEditor-SoJ8X-MO.js","assets/NotebookEditor-C3VQ7ylN.css","assets/trash-DaB37xAz.js"])))=>i.map(i=>d[i]);
2
+ import { w as createLucideIcon, r as reactExports, ce as useIsomorphicLayoutEffect, cg as frame_1, d8 as LayoutGroupContext, d9 as nodeGroup_1, j as jsxRuntimeExports, cj as useConstant, t as apiClient, bE as isQuestRuntimeSurface, da as shouldUseQuestProject, bF as getApiBaseUrl, db as deriveMcpIdentity, dc as supportsProductApis, cV as axios, dd as getCachedValue, de as setCachedValue, df as recordRequestEvent, dg as redactSensitive, dh as sanitizeUrl, di as refreshAccessToken, aV as useChatSessionStore, cF as getMyToken, bG as redirectToLanding, Q as create$1, aA as useLabCopilotStore, bH as useCliStore, dj as EXPLORER_REFRESH_EVENT, n as useTabsStore, cX as buildCliFileId, dk as getCliFileName, cY as toCliResourcePath, aM as getPluginIdFromExtension, v as BUILTIN_PLUGINS, b as cn, dl as GripVertical, f as useFileTreeStore, W as toFilesResourcePath, aL as getPluginIdFromMimeType, T as TriangleAlert, dm as resolveMcpIdentity, dn as getToolArgsRecord, dp as getToolResultRecord, dq as getToolResultValue, dr as asString$2, ds as asRecord$4, dt as asStringArray, du as extractPathEntries, dv as BookOpenText, dw as Clock3, dx as truncateText, dy as ArrowUpRight, l as Search, dz as Database, dA as ArrowRightLeft, N as Sparkles, k as FileText, by as GitBranch, dB as asBoolean, dC as asNumber, dD as BASH_CARRIAGE_RETURN_PREFIX, aN as useQuery, br as CircleHelp, dE as Activity, bt as Clock, dF as truncateText$1, dG as listLabPendingQuestions, dH as listLabQuestionHistory, af as BookOpen, dI as ExternalLink, u as useI18n, dJ as GraduationCap, dK as normalizeWebSearchPayload, dL as WebSearchQueryPills, dM as WebSearchResults, P as EnhancedTerminal, h as dynamic, _ as __vitePreload, dN as BashToolView, ac as Terminal, o as useToast, dO as getMimeTypeFromExtension, dP as getFileTextPreview, c2 as createFileObjectUrl, c as copyToClipboard, cp as ChevronLeft, cs as Folder, m as ChevronDown, X as X$1, L as LoaderCircle, aJ as FileIcon, dQ as formatFileSize, E as Eye, e as Copy, ba as Dialog, bb as DialogContent, co as ChevronRight, dR as ConfirmModal, dS as RotatingText, d as Check, aS as useReducedMotion, dT as useTokenStream, dU as McpBashExecView, dV as PngIcon, dW as Brain, dX as BRAND_LOGO_SMALL_SRC, dY as BRAND_LOGO_SMALL_SRC_INVERTED, dZ as CircleX, b0 as motion, bd as DialogTitle, ct as DialogDescription, bT as DropdownMenu, bU as DropdownMenuTrigger, b8 as Ellipsis, bV as DropdownMenuContent, bX as DropdownMenuItem, cB as DropdownMenuSeparator, cq as GlareHover, cA as SpotlightCard, d4 as Noise, b9 as Plus, ai as Info, a2 as Play, d_ as getWorkspaceContentTone, a$ as AnimatePresence, ab as useOpenFile, a as useWorkspaceSurfaceStore, z as useAuthStore, d$ as useSearchParams, e0 as useAgentRegistryStore, e1 as PanelLeft, e2 as parseCliFileId, c0 as getFile, bL as getProject, cI as refreshCliServerStatus, e3 as COPILOT_FILES_ENABLED, a0 as listLatexBuilds, a6 as getLatexBuildLogText, $ as compileLatex, e4 as ThinkingIndicator, e5 as assetUrl, e6 as VariableSizeList, bs as OrbitLogoStatus, aR as reactDomExports, e7 as ChatScrollProvider, bc as DialogHeader, be as DialogFooter } from './index-Nt9hS4ck.js';
3
+ import { u as useFileContentStore } from './file-content-D1PxfOrp.js';
4
+ import { n as normalizePath$1, j as joinPath, s as splitPath, e as Server, L as Layers, S as Select, a as SelectTrigger, c as SelectContent, d as SelectItem } from './select-D4dAtrA8.js';
5
5
  import { q as queueFileJumpEffect } from './file-jump-queue-r5XKgJEV.js';
6
- import { q as queuePdfEffect, M as MessageSquare } from './pdf-effect-queue-DlEr1_y5.js';
7
- import { F as FileDiffPanel } from './file-diff-panel-DVoheLFq.js';
8
- import { B as Bot } from './bot-C_G4WtNI.js';
9
- import { C as ChevronUp } from './index-Dxa2eYMY.js';
10
- import { v as ve$2, d as defaultExtensions, g as getEditorMarkdown, s as setEditorMarkdown, U as U$2, I as I$1 } from './NotebookEditor-BMXKrDRk.js';
11
- import { T as Trash, A as ArrowDown } from './trash-ChU3SEE3.js';
6
+ import { q as queuePdfEffect, M as MessageSquare } from './pdf-effect-queue-BBTTQaO-.js';
7
+ import { F as FileDiffPanel } from './file-diff-panel-DG1oT_Hj.js';
8
+ import { B as Bot } from './bot-v_RASACv.js';
9
+ import { C as ChevronUp } from './index-DVsMKK_y.js';
10
+ import { v as ve$2, d as defaultExtensions, g as getEditorMarkdown, s as setEditorMarkdown, U as U$2, I as I$1 } from './NotebookEditor-SoJ8X-MO.js';
11
+ import { T as Trash, A as ArrowDown } from './trash-DaB37xAz.js';
12
12
 
13
13
  /**
14
14
  * @license lucide-react v0.511.0 - ISC
@@ -11538,7 +11538,7 @@ function SearchToolView({ toolContent, panelMode }) {
11538
11538
  }
11539
11539
 
11540
11540
  const CliToolTerminal = dynamic(
11541
- () => __vitePreload(() => import('./index-hOUOWbW2.js'),true?__vite__mapDeps([0,1,2,3]):void 0).then((mod) => mod.CliToolTerminal),
11541
+ () => __vitePreload(() => import('./index-RDlNXXx1.js'),true?__vite__mapDeps([0,1,2,3]):void 0).then((mod) => mod.CliToolTerminal),
11542
11542
  {
11543
11543
  loading: () => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex h-full items-center justify-center text-xs text-[var(--text-tertiary)]", children: "Loading terminal..." })
11544
11544
  }
@@ -18501,7 +18501,7 @@ function pickGreetingTemplate() {
18501
18501
  return GREETING_TEMPLATES[index];
18502
18502
  }
18503
18503
  const VNCViewer = dynamic(
18504
- () => __vitePreload(() => import('./VNCViewer-D7-dIYon.js'),true?__vite__mapDeps([4,1,2,5,6,7,8,9,10,11,12,13,14]):void 0).then((mod) => mod.VNCViewer),
18504
+ () => __vitePreload(() => import('./VNCViewer-BgbuvWhR.js'),true?__vite__mapDeps([4,1,2,5,6,7,8,9,10,11,12,13,14]):void 0).then((mod) => mod.VNCViewer),
18505
18505
  {
18506
18506
  loading: () => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex h-full w-full items-center justify-center text-sm text-[var(--text-tertiary)]", children: "Loading sandbox view..." })
18507
18507
  }
@@ -1,4 +1,4 @@
1
- import { r as reactExports, c as copyToClipboard, j as jsxRuntimeExports, k as FileText, l as Search, K as ChartColumn, N as Sparkles, d as Check, e as Copy, b as cn } from './index-CLQauncb.js';
1
+ import { r as reactExports, c as copyToClipboard, j as jsxRuntimeExports, k as FileText, l as Search, K as ChartColumn, N as Sparkles, d as Check, e as Copy, b as cn } from './index-Nt9hS4ck.js';
2
2
 
3
3
  const actions = [
4
4
  {