@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
@@ -44,7 +44,7 @@ export const Composer = ({ input, statusLine, suggestions = [], placeholder = 'T
44
44
  }))) : (React.createElement(Text, { color: theme.text.secondary }, configMode === 'edit'
45
45
  ? 'Config editor · Enter save · Ctrl+J newline · Esc cancel'
46
46
  : configMode === 'browse'
47
- ? 'Config browser · ↑/↓ select · Enter edit · Esc close'
47
+ ? 'Config workspace · ↑/↓ select · Enter open · Esc back'
48
48
  : selectionMode
49
49
  ? 'Quest browser · ↑/↓ select · Enter confirm · Esc cancel'
50
50
  : mode === 'home'
@@ -1,29 +1,53 @@
1
- import React, { useMemo } from 'react';
1
+ import React from 'react';
2
2
  import { Box, Text } from 'ink';
3
- import { shortenPath, tildeifyPath } from '../utils/paths.js';
4
3
  import { useTerminalSize } from '../hooks/useTerminalSize.js';
5
4
  import { theme } from '../semantic-colors.js';
6
- const sectionTitle = (scope, questId) => scope === 'global' ? 'Global Config' : `Current Quest${questId ? ` · ${questId}` : ''}`;
7
- export const ConfigScreen = ({ mode, items, selectedIndex, selectedQuestId, editor, availableHeight, }) => {
5
+ import { shortenPath, tildeifyPath } from '../utils/paths.js';
6
+ const renderListItems = (items, selectedIndex, columns) => {
7
+ return items.map((item, index) => {
8
+ const isSelected = index === selectedIndex;
9
+ const titleColor = item.disabled ? theme.text.secondary : isSelected ? theme.status.success : theme.text.primary;
10
+ return (React.createElement(Box, { key: item.id, flexDirection: "column", marginBottom: 1 },
11
+ React.createElement(Text, { color: titleColor },
12
+ isSelected ? '> ' : ' ',
13
+ index + 1,
14
+ ". ",
15
+ item.title),
16
+ item.description ? (React.createElement(Text, { color: theme.text.secondary }, shortenPath(item.description, Math.max(24, columns - 4)))) : null,
17
+ item.secondary ? React.createElement(Text, { color: theme.text.secondary }, shortenPath(item.secondary, Math.max(24, columns - 4))) : null));
18
+ });
19
+ };
20
+ const renderMultilineValue = (value) => value.split('\n').map((line, index) => (React.createElement(Text, { key: `multiline:${index}`, color: theme.text.primary }, line || ' ')));
21
+ const connectorStateLine = (snapshot) => {
22
+ if (!snapshot) {
23
+ return 'No runtime snapshot yet.';
24
+ }
25
+ const parts = [
26
+ snapshot.enabled === false ? 'disabled' : snapshot.enabled ? 'enabled' : 'unknown',
27
+ snapshot.connection_state || null,
28
+ snapshot.auth_state || null,
29
+ typeof snapshot.binding_count === 'number' ? `bindings ${snapshot.binding_count}` : null,
30
+ typeof snapshot.target_count === 'number' ? `targets ${snapshot.target_count}` : null,
31
+ ].filter(Boolean);
32
+ return parts.join(' · ') || 'No runtime snapshot yet.';
33
+ };
34
+ export const ConfigScreen = ({ panel, availableHeight }) => {
8
35
  const { rows, columns } = useTerminalSize();
9
36
  const safeRows = availableHeight ?? rows;
10
- const selected = items[Math.max(0, Math.min(selectedIndex, items.length - 1))] ?? null;
11
- const globalItems = useMemo(() => items.map((item, index) => ({ item, index })).filter(({ item }) => item.scope === 'global'), [items]);
12
- const questItems = useMemo(() => items.map((item, index) => ({ item, index })).filter(({ item }) => item.scope === 'quest'), [items]);
13
- if (mode === 'edit' && editor) {
14
- const previewLines = editor.content.split('\n');
37
+ if (panel.kind === 'document-editor') {
38
+ const previewLines = panel.content.split('\n');
15
39
  const maxPreviewLines = Math.max(8, (safeRows || 24) - 8);
16
40
  const visibleLines = previewLines.slice(0, maxPreviewLines);
17
41
  return (React.createElement(Box, { flexDirection: "column", width: columns },
18
42
  React.createElement(Text, { color: theme.text.primary }, "Config Editor"),
19
43
  React.createElement(Text, { color: theme.text.link },
20
- editor.item.scope === 'global' ? 'Global' : 'Quest',
44
+ panel.item.scope === 'global' ? 'Global' : 'Quest',
21
45
  " \u00B7 ",
22
- editor.item.title),
23
- React.createElement(Text, { color: theme.text.secondary }, tildeifyPath(editor.item.path)),
46
+ panel.item.title),
47
+ React.createElement(Text, { color: theme.text.secondary }, tildeifyPath(panel.item.path)),
24
48
  React.createElement(Text, { color: theme.text.secondary }, "Enter save \u00B7 Ctrl+J newline \u00B7 Esc cancel"),
25
49
  React.createElement(Box, { marginTop: 1, flexDirection: "column" },
26
- visibleLines.map((line, index) => (React.createElement(Box, { key: `${editor.item.id}-line-${index}`, flexDirection: "row" },
50
+ visibleLines.map((line, index) => (React.createElement(Box, { key: `${panel.item.id}-line-${index}`, flexDirection: "row" },
27
51
  React.createElement(Box, { minWidth: 5 },
28
52
  React.createElement(Text, { color: theme.text.secondary }, String(index + 1).padStart(4, ' '))),
29
53
  React.createElement(Text, { color: theme.text.primary }, line || ' ')))),
@@ -32,29 +56,159 @@ export const ConfigScreen = ({ mode, items, selectedIndex, selectedQuestId, edit
32
56
  previewLines.length - visibleLines.length,
33
57
  " more line(s) in buffer")) : null)));
34
58
  }
35
- const renderSection = (scope, entries) => (React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
36
- React.createElement(Text, { color: theme.text.link }, sectionTitle(scope, selectedQuestId)),
37
- entries.length === 0 ? (React.createElement(Text, { color: theme.text.secondary }, scope === 'global' ? 'No global config files.' : 'No quest config files for the current selection.')) : (entries.map(({ item, index }) => {
38
- const isSelected = index === selectedIndex;
39
- const displayPath = shortenPath(tildeifyPath(item.path), Math.max(28, columns - 26));
40
- return (React.createElement(Box, { key: item.id, flexDirection: "column", marginBottom: 1 },
41
- React.createElement(Text, { color: isSelected ? theme.status.success : theme.text.primary },
42
- isSelected ? '> ' : ' ',
43
- index + 1,
44
- ". ",
45
- item.title),
46
- React.createElement(Text, { color: theme.text.secondary }, displayPath)));
47
- }))));
59
+ if (panel.kind === 'connector-field-editor') {
60
+ const previewLines = panel.content.split('\n');
61
+ const maxPreviewLines = Math.max(8, (safeRows || 24) - 8);
62
+ const visibleLines = previewLines.slice(0, maxPreviewLines);
63
+ return (React.createElement(Box, { flexDirection: "column", width: columns },
64
+ React.createElement(Text, { color: theme.text.primary }, "Connector Field Editor"),
65
+ React.createElement(Text, { color: theme.text.link },
66
+ panel.connectorName,
67
+ " \u00B7 ",
68
+ panel.fieldLabel),
69
+ panel.description ? React.createElement(Text, { color: theme.text.secondary }, panel.description) : null,
70
+ React.createElement(Text, { color: theme.text.secondary }, "Enter apply \u00B7 Ctrl+J newline \u00B7 Esc cancel"),
71
+ React.createElement(Box, { marginTop: 1, flexDirection: "column" },
72
+ visibleLines.map((line, index) => (React.createElement(Box, { key: `${panel.connectorName}:${panel.fieldLabel}:${index}`, flexDirection: "row" },
73
+ React.createElement(Box, { minWidth: 5 },
74
+ React.createElement(Text, { color: theme.text.secondary }, String(index + 1).padStart(4, ' '))),
75
+ React.createElement(Text, { color: theme.text.primary }, panel.masked && line ? '*'.repeat(line.length) : line || ' ')))),
76
+ previewLines.length > visibleLines.length ? (React.createElement(Text, { color: theme.text.secondary },
77
+ "\u2026 ",
78
+ previewLines.length - visibleLines.length,
79
+ " more line(s) in buffer")) : null)));
80
+ }
81
+ if (panel.kind === 'root') {
82
+ const entries = panel.items.map((item) => ({
83
+ id: item.id,
84
+ title: item.title,
85
+ description: item.description,
86
+ }));
87
+ return (React.createElement(Box, { flexDirection: "column", width: columns },
88
+ React.createElement(Text, { color: theme.text.primary }, "Config"),
89
+ React.createElement(Text, { color: theme.text.secondary }, "Choose a config area with arrows, then press Enter."),
90
+ React.createElement(Text, { color: theme.text.secondary }, "Esc close \u00B7 Enter open \u00B7 PgUp/PgDn scroll"),
91
+ React.createElement(Box, { marginTop: 1, flexDirection: "column" }, renderListItems(entries, panel.selectedIndex, columns)),
92
+ panel.selectedQuestId ? (React.createElement(Text, { color: theme.text.secondary },
93
+ "Current quest: ",
94
+ panel.selectedQuestId)) : (React.createElement(Text, { color: theme.text.secondary }, "No quest currently selected."))));
95
+ }
96
+ if (panel.kind === 'files') {
97
+ const entries = panel.items.map((item) => ({
98
+ id: item.id,
99
+ title: item.title,
100
+ description: shortenPath(tildeifyPath(item.path), Math.max(28, columns - 10)),
101
+ }));
102
+ const selected = panel.items[Math.max(0, Math.min(panel.selectedIndex, panel.items.length - 1))] ?? null;
103
+ return (React.createElement(Box, { flexDirection: "column", width: columns },
104
+ React.createElement(Text, { color: theme.text.primary }, panel.title),
105
+ React.createElement(Text, { color: theme.text.secondary }, panel.description),
106
+ React.createElement(Text, { color: theme.text.secondary }, "\u2191/\u2193 choose \u00B7 Enter edit \u00B7 PgUp/PgDn scroll \u00B7 Esc back"),
107
+ React.createElement(Box, { marginTop: 1, flexDirection: "column" }, entries.length > 0 ? (renderListItems(entries, panel.selectedIndex, columns)) : (React.createElement(Text, { color: theme.text.secondary }, "No config files available in this section."))),
108
+ selected ? (React.createElement(Box, { flexDirection: "column", marginTop: 1 },
109
+ React.createElement(Text, { color: theme.text.link }, "Selected"),
110
+ React.createElement(Text, { color: theme.text.primary }, selected.title),
111
+ React.createElement(Text, { color: theme.text.secondary }, tildeifyPath(selected.path)))) : null));
112
+ }
113
+ if (panel.kind === 'connector-list') {
114
+ const entries = panel.items.map((item) => ({
115
+ id: item.name,
116
+ title: `${item.label} · ${item.enabled ? 'enabled' : 'disabled'}`,
117
+ description: item.subtitle,
118
+ secondary: [
119
+ item.connectionState || 'unknown',
120
+ typeof item.bindingCount === 'number' ? `bindings ${item.bindingCount}` : null,
121
+ typeof item.targetCount === 'number' ? `targets ${item.targetCount}` : null,
122
+ item.supportMode === 'guided' ? 'guided setup' : 'raw config only',
123
+ ]
124
+ .filter(Boolean)
125
+ .join(' · '),
126
+ }));
127
+ return (React.createElement(Box, { flexDirection: "column", width: columns },
128
+ React.createElement(Text, { color: theme.text.primary }, "Connectors"),
129
+ React.createElement(Text, { color: theme.text.secondary }, "Choose a connector, then press Enter."),
130
+ React.createElement(Text, { color: theme.text.secondary }, "\u2191/\u2193 choose \u00B7 Enter open \u00B7 PgUp/PgDn scroll \u00B7 Esc back"),
131
+ React.createElement(Box, { marginTop: 1, flexDirection: "column" }, entries.length > 0 ? renderListItems(entries, panel.selectedIndex, columns) : React.createElement(Text, { color: theme.text.secondary }, "No connectors available."))));
132
+ }
133
+ if (panel.kind === 'connector-detail') {
134
+ const selected = panel.items[Math.max(0, Math.min(panel.selectedIndex, panel.items.length - 1))] ?? null;
135
+ return (React.createElement(Box, { flexDirection: "column", width: columns },
136
+ React.createElement(Text, { color: theme.text.primary }, panel.connectorLabel),
137
+ React.createElement(Text, { color: theme.text.secondary }, connectorStateLine(panel.snapshot)),
138
+ panel.contextLine ? React.createElement(Text, { color: theme.text.link }, panel.contextLine) : null,
139
+ React.createElement(Text, { color: theme.text.secondary },
140
+ "\u2191/\u2193 choose \u00B7 Enter action/edit \u00B7 PgUp/PgDn scroll \u00B7 Esc back",
141
+ panel.dirty ? ' · unsaved changes' : ''),
142
+ panel.warning ? React.createElement(Text, { color: theme.status.warning }, panel.warning) : null,
143
+ panel.guideSections && panel.guideSections.length > 0 ? (React.createElement(Box, { marginTop: 1, flexDirection: "column" }, panel.guideSections.map((section) => {
144
+ const titleColor = section.tone === 'warning'
145
+ ? theme.status.warning
146
+ : section.tone === 'success'
147
+ ? theme.status.success
148
+ : theme.text.link;
149
+ const lineColor = section.tone === 'warning'
150
+ ? theme.status.warning
151
+ : section.tone === 'success'
152
+ ? theme.text.primary
153
+ : theme.text.secondary;
154
+ return (React.createElement(Box, { key: `guide:${section.id}`, flexDirection: "column", marginBottom: 1 },
155
+ React.createElement(Text, { color: titleColor }, section.title),
156
+ section.lines.map((line, index) => (React.createElement(Text, { key: `guide:${section.id}:${index}`, color: lineColor }, line)))));
157
+ }))) : null,
158
+ React.createElement(Box, { marginTop: 1, flexDirection: "column" }, panel.items.map((item, index) => {
159
+ const isSelected = index === panel.selectedIndex;
160
+ if (item.type === 'action') {
161
+ return (React.createElement(Box, { key: `action:${item.id}`, flexDirection: "column", marginBottom: 1 },
162
+ React.createElement(Text, { color: item.disabled ? theme.text.secondary : isSelected ? theme.status.success : theme.text.primary },
163
+ isSelected ? '> ' : ' ',
164
+ index + 1,
165
+ ". [Action] ",
166
+ item.label),
167
+ React.createElement(Text, { color: theme.text.secondary }, item.description)));
168
+ }
169
+ if (item.type === 'field') {
170
+ return (React.createElement(Box, { key: `field:${item.key}`, flexDirection: "column", marginBottom: 1 },
171
+ React.createElement(Text, { color: isSelected ? theme.status.success : theme.text.primary },
172
+ isSelected ? '> ' : ' ',
173
+ index + 1,
174
+ ". ",
175
+ item.label,
176
+ ": ",
177
+ item.value || '—',
178
+ item.dirty ? ' *' : ''),
179
+ React.createElement(Text, { color: theme.text.secondary }, item.description)));
180
+ }
181
+ return (React.createElement(Box, { key: `info:${item.id}`, flexDirection: "column", marginBottom: 1 },
182
+ React.createElement(Text, { color: isSelected ? theme.status.success : theme.text.primary },
183
+ isSelected ? '> ' : ' ',
184
+ index + 1,
185
+ ". ",
186
+ item.label,
187
+ ": ",
188
+ item.multiline ? '' : item.value || '—'),
189
+ item.multiline ? React.createElement(Box, { flexDirection: "column" }, renderMultilineValue(item.value)) : null,
190
+ item.description ? React.createElement(Text, { color: theme.text.secondary }, item.description) : null));
191
+ })),
192
+ selected && selected.type === 'info' && !selected.multiline ? (React.createElement(Box, { flexDirection: "column", marginTop: 1 },
193
+ React.createElement(Text, { color: theme.text.link }, "Selected"),
194
+ React.createElement(Text, { color: theme.text.primary }, selected.value || '—'))) : null));
195
+ }
196
+ const qrLines = String(panel.qrAscii || '')
197
+ .split('\n')
198
+ .filter((line) => line.length > 0);
48
199
  return (React.createElement(Box, { flexDirection: "column", width: columns },
49
- React.createElement(Text, { color: theme.text.primary }, "Config"),
50
- React.createElement(Text, { color: theme.text.secondary }, "Select a file to open and edit in-place."),
51
- React.createElement(Text, { color: theme.text.secondary }, "\u2191/\u2193 choose \u00B7 Enter edit \u00B7 Esc close"),
200
+ React.createElement(Text, { color: theme.text.primary }, "Weixin QR Login"),
201
+ React.createElement(Text, { color: theme.text.secondary },
202
+ "Status: ",
203
+ panel.status || 'waiting',
204
+ panel.sessionKey ? ` · ${panel.sessionKey}` : ''),
205
+ React.createElement(Text, { color: theme.text.secondary }, "Esc back \u00B7 QR refreshes automatically while waiting"),
206
+ panel.message ? React.createElement(Text, { color: theme.text.secondary }, panel.message) : null,
207
+ React.createElement(Box, { marginTop: 1, flexDirection: "column" }, qrLines.length > 0 ? (qrLines.map((line, index) => (React.createElement(Text, { key: `qr:${index}`, color: theme.text.primary }, line)))) : panel.qrContent ? (React.createElement(Text, { color: theme.text.secondary }, panel.qrContent)) : (React.createElement(Text, { color: theme.text.secondary }, "QR code is loading\u2026"))),
208
+ panel.qrUrl ? (React.createElement(Box, { marginTop: 1, flexDirection: "column" },
209
+ React.createElement(Text, { color: theme.text.link }, "QR Source"),
210
+ React.createElement(Text, { color: theme.text.secondary }, shortenPath(panel.qrUrl, Math.max(24, columns - 4))))) : null,
52
211
  React.createElement(Box, { marginTop: 1, flexDirection: "column" },
53
- renderSection('global', globalItems),
54
- renderSection('quest', questItems)),
55
- selected ? (React.createElement(Box, { flexDirection: "column", marginTop: 1 },
56
- React.createElement(Text, { color: theme.text.link }, "Selected"),
57
- React.createElement(Text, { color: theme.text.primary }, selected.title),
58
- React.createElement(Text, { color: theme.text.secondary }, tildeifyPath(selected.path)),
59
- React.createElement(Text, { color: theme.text.secondary }, selected.scope === 'global' ? 'Global runtime config file.' : 'Quest-local config file.'))) : null));
212
+ React.createElement(Text, { color: theme.text.secondary }, "Scan this QR code with WeChat, then confirm the login on the phone."),
213
+ React.createElement(Text, { color: theme.text.secondary }, "DeepScientist will save the connector automatically after confirmation."))));
60
214
  };
@@ -1,29 +1,10 @@
1
1
  import React from 'react';
2
2
  import { Text } from 'ink';
3
3
  import { theme } from '../semantic-colors.js';
4
- const hashWord = (value) => {
5
- let hash = 0;
6
- for (let index = 0; index < value.length; index += 1) {
7
- hash = (hash * 31 + value.charCodeAt(index)) >>> 0;
8
- }
9
- return hash;
10
- };
11
- const renderSegment = (segment, palette) => {
12
- const parts = segment.split(/(\s+)/);
13
- return parts.map((part, index) => {
14
- if (!part)
15
- return null;
16
- if (part.trim().length === 0) {
17
- return React.createElement(Text, { key: `space-${index}` }, part);
18
- }
19
- const color = palette[hashWord(part) % palette.length];
20
- return (React.createElement(Text, { key: `word-${index}`, color: color }, part));
21
- });
22
- };
23
4
  export const GradientStatusText = ({ text }) => {
24
5
  const palette = theme.ui.gradient.length > 0 ? [...theme.ui.gradient] : [theme.text.accent];
25
6
  const segments = text.split('|').map((segment) => segment.trim());
26
7
  return (React.createElement(Text, { wrap: "truncate" }, segments.map((segment, index) => (React.createElement(React.Fragment, { key: `segment-${index}` },
27
8
  index > 0 ? React.createElement(Text, { color: theme.text.secondary }, " | ") : null,
28
- renderSegment(segment, palette))))));
9
+ React.createElement(Text, { color: palette[index % palette.length] || theme.text.accent }, segment))))));
29
10
  };
@@ -101,6 +101,12 @@ const splitTrailingPartialAny = (data, tokens) => {
101
101
  }
102
102
  return best;
103
103
  };
104
+ const hasPasteTokenFragment = (data) => {
105
+ if (!data) {
106
+ return false;
107
+ }
108
+ return splitTrailingPartialAny(data, [...PASTE_START_TOKENS, ...PASTE_END_TOKENS]).tail.length > 0;
109
+ };
104
110
  const findToken = (data, tokens) => {
105
111
  let bestIndex = -1;
106
112
  let bestToken = null;
@@ -200,8 +206,8 @@ export const InputPrompt = ({ value, placeholder = 'Type a message', disabled, g
200
206
  }, [value, cursorIndex, firstLineWidth, otherLineWidth, isPlaceholder, placeholder]);
201
207
  const outerHeight = contentLines.length + 2;
202
208
  const borderColor = glowActive ? theme.text.accent : theme.border.default;
203
- const cursorBackground = '#7fbfff';
204
- const cursorTextColor = 'black';
209
+ const cursorBackground = theme.ui.cursor.background;
210
+ const cursorTextColor = theme.ui.cursor.text;
205
211
  const topBorder = useMemo(() => {
206
212
  const middle = '─'.repeat(Math.max(0, outerWidth - 2));
207
213
  return `╭${middle}╮`;
@@ -311,8 +317,10 @@ export const InputPrompt = ({ value, placeholder = 'Type a message', disabled, g
311
317
  insertValue(head);
312
318
  handled = true;
313
319
  }
314
- if (tail)
320
+ if (tail) {
315
321
  pastePendingRef.current = tail;
322
+ return true;
323
+ }
316
324
  return handled;
317
325
  }
318
326
  if (startIndex > 0) {
@@ -332,18 +340,44 @@ export const InputPrompt = ({ value, placeholder = 'Type a message', disabled, g
332
340
  if (key.ctrl && (input === 'c' || input === '\u0003')) {
333
341
  return;
334
342
  }
335
- if ((key.ctrl || key.meta) && !(key.ctrl && input === 'j')) {
336
- return;
337
- }
338
343
  const hasPasteMarkers = pasteActiveRef.current ||
339
344
  pastePendingRef.current.length > 0 ||
340
345
  PASTE_START_TOKENS.some((token) => input.includes(token)) ||
341
- PASTE_END_TOKENS.some((token) => input.includes(token));
346
+ PASTE_END_TOKENS.some((token) => input.includes(token)) ||
347
+ hasPasteTokenFragment(input);
342
348
  if (hasPasteMarkers) {
343
349
  const handled = handlePasteChunk(input);
344
350
  if (handled)
345
351
  return;
346
352
  }
353
+ const backspaceMatches = input.match(/[\x7f\b]/g);
354
+ if (key.backspace || backspaceMatches) {
355
+ const removalCount = Math.max(backspaceMatches?.length || 0, key.backspace ? 1 : 0);
356
+ if (removalCount > 0) {
357
+ if (mentionsEnabled) {
358
+ const range = getLeadingMentionDeleteRange(valueRef.current);
359
+ const currentCursorIndex = cursorIndexRef.current;
360
+ if (range && currentCursorIndex > 0 && currentCursorIndex <= range.end) {
361
+ const nextValue = valueRef.current.slice(range.end);
362
+ setValue(nextValue, 0);
363
+ return;
364
+ }
365
+ }
366
+ deleteBeforeCursor(removalCount);
367
+ const cleanedInput = input.replace(/[\x7f\b]/g, '');
368
+ if (cleanedInput) {
369
+ insertValue(cleanedInput);
370
+ }
371
+ return;
372
+ }
373
+ }
374
+ if (key.delete) {
375
+ deleteAtCursor(1);
376
+ return;
377
+ }
378
+ if ((key.ctrl || key.meta) && !(key.ctrl && input === 'j')) {
379
+ return;
380
+ }
347
381
  if (suggestionsVisible) {
348
382
  if ((key.upArrow || key.downArrow) && onSuggestionNavigate) {
349
383
  onSuggestionNavigate(key.upArrow ? -1 : 1);
@@ -439,31 +473,6 @@ export const InputPrompt = ({ value, placeholder = 'Type a message', disabled, g
439
473
  insertValue('\n');
440
474
  return;
441
475
  }
442
- const backspaceMatches = input.match(/[\x7f\b]/g);
443
- if (key.backspace || backspaceMatches) {
444
- const removalCount = Math.max(backspaceMatches?.length || 0, key.backspace ? 1 : 0);
445
- if (removalCount > 0) {
446
- if (mentionsEnabled) {
447
- const range = getLeadingMentionDeleteRange(valueRef.current);
448
- const currentCursorIndex = cursorIndexRef.current;
449
- if (range && currentCursorIndex > 0 && currentCursorIndex <= range.end) {
450
- const nextValue = valueRef.current.slice(range.end);
451
- setValue(nextValue, 0);
452
- return;
453
- }
454
- }
455
- deleteBeforeCursor(removalCount);
456
- const cleanedInput = input.replace(/[\x7f\b]/g, '');
457
- if (cleanedInput) {
458
- insertValue(cleanedInput);
459
- }
460
- return;
461
- }
462
- }
463
- if (key.delete) {
464
- deleteAtCursor(1);
465
- return;
466
- }
467
476
  if (input.includes('\x1b')) {
468
477
  return;
469
478
  }
@@ -6,6 +6,6 @@ export const LoadingIndicator = ({ active, currentLoadingPhrase, rightContent, }
6
6
  return null;
7
7
  }
8
8
  return (React.createElement(Box, { marginTop: 1, width: "100%", justifyContent: "space-between" },
9
- React.createElement(Text, { color: theme.text.accent }, currentLoadingPhrase || 'Running'),
9
+ React.createElement(Text, { color: theme.text.link }, currentLoadingPhrase || 'Running'),
10
10
  rightContent ? React.createElement(Box, null, rightContent) : null));
11
11
  };
@@ -1,13 +1,7 @@
1
1
  import React from 'react';
2
2
  import { Box, Text } from 'ink';
3
3
  import { useTerminalSize } from '../hooks/useTerminalSize.js';
4
- const COLORS = {
5
- blue: '#4796E4',
6
- sky: '#6E8CE8',
7
- violet: '#847ACE',
8
- rose: '#C3677F',
9
- gold: '#B69B4A',
10
- };
4
+ import { theme } from '../semantic-colors.js';
11
5
  const WORDMARK_LINES = [
12
6
  ' ____ ____ _ _ _ _ ',
13
7
  ' | _ \\ ___ ___ _ __ / ___| ___(_) ___ _ __ | |_(_)___| |_ ',
@@ -17,38 +11,67 @@ const WORDMARK_LINES = [
17
11
  ' |_| ',
18
12
  ];
19
13
  const WORDMARK_COLORS = [
20
- COLORS.blue,
21
- COLORS.sky,
22
- COLORS.violet,
23
- COLORS.violet,
24
- COLORS.rose,
25
- COLORS.gold,
14
+ theme.ui.brand.strong,
15
+ theme.ui.brand.medium,
16
+ theme.ui.brand.soft,
17
+ theme.ui.brand.soft,
18
+ theme.ui.brand.medium,
19
+ theme.text.secondary,
20
+ ];
21
+ const ICON_LINES = [
22
+ [{ text: ' ╭─────────╮', color: theme.ui.brand.medium }],
23
+ [
24
+ { text: ' │ ', color: theme.ui.brand.medium },
25
+ { text: '●', color: theme.ui.brand.soft },
26
+ { text: '─', color: theme.ui.brand.medium },
27
+ { text: '●', color: theme.ui.brand.strong },
28
+ { text: '─', color: theme.ui.brand.medium },
29
+ { text: '●', color: theme.ui.brand.soft },
30
+ { text: ' │', color: theme.ui.brand.medium },
31
+ ],
32
+ [
33
+ { text: ' │ │ ', color: theme.ui.brand.medium },
34
+ { text: '╲', color: theme.ui.brand.soft },
35
+ { text: '│', color: theme.ui.brand.medium },
36
+ { text: ' │', color: theme.ui.brand.medium },
37
+ ],
38
+ [
39
+ { text: ' │ ', color: theme.ui.brand.medium },
40
+ { text: '●', color: theme.ui.brand.soft },
41
+ { text: '─', color: theme.ui.brand.medium },
42
+ { text: '●', color: theme.ui.brand.strong },
43
+ { text: '─', color: theme.ui.brand.medium },
44
+ { text: '●', color: theme.ui.brand.medium },
45
+ { text: '─', color: theme.ui.brand.medium },
46
+ { text: '●', color: theme.ui.brand.soft },
47
+ { text: ' │', color: theme.ui.brand.medium },
48
+ ],
49
+ [
50
+ { text: ' │ ', color: theme.ui.brand.medium },
51
+ { text: '╲', color: theme.ui.brand.soft },
52
+ { text: ' │', color: theme.ui.brand.medium },
53
+ { text: ' │', color: theme.ui.brand.medium },
54
+ ],
55
+ [
56
+ { text: ' │ ', color: theme.ui.brand.medium },
57
+ { text: '●', color: theme.ui.brand.medium },
58
+ { text: ' │', color: theme.ui.brand.medium },
59
+ ],
60
+ [{ text: ' ╰─────────╯', color: theme.ui.brand.medium }],
26
61
  ];
27
- const IconMark = () => (React.createElement(Box, { flexDirection: "column", marginRight: 2 },
28
- React.createElement(Text, null,
29
- React.createElement(Text, { color: COLORS.gold }, " \u2726")),
30
- React.createElement(Text, null,
31
- React.createElement(Text, { color: COLORS.blue }, " \u256D\u2500\u2500"),
32
- React.createElement(Text, { color: COLORS.violet }, "\u25CC"),
33
- React.createElement(Text, { color: COLORS.blue }, "\u2500\u2500\u256E")),
34
- React.createElement(Text, null,
35
- React.createElement(Text, { color: COLORS.violet }, "\u25CC "),
36
- React.createElement(Text, { color: COLORS.blue }, "\u2502 "),
37
- React.createElement(Text, { color: COLORS.gold }, "\u25CF"),
38
- React.createElement(Text, { color: COLORS.blue }, " \u2502"),
39
- React.createElement(Text, { color: COLORS.violet }, " \u25CC")),
40
- React.createElement(Text, null,
41
- React.createElement(Text, { color: COLORS.blue }, " \u2570\u2500\u2500"),
42
- React.createElement(Text, { color: COLORS.violet }, "\u25CC"),
43
- React.createElement(Text, { color: COLORS.blue }, "\u2500\u2500\u256F")),
44
- React.createElement(Text, null,
45
- React.createElement(Text, { color: COLORS.gold }, " \u2726")),
46
- React.createElement(Text, { color: COLORS.gold }, " research orbit")));
62
+ const IconMark = () => (React.createElement(Box, { flexDirection: "column", marginRight: 2 }, ICON_LINES.map((segments, lineIndex) => (React.createElement(Text, { key: `icon-line-${lineIndex}` }, segments.map((segment, segmentIndex) => (React.createElement(Text, { key: `icon-line-${lineIndex}-segment-${segmentIndex}`, color: segment.color }, segment.text))))))));
47
63
  const CompactMark = () => (React.createElement(Text, null,
48
- React.createElement(Text, { color: COLORS.gold }, "\u2726 "),
49
- React.createElement(Text, { color: COLORS.blue }, "DEEP"),
50
- React.createElement(Text, { color: COLORS.violet }, "SCIENT"),
51
- React.createElement(Text, { color: COLORS.rose }, "IST")));
64
+ React.createElement(Text, { color: theme.ui.brand.medium }, "["),
65
+ React.createElement(Text, { color: theme.ui.brand.soft }, "\u25CF"),
66
+ React.createElement(Text, { color: theme.ui.brand.medium }, "\u2500"),
67
+ React.createElement(Text, { color: theme.ui.brand.strong }, "\u25CF"),
68
+ React.createElement(Text, { color: theme.ui.brand.medium }, "\u2500"),
69
+ React.createElement(Text, { color: theme.ui.brand.soft }, "\u25CF"),
70
+ React.createElement(Text, { color: theme.ui.brand.medium }, "]"),
71
+ React.createElement(Text, { color: theme.text.secondary }, " "),
72
+ React.createElement(Text, { color: theme.ui.brand.strong }, "DEEP"),
73
+ React.createElement(Text, { color: theme.ui.brand.medium }, "SCIENT"),
74
+ React.createElement(Text, { color: theme.ui.brand.soft }, "IST")));
52
75
  export const Logo = () => {
53
76
  const { columns } = useTerminalSize();
54
77
  if (columns < 120) {
@@ -57,5 +80,5 @@ export const Logo = () => {
57
80
  }
58
81
  return (React.createElement(Box, { flexDirection: "row", alignItems: "flex-start" },
59
82
  React.createElement(IconMark, null),
60
- React.createElement(Box, { flexDirection: "column" }, WORDMARK_LINES.map((line, index) => (React.createElement(Text, { key: line, color: WORDMARK_COLORS[index] || COLORS.blue }, line))))));
83
+ React.createElement(Box, { flexDirection: "column" }, WORDMARK_LINES.map((line, index) => (React.createElement(Text, { key: line, color: WORDMARK_COLORS[index] || theme.ui.brand.strong }, line))))));
61
84
  };
@@ -9,7 +9,7 @@ import { QuestScreen } from './QuestScreen.js';
9
9
  import { WelcomePanel } from './WelcomePanel.js';
10
10
  import { theme } from '../semantic-colors.js';
11
11
  import { isAlternateBufferEnabled } from '../utils/terminal.js';
12
- const MainContentComponent = ({ quests, browseQuestId, configMode, configItems, configIndex, configEditor, questPanelMode, questPanelQuests, questPanelIndex, snapshot, connectors, session, history, pendingHistoryItems, baseUrl, connectionState, availableHeight, onQuestPanelMove, onQuestPanelConfirm, onQuestPanelCancel, }) => {
12
+ const MainContentComponent = ({ quests, browseQuestId, configMode, configPanel, questPanelMode, questPanelQuests, questPanelIndex, snapshot, connectors, session, history, pendingHistoryItems, baseUrl, connectionState, availableHeight, onQuestPanelMove, onQuestPanelConfirm, onQuestPanelCancel, }) => {
13
13
  const { columns } = useTerminalSize();
14
14
  const scrollRef = useRef(null);
15
15
  const [isFollowing, setIsFollowing] = useState(true);
@@ -80,9 +80,16 @@ const MainContentComponent = ({ quests, browseQuestId, configMode, configItems,
80
80
  scrollRef.current?.scrollBy(1);
81
81
  }
82
82
  });
83
+ const renderConfigPanel = () => {
84
+ const node = (React.createElement(ConfigScreen, { panel: configPanel || { kind: 'root', items: [], selectedIndex: 0, selectedQuestId }, availableHeight: availableHeight }));
85
+ if (!viewportHeight) {
86
+ return node;
87
+ }
88
+ return (React.createElement(Scrollable, { ref: scrollRef, height: viewportHeight, width: columns, onScrollState: handleScrollState }, node));
89
+ };
83
90
  if (showWelcome) {
84
91
  if (configMode) {
85
- return (React.createElement(ConfigScreen, { mode: configMode, items: configItems, selectedIndex: configIndex, selectedQuestId: selectedQuestId, editor: configEditor, availableHeight: availableHeight }));
92
+ return renderConfigPanel();
86
93
  }
87
94
  if (questPanelMode) {
88
95
  return (React.createElement(QuestScreen, { mode: questPanelMode, quests: questPanelQuests, selectedIndex: questPanelIndex, availableHeight: availableHeight, onMove: onQuestPanelMove, onConfirm: onQuestPanelConfirm, onCancel: onQuestPanelCancel }));
@@ -90,7 +97,7 @@ const MainContentComponent = ({ quests, browseQuestId, configMode, configItems,
90
97
  return (React.createElement(WelcomePanel, { quests: quests, browseQuestId: browseQuestId, connectors: connectors, baseUrl: baseUrl, connectionState: connectionState }));
91
98
  }
92
99
  if (configMode) {
93
- return (React.createElement(ConfigScreen, { mode: configMode, items: configItems, selectedIndex: configIndex, selectedQuestId: selectedQuestId, editor: configEditor, availableHeight: availableHeight }));
100
+ return renderConfigPanel();
94
101
  }
95
102
  if (questPanelMode) {
96
103
  return (React.createElement(QuestScreen, { mode: questPanelMode, quests: questPanelQuests, selectedIndex: questPanelIndex, availableHeight: availableHeight, onMove: onQuestPanelMove, onConfirm: onQuestPanelConfirm, onCancel: onQuestPanelCancel }));
@@ -1,17 +1,10 @@
1
1
  import React from 'react';
2
2
  import { Box, Text } from 'ink';
3
- import Gradient from 'ink-gradient';
4
3
  import stringWidth from 'string-width';
5
4
  import { Logo } from './Logo.js';
6
5
  import { theme } from '../semantic-colors.js';
7
6
  import { useTerminalSize } from '../hooks/useTerminalSize.js';
8
- // Colors matching AsciiArt
9
- const COLORS = {
10
- blue: '#4796E4',
11
- red: '#F38BA8',
12
- gradient: ['#9B59B6', '#8E44AD', '#C471ED', '#F64F9C'],
13
- gold: '#B69B4A',
14
- };
7
+ import { ThemedGradient } from './ThemedGradient.js';
15
8
  const clipText = (value, maxWidth) => {
16
9
  const safeWidth = Math.max(4, maxWidth);
17
10
  if (stringWidth(value) <= safeWidth) {
@@ -97,8 +90,7 @@ export const WelcomePanel = ({ quests, browseQuestId, connectors, baseUrl, conne
97
90
  ? 'Press Ctrl+O to open the web workspace if auto-open is unavailable.'
98
91
  : 'Ctrl+O opens the web workspace.';
99
92
  return (React.createElement(Box, { flexDirection: "column", marginBottom: 1 },
100
- React.createElement(Box, { flexDirection: "column" }, infoLines.map((info, idx) => (React.createElement(Box, { key: idx }, info.style === 'title' ? (React.createElement(Gradient, { colors: COLORS.gradient },
101
- React.createElement(Text, { bold: true }, info.value))) : (React.createElement(React.Fragment, null,
93
+ React.createElement(Box, { flexDirection: "column" }, infoLines.map((info, idx) => (React.createElement(Box, { key: idx }, info.style === 'title' ? (React.createElement(ThemedGradient, { bold: true }, info.value)) : (React.createElement(React.Fragment, null,
102
94
  info.label && (React.createElement(Text, { color: theme.text.secondary },
103
95
  info.label,
104
96
  ": ")),
@@ -106,9 +98,9 @@ export const WelcomePanel = ({ quests, browseQuestId, connectors, baseUrl, conne
106
98
  React.createElement(Box, { marginTop: 1 },
107
99
  React.createElement(Logo, null)),
108
100
  React.createElement(Box, { marginTop: 1, width: columns, justifyContent: "center" },
109
- React.createElement(Text, { color: COLORS.gold }, "Web Workspace")),
101
+ React.createElement(Text, { color: theme.text.link }, "Web Workspace")),
110
102
  React.createElement(Box, { width: columns, justifyContent: "center" },
111
- React.createElement(Text, { bold: true, color: COLORS.blue }, urlBannerText)),
103
+ React.createElement(Text, { bold: true, color: theme.text.accent }, urlBannerText)),
112
104
  React.createElement(Box, { width: columns, justifyContent: "center" },
113
105
  React.createElement(Text, { color: theme.text.secondary }, clipText(urlHint, Math.max(20, columns - 4)))),
114
106
  React.createElement(Box, { marginTop: 1 },
@@ -4,7 +4,7 @@ import { MarkdownDisplay } from '../../utils/MarkdownDisplay.js';
4
4
  import { theme } from '../../semantic-colors.js';
5
5
  export const AssistantMessage = ({ text, source, skillId, streaming, width, }) => {
6
6
  const prefix = '• ';
7
- const responseColor = 'white';
7
+ const responseColor = theme.text.response;
8
8
  const prefixWidth = prefix.length;
9
9
  const contentWidth = Math.max(1, width - prefixWidth);
10
10
  const agentLabel = [source ? `@${source}` : null, skillId ? `skill:${skillId}` : null, streaming ? 'streaming' : null]