@researai/deepscientist 1.5.0 → 1.5.1

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 (163) hide show
  1. package/AGENTS.md +26 -0
  2. package/README.md +19 -179
  3. package/assets/connectors/lingzhu/openclaw-bridge/README.md +124 -0
  4. package/assets/connectors/lingzhu/openclaw-bridge/index.ts +162 -0
  5. package/assets/connectors/lingzhu/openclaw-bridge/openclaw.plugin.json +145 -0
  6. package/assets/connectors/lingzhu/openclaw-bridge/package.json +35 -0
  7. package/assets/connectors/lingzhu/openclaw-bridge/src/cli.ts +180 -0
  8. package/assets/connectors/lingzhu/openclaw-bridge/src/config.ts +196 -0
  9. package/assets/connectors/lingzhu/openclaw-bridge/src/debug-log.ts +111 -0
  10. package/assets/connectors/lingzhu/openclaw-bridge/src/events.ts +4 -0
  11. package/assets/connectors/lingzhu/openclaw-bridge/src/http-handler.ts +1133 -0
  12. package/assets/connectors/lingzhu/openclaw-bridge/src/image-cache.ts +75 -0
  13. package/assets/connectors/lingzhu/openclaw-bridge/src/lingzhu-tools.ts +246 -0
  14. package/assets/connectors/lingzhu/openclaw-bridge/src/transform.ts +541 -0
  15. package/assets/connectors/lingzhu/openclaw-bridge/src/types.ts +131 -0
  16. package/assets/connectors/lingzhu/openclaw-bridge/tsconfig.json +14 -0
  17. package/assets/connectors/lingzhu/openclaw.lingzhu.config.template.json +39 -0
  18. package/bin/ds.js +233 -53
  19. package/docs/en/00_QUICK_START.md +134 -0
  20. package/docs/en/01_SETTINGS_REFERENCE.md +1104 -0
  21. package/docs/en/02_START_RESEARCH_GUIDE.md +404 -0
  22. package/docs/en/03_QQ_CONNECTOR_GUIDE.md +325 -0
  23. package/docs/en/04_LINGZHU_CONNECTOR_GUIDE.md +216 -0
  24. package/docs/en/05_TUI_GUIDE.md +141 -0
  25. package/docs/en/06_RUNTIME_AND_CANVAS.md +679 -0
  26. package/docs/en/07_MEMORY_AND_MCP.md +253 -0
  27. package/docs/en/08_FIGURE_STYLE_GUIDE.md +97 -0
  28. package/docs/en/09_DOCTOR.md +108 -0
  29. package/docs/en/90_ARCHITECTURE.md +245 -0
  30. package/docs/en/91_DEVELOPMENT.md +195 -0
  31. package/docs/en/99_ACKNOWLEDGEMENTS.md +29 -0
  32. package/docs/zh/00_QUICK_START.md +134 -0
  33. package/docs/zh/01_SETTINGS_REFERENCE.md +1137 -0
  34. package/docs/zh/02_START_RESEARCH_GUIDE.md +414 -0
  35. package/docs/zh/03_QQ_CONNECTOR_GUIDE.md +324 -0
  36. package/docs/zh/04_LINGZHU_CONNECTOR_GUIDE.md +230 -0
  37. package/docs/zh/05_TUI_GUIDE.md +128 -0
  38. package/docs/zh/06_RUNTIME_AND_CANVAS.md +271 -0
  39. package/docs/zh/07_MEMORY_AND_MCP.md +235 -0
  40. package/docs/zh/08_FIGURE_STYLE_GUIDE.md +97 -0
  41. package/docs/zh/09_DOCTOR.md +112 -0
  42. package/docs/zh/99_ACKNOWLEDGEMENTS.md +29 -0
  43. package/install.sh +32 -8
  44. package/package.json +4 -2
  45. package/pyproject.toml +1 -1
  46. package/src/deepscientist/artifact/guidance.py +9 -2
  47. package/src/deepscientist/artifact/service.py +482 -22
  48. package/src/deepscientist/bash_exec/monitor.py +27 -5
  49. package/src/deepscientist/bash_exec/runtime.py +639 -0
  50. package/src/deepscientist/bash_exec/service.py +99 -16
  51. package/src/deepscientist/bridges/base.py +3 -0
  52. package/src/deepscientist/bridges/connectors.py +292 -13
  53. package/src/deepscientist/channels/qq.py +19 -2
  54. package/src/deepscientist/channels/relay.py +1 -0
  55. package/src/deepscientist/cli.py +32 -25
  56. package/src/deepscientist/config/models.py +28 -2
  57. package/src/deepscientist/config/service.py +201 -6
  58. package/src/deepscientist/connector_runtime.py +2 -0
  59. package/src/deepscientist/daemon/api/handlers.py +50 -5
  60. package/src/deepscientist/daemon/api/router.py +1 -0
  61. package/src/deepscientist/daemon/app.py +442 -15
  62. package/src/deepscientist/doctor.py +444 -0
  63. package/src/deepscientist/home.py +1 -0
  64. package/src/deepscientist/latex_runtime.py +17 -4
  65. package/src/deepscientist/lingzhu_support.py +182 -0
  66. package/src/deepscientist/mcp/server.py +49 -2
  67. package/src/deepscientist/prompts/builder.py +181 -58
  68. package/src/deepscientist/quest/layout.py +1 -0
  69. package/src/deepscientist/quest/service.py +63 -2
  70. package/src/deepscientist/quest/stage_views.py +19 -1
  71. package/src/deepscientist/runtime_tools/__init__.py +16 -0
  72. package/src/deepscientist/runtime_tools/builtins.py +19 -0
  73. package/src/deepscientist/runtime_tools/models.py +29 -0
  74. package/src/deepscientist/runtime_tools/registry.py +40 -0
  75. package/src/deepscientist/runtime_tools/service.py +59 -0
  76. package/src/deepscientist/runtime_tools/tinytex.py +25 -0
  77. package/src/deepscientist/tinytex.py +276 -0
  78. package/src/prompts/connectors/lingzhu.md +12 -0
  79. package/src/prompts/connectors/qq.md +121 -0
  80. package/src/prompts/system.md +177 -33
  81. package/src/skills/analysis-campaign/SKILL.md +22 -6
  82. package/src/skills/baseline/SKILL.md +5 -4
  83. package/src/skills/decision/SKILL.md +4 -3
  84. package/src/skills/experiment/SKILL.md +5 -4
  85. package/src/skills/finalize/SKILL.md +5 -4
  86. package/src/skills/idea/SKILL.md +5 -4
  87. package/src/skills/intake-audit/SKILL.md +277 -0
  88. package/src/skills/intake-audit/references/state-audit-template.md +41 -0
  89. package/src/skills/rebuttal/SKILL.md +407 -0
  90. package/src/skills/rebuttal/references/action-plan-template.md +63 -0
  91. package/src/skills/rebuttal/references/evidence-update-template.md +30 -0
  92. package/src/skills/rebuttal/references/response-letter-template.md +113 -0
  93. package/src/skills/rebuttal/references/review-matrix-template.md +55 -0
  94. package/src/skills/review/SKILL.md +293 -0
  95. package/src/skills/review/references/experiment-todo-template.md +29 -0
  96. package/src/skills/review/references/review-report-template.md +83 -0
  97. package/src/skills/review/references/revision-log-template.md +40 -0
  98. package/src/skills/scout/SKILL.md +5 -4
  99. package/src/skills/write/SKILL.md +7 -3
  100. package/src/tui/dist/components/WelcomePanel.js +17 -43
  101. package/src/tui/dist/components/messages/BashExecOperationMessage.js +3 -2
  102. package/src/tui/package.json +1 -1
  103. package/src/ui/dist/assets/{AiManusChatView-7v-dHngU.js → AiManusChatView-w5lF2Ttt.js} +109 -575
  104. package/src/ui/dist/assets/{AnalysisPlugin-B_Xmz-KE.js → AnalysisPlugin-DJOED79I.js} +1 -1
  105. package/src/ui/dist/assets/{AutoFigurePlugin-Cko-0tm1.js → AutoFigurePlugin-DaG61Y0M.js} +63 -8
  106. package/src/ui/dist/assets/{CliPlugin-BsU0ht7q.js → CliPlugin-CV4LqUB_.js} +43 -609
  107. package/src/ui/dist/assets/{CodeEditorPlugin-DcMMP0Rt.js → CodeEditorPlugin-DylfAea4.js} +8 -8
  108. package/src/ui/dist/assets/{CodeViewerPlugin-BqoQ5QyY.js → CodeViewerPlugin-F7saY0LM.js} +5 -5
  109. package/src/ui/dist/assets/{DocViewerPlugin-D7eHNhU6.js → DocViewerPlugin-COP0c7jf.js} +3 -3
  110. package/src/ui/dist/assets/{GitDiffViewerPlugin-DLJN42T5.js → GitDiffViewerPlugin-CAS05pT9.js} +1 -1
  111. package/src/ui/dist/assets/{ImageViewerPlugin-gJMV7MOu.js → ImageViewerPlugin-Bco1CN_w.js} +5 -6
  112. package/src/ui/dist/assets/{LabCopilotPanel-B857sfxP.js → LabCopilotPanel-CvMlCD99.js} +12 -15
  113. package/src/ui/dist/assets/LabPlugin-BYankkE4.js +2676 -0
  114. package/src/ui/dist/assets/LabPlugin-D9jVIo0A.css +2698 -0
  115. package/src/ui/dist/assets/{LatexPlugin-DWKEo-Wj.js → LatexPlugin-LDSMR-t-.js} +16 -16
  116. package/src/ui/dist/assets/{MarkdownViewerPlugin-DBzoEmhv.js → MarkdownViewerPlugin-B7o80jgm.js} +4 -4
  117. package/src/ui/dist/assets/{MarketplacePlugin-DoHc-8vo.js → MarketplacePlugin-CM6ZOcpC.js} +3 -3
  118. package/src/ui/dist/assets/{NotebookEditor-CKjKH-yS.js → NotebookEditor-Dc61cXmK.js} +3 -3
  119. package/src/ui/dist/assets/{PdfLoader-zFoL0VPo.js → PdfLoader-DWowuQwx.js} +1 -1
  120. package/src/ui/dist/assets/{PdfMarkdownPlugin-DXPaL9Nt.js → PdfMarkdownPlugin-BsJM1q_a.js} +3 -3
  121. package/src/ui/dist/assets/{PdfViewerPlugin-DhK8qCFp.js → PdfViewerPlugin-DB2eEEFQ.js} +10 -10
  122. package/src/ui/dist/assets/{SearchPlugin-CdSi6krf.js → SearchPlugin-CraThSvt.js} +1 -1
  123. package/src/ui/dist/assets/{Stepper-V-WiDQJl.js → Stepper-CgocRTPq.js} +1 -1
  124. package/src/ui/dist/assets/{TextViewerPlugin-hIs1Efiu.js → TextViewerPlugin-B1JGhKtd.js} +4 -4
  125. package/src/ui/dist/assets/{VNCViewer-DG8b0q2X.js → VNCViewer-CclFC7FM.js} +9 -10
  126. package/src/ui/dist/assets/{bibtex-HDac6fVW.js → bibtex-D3IKsMl7.js} +1 -1
  127. package/src/ui/dist/assets/{code-BnBeNxBc.js → code-BP37Xx0p.js} +1 -1
  128. package/src/ui/dist/assets/{file-content-IRQ3jHb8.js → file-content-BAJSu-9r.js} +1 -1
  129. package/src/ui/dist/assets/{file-diff-panel-DZoQ9I6r.js → file-diff-panel-DUGeCTuy.js} +1 -1
  130. package/src/ui/dist/assets/{file-socket-BMCdLc-P.js → file-socket-CXc1Ojf7.js} +1 -1
  131. package/src/ui/dist/assets/{file-utils-CltILB3w.js → file-utils-2J21jt7M.js} +1 -1
  132. package/src/ui/dist/assets/{image-Boe6ffhu.js → image-CMMmgvcn.js} +1 -1
  133. package/src/ui/dist/assets/{index-BlplpvE1.js → index-BaVumsQT.js} +2 -2
  134. package/src/ui/dist/assets/{index-DZqJ-qAM.js → index-CWgMgpow.js} +60 -2154
  135. package/src/ui/dist/assets/{index-DO43pFZP.js → index-DmwmJmbW.js} +6372 -8434
  136. package/src/ui/dist/assets/{index-Bq2bvfkl.css → index-KGt-z-dD.css} +225 -2920
  137. package/src/ui/dist/assets/{index-2Zf65FZt.js → index-s7aHnNQ4.js} +1 -1
  138. package/src/ui/dist/assets/{message-square-mUHn_Ssb.js → message-square-CQRfX0Am.js} +1 -1
  139. package/src/ui/dist/assets/{monaco-fe0arNEU.js → monaco-B4TbdsrF.js} +1 -1
  140. package/src/ui/dist/assets/{popover-D_7i19qU.js → popover-B8Rokodk.js} +1 -1
  141. package/src/ui/dist/assets/{project-sync-DyVGrU7H.js → project-sync-D_i96KH4.js} +2 -8
  142. package/src/ui/dist/assets/{sigma-BzazRyxQ.js → sigma-D12PnzCN.js} +1 -1
  143. package/src/ui/dist/assets/{tooltip-DN_yjHFH.js → tooltip-B6YrI4aJ.js} +1 -1
  144. package/src/ui/dist/assets/trash-Bc8jGp0V.js +32 -0
  145. package/src/ui/dist/assets/{useCliAccess-DV2L2Qxy.js → useCliAccess-mXVCYSZ-.js} +12 -42
  146. package/src/ui/dist/assets/{useFileDiffOverlay-DyTj-p_V.js → useFileDiffOverlay-Bg6b9H9K.js} +1 -1
  147. package/src/ui/dist/assets/{wrap-text-ozYHtUwq.js → wrap-text-Drh5GEnL.js} +1 -1
  148. package/src/ui/dist/assets/{zoom-out-BN9MUyCQ.js → zoom-out-CJj9DZLn.js} +1 -1
  149. package/src/ui/dist/index.html +2 -2
  150. package/assets/fonts/Inter-Variable.ttf +0 -0
  151. package/assets/fonts/NotoSerifSC-Regular-C94HN_ZN.ttf +0 -0
  152. package/assets/fonts/NunitoSans-Variable.ttf +0 -0
  153. package/assets/fonts/Satoshi-Medium-ByP-Zb-9.woff2 +0 -0
  154. package/assets/fonts/SourceSans3-Variable.ttf +0 -0
  155. package/assets/fonts/ds-fonts.css +0 -83
  156. package/src/ui/dist/assets/Inter-Variable-VF2RPR_K.ttf +0 -0
  157. package/src/ui/dist/assets/LabPlugin-bL7rpic8.js +0 -43
  158. package/src/ui/dist/assets/NotoSerifSC-Regular-C94HN_ZN-C94HN_ZN.ttf +0 -0
  159. package/src/ui/dist/assets/NunitoSans-Variable-B_ZymHAd.ttf +0 -0
  160. package/src/ui/dist/assets/Satoshi-Medium-ByP-Zb-9-GkA34YXu.woff2 +0 -0
  161. package/src/ui/dist/assets/SourceSans3-Variable-CD-WOsSK.ttf +0 -0
  162. package/src/ui/dist/assets/info-CcsK_htA.js +0 -18
  163. package/src/ui/dist/assets/user-plus-BusDx-hF.js +0 -79
@@ -0,0 +1,39 @@
1
+ {
2
+ "gateway": {
3
+ "port": 18789,
4
+ "http": {
5
+ "endpoints": {
6
+ "chatCompletions": {
7
+ "enabled": true
8
+ }
9
+ }
10
+ }
11
+ },
12
+ "plugins": {
13
+ "entries": {
14
+ "lingzhu": {
15
+ "enabled": true,
16
+ "config": {
17
+ "authAk": "",
18
+ "agentId": "main",
19
+ "includeMetadata": true,
20
+ "requestTimeoutMs": 60000,
21
+ "systemPrompt": "",
22
+ "defaultNavigationMode": "0",
23
+ "enableFollowUp": true,
24
+ "followUpMaxCount": 3,
25
+ "maxImageBytes": 5242880,
26
+ "sessionMode": "per_user",
27
+ "sessionNamespace": "lingzhu",
28
+ "autoReceiptAck": true,
29
+ "visibleProgressHeartbeat": true,
30
+ "visibleProgressHeartbeatSec": 10,
31
+ "debugLogging": false,
32
+ "debugLogPayloads": false,
33
+ "debugLogDir": "",
34
+ "enableExperimentalNativeActions": false
35
+ }
36
+ }
37
+ }
38
+ }
39
+ }
package/bin/ds.js CHANGED
@@ -21,10 +21,12 @@ const pythonCommands = new Set([
21
21
  'note',
22
22
  'approve',
23
23
  'graph',
24
- 'metrics',
24
+ 'doctor',
25
+ 'docker',
25
26
  'push',
26
27
  'memory',
27
28
  'baseline',
29
+ 'latex',
28
30
  'config',
29
31
  ]);
30
32
 
@@ -34,17 +36,21 @@ function printLauncherHelp() {
34
36
  console.log(`DeepScientist launcher
35
37
 
36
38
  Usage:
37
- research
38
- research --web
39
- research --both
40
- research --stop
41
- research --restart
42
- research --home ~/DeepScientist --port 20999
39
+ ds
40
+ ds --tui
41
+ ds --both
42
+ ds --stop
43
+ ds --restart
44
+ ds doctor
45
+ ds latex status
46
+ ds --home ~/DeepScientist --port 20999
43
47
 
44
48
  Advanced Python CLI:
45
49
  ds init
46
- ds new "reproduce baseline and test idea"
47
- ds run decision --quest-id q-001 --message "review current state"
50
+ ds new "reproduce baseline and test one stronger idea"
51
+ ds doctor
52
+ ds latex install-runtime
53
+ ds run decision --quest-id 001 --message "review current state"
48
54
  `);
49
55
  }
50
56
 
@@ -88,6 +94,146 @@ function bindUiUrl(host, port) {
88
94
  return `http://${formatHttpHost(normalized)}:${port}`;
89
95
  }
90
96
 
97
+ function normalizeMode(value) {
98
+ const normalized = String(value || '')
99
+ .trim()
100
+ .toLowerCase();
101
+ if (normalized === 'tui' || normalized === 'both' || normalized === 'web') {
102
+ return normalized;
103
+ }
104
+ return 'web';
105
+ }
106
+
107
+ function parseBooleanSetting(rawValue, fallback = false) {
108
+ if (typeof rawValue === 'boolean') {
109
+ return rawValue;
110
+ }
111
+ const normalized = String(rawValue || '')
112
+ .trim()
113
+ .toLowerCase();
114
+ if (['true', 'yes', 'on', '1'].includes(normalized)) {
115
+ return true;
116
+ }
117
+ if (['false', 'no', 'off', '0'].includes(normalized)) {
118
+ return false;
119
+ }
120
+ return fallback;
121
+ }
122
+
123
+ function supportsAnsi() {
124
+ return Boolean(process.stdout.isTTY && process.env.TERM !== 'dumb');
125
+ }
126
+
127
+ function stripAnsi(text) {
128
+ return String(text || '')
129
+ .replace(/\u001B]8;;[^\u0007]*\u0007/g, '')
130
+ .replace(/\u001B]8;;\u0007/g, '')
131
+ .replace(/\u001B\[[0-9;]*m/g, '');
132
+ }
133
+
134
+ function visibleWidth(text) {
135
+ return stripAnsi(text).length;
136
+ }
137
+
138
+ function centerText(text, width) {
139
+ const targetWidth = Math.max(visibleWidth(text), width || 0);
140
+ const padding = Math.max(0, Math.floor((targetWidth - visibleWidth(text)) / 2));
141
+ return `${' '.repeat(padding)}${text}`;
142
+ }
143
+
144
+ function hyperlink(url, label = url) {
145
+ if (!supportsAnsi()) {
146
+ return label;
147
+ }
148
+ return `\u001B]8;;${url}\u0007${label}\u001B]8;;\u0007`;
149
+ }
150
+
151
+ function colorize(code, text) {
152
+ if (!supportsAnsi()) {
153
+ return text;
154
+ }
155
+ return `${code}${text}\u001B[0m`;
156
+ }
157
+
158
+ function renderBrandArtwork() {
159
+ const brandPath = path.join(repoRoot, 'assets', 'branding', 'deepscientist-mark.png');
160
+ const chafa = resolveExecutableOnPath('chafa');
161
+ if (!supportsAnsi() || !chafa || !fs.existsSync(brandPath)) {
162
+ return [];
163
+ }
164
+ const width = Math.max(18, Math.min(30, Math.floor((process.stdout.columns || 100) / 3)));
165
+ const height = Math.max(8, Math.floor(width / 2));
166
+ try {
167
+ const result = spawnSync(
168
+ chafa,
169
+ ['--size', `${width}x${height}`, '--format', 'symbols', '--colors', '16', brandPath],
170
+ { encoding: 'utf8' }
171
+ );
172
+ if (result.status === 0 && result.stdout && result.stdout.trim()) {
173
+ return result.stdout.replace(/\s+$/, '').split(/\r?\n/);
174
+ }
175
+ } catch {}
176
+ return [];
177
+ }
178
+
179
+ function printLaunchCard({ url, bindUrl, mode, autoOpenRequested, browserOpened, daemonOnly }) {
180
+ const width = Math.max(72, Math.min(process.stdout.columns || 100, 108));
181
+ const divider = colorize('\u001B[38;5;245m', '─'.repeat(Math.max(36, width - 6)));
182
+ const title = colorize('\u001B[1;38;5;39m', 'ResearAI');
183
+ const subtitle = colorize('\u001B[38;5;110m', 'Local-first research operating system');
184
+ const urlLabel = colorize('\u001B[1;38;5;45m', hyperlink(url, url));
185
+ const workspaceMode =
186
+ mode === 'both'
187
+ ? 'Web workspace + terminal workspace'
188
+ : mode === 'tui'
189
+ ? 'Terminal workspace'
190
+ : 'Web workspace';
191
+ const browserLine = autoOpenRequested
192
+ ? browserOpened
193
+ ? 'Browser launch requested successfully.'
194
+ : 'Browser auto-open was requested but is not available in this terminal session.'
195
+ : 'Browser auto-open is disabled. Open the URL manually if needed.';
196
+ const nextStep = daemonOnly
197
+ ? 'Use ds --tui to enter the terminal workspace.'
198
+ : mode === 'web'
199
+ ? 'Use ds --tui to enter the terminal workspace.'
200
+ : mode === 'both'
201
+ ? 'The terminal workspace starts below.'
202
+ : 'Use Ctrl+O inside TUI to reopen the web workspace.';
203
+
204
+ console.log('');
205
+ const artwork = renderBrandArtwork();
206
+ for (const line of artwork) {
207
+ console.log(centerText(line, width));
208
+ }
209
+ if (artwork.length === 0) {
210
+ console.log(centerText(colorize('\u001B[1;38;5;39m', '⛰'), width));
211
+ }
212
+ const wordmark = [
213
+ ' ____ ____ _ _ _ _ ',
214
+ ' | _ \\ ___ ___ _ __ / ___| ___(_) ___ _ __ | |_(_)___| |_ ',
215
+ " | | | |/ _ \\/ _ \\ '_ \\\\___ \\ / __| |/ _ \\ '_ \\| __| / __| __|",
216
+ ' | |_| | __/ __/ |_) |___) | (__| | __/ | | | |_| \\__ \\ |_ ',
217
+ ' |____/ \\___|\\___| .__/|____/ \\___|_|\\___|_| |_|\\__|_|___/\\__|',
218
+ ' |_| ',
219
+ ];
220
+ console.log(centerText(title, width));
221
+ for (const line of wordmark) {
222
+ console.log(centerText(colorize('\u001B[1;38;5;39m', line), width));
223
+ }
224
+ console.log(centerText(subtitle, width));
225
+ console.log('');
226
+ console.log(centerText(divider, width));
227
+ console.log(centerText(colorize('\u001B[1m', workspaceMode), width));
228
+ console.log(centerText(urlLabel, width));
229
+ console.log(centerText(divider, width));
230
+ console.log(centerText(browserLine, width));
231
+ console.log(centerText(`Daemon bind: ${bindUrl}`, width));
232
+ console.log(centerText(nextStep, width));
233
+ console.log(centerText('Run ds --stop to stop the managed daemon.', width));
234
+ console.log('');
235
+ }
236
+
91
237
  function escapeHtml(value) {
92
238
  return String(value ?? '')
93
239
  .replaceAll('&', '&')
@@ -274,13 +420,13 @@ function createCodexPreflightError(home, probe) {
274
420
 
275
421
  function parseLauncherArgs(argv) {
276
422
  const args = [...argv];
277
- let mode = 'both';
423
+ let mode = null;
278
424
  let host = null;
279
425
  let port = null;
280
426
  let home = null;
281
427
  let stop = false;
282
428
  let restart = false;
283
- let openBrowser = false;
429
+ let openBrowser = null;
284
430
  let questId = null;
285
431
  let status = false;
286
432
  let daemonOnly = false;
@@ -305,7 +451,7 @@ function parseLauncherArgs(argv) {
305
451
  else if (arg === '--port' && args[index + 1]) port = Number(args[++index]);
306
452
  else if (arg === '--home' && args[index + 1]) home = path.resolve(args[++index]);
307
453
  else if (arg === '--quest-id' && args[index + 1]) questId = args[++index];
308
- else if (arg === '--mode' && args[index + 1]) mode = args[++index];
454
+ else if (arg === '--mode' && args[index + 1]) mode = normalizeMode(args[++index]);
309
455
  else if (arg === '--help' || arg === '-h') return { help: true };
310
456
  else if (!arg.startsWith('--')) return null;
311
457
  }
@@ -962,30 +1108,53 @@ async function readConfiguredUiAddress(home, venvPython, fallbackHost, fallbackP
962
1108
  const text = result.stdout || '';
963
1109
  const hostMatch = text.match(/^\s*host:\s*["']?([^"'\n]+)["']?\s*$/m);
964
1110
  const portMatch = text.match(/^\s*port:\s*(\d+)\s*$/m);
1111
+ const modeMatch = text.match(/^\s*default_mode:\s*["']?([^"'\n]+)["']?\s*$/m);
1112
+ const autoOpenMatch = text.match(/^\s*auto_open_browser:\s*([^\n]+)\s*$/m);
965
1113
  return {
966
1114
  host: fallbackHost || (hostMatch ? hostMatch[1].trim() : '0.0.0.0'),
967
1115
  port: fallbackPort || (portMatch ? Number(portMatch[1]) : 20999),
1116
+ defaultMode: normalizeMode(modeMatch ? modeMatch[1].trim() : 'web'),
1117
+ autoOpenBrowser: parseBooleanSetting(autoOpenMatch ? autoOpenMatch[1].trim() : true, true),
968
1118
  };
969
1119
  } catch {
970
- return { host: fallbackHost || '0.0.0.0', port: fallbackPort || 20999 };
1120
+ return {
1121
+ host: fallbackHost || '0.0.0.0',
1122
+ port: fallbackPort || 20999,
1123
+ defaultMode: 'web',
1124
+ autoOpenBrowser: true,
1125
+ };
971
1126
  }
972
1127
  }
973
1128
 
974
1129
  function readConfiguredUiAddressFromFile(home, fallbackHost, fallbackPort) {
975
1130
  const configPath = path.join(home, 'config', 'config.yaml');
976
1131
  if (!fs.existsSync(configPath)) {
977
- return { host: fallbackHost || '0.0.0.0', port: fallbackPort || 20999 };
1132
+ return {
1133
+ host: fallbackHost || '0.0.0.0',
1134
+ port: fallbackPort || 20999,
1135
+ defaultMode: 'web',
1136
+ autoOpenBrowser: true,
1137
+ };
978
1138
  }
979
1139
  try {
980
1140
  const text = fs.readFileSync(configPath, 'utf8');
981
1141
  const hostMatch = text.match(/^\s*host:\s*["']?([^"'\n]+)["']?\s*$/m);
982
1142
  const portMatch = text.match(/^\s*port:\s*(\d+)\s*$/m);
1143
+ const modeMatch = text.match(/^\s*default_mode:\s*["']?([^"'\n]+)["']?\s*$/m);
1144
+ const autoOpenMatch = text.match(/^\s*auto_open_browser:\s*([^\n]+)\s*$/m);
983
1145
  return {
984
1146
  host: fallbackHost || (hostMatch ? hostMatch[1].trim() : '0.0.0.0'),
985
1147
  port: fallbackPort || (portMatch ? Number(portMatch[1]) : 20999),
1148
+ defaultMode: normalizeMode(modeMatch ? modeMatch[1].trim() : 'web'),
1149
+ autoOpenBrowser: parseBooleanSetting(autoOpenMatch ? autoOpenMatch[1].trim() : true, true),
986
1150
  };
987
1151
  } catch {
988
- return { host: fallbackHost || '0.0.0.0', port: fallbackPort || 20999 };
1152
+ return {
1153
+ host: fallbackHost || '0.0.0.0',
1154
+ port: fallbackPort || 20999,
1155
+ defaultMode: 'web',
1156
+ autoOpenBrowser: true,
1157
+ };
989
1158
  }
990
1159
  }
991
1160
 
@@ -1080,38 +1249,42 @@ async function startDaemon(home, venvPython, host, port) {
1080
1249
  }
1081
1250
 
1082
1251
  function openBrowser(url) {
1083
- try {
1084
- if (process.platform === 'darwin') {
1085
- const child = spawn('open', [url], { detached: true, stdio: 'ignore' });
1086
- child.on('error', () => {
1087
- console.log(`Open this URL in your browser: ${url}`);
1088
- });
1252
+ const spawnDetached = (command, args) => {
1253
+ try {
1254
+ const child = spawn(command, args, { detached: true, stdio: 'ignore' });
1089
1255
  child.unref();
1090
1256
  return true;
1257
+ } catch {
1258
+ return false;
1091
1259
  }
1092
- if (process.platform === 'win32') {
1093
- const child = spawn('cmd', ['/c', 'start', '', url], { detached: true, stdio: 'ignore' });
1094
- child.on('error', () => {
1095
- console.log(`Open this URL in your browser: ${url}`);
1096
- });
1097
- child.unref();
1098
- return true;
1260
+ };
1261
+
1262
+ if (process.platform === 'darwin') {
1263
+ const opener = resolveExecutableOnPath('open');
1264
+ return opener ? spawnDetached(opener, [url]) : false;
1265
+ }
1266
+ if (process.platform === 'win32') {
1267
+ return spawnDetached('cmd', ['/c', 'start', '', url]);
1268
+ }
1269
+
1270
+ const commands = [
1271
+ { command: 'xdg-open', args: [url] },
1272
+ { command: 'gio', args: ['open', url] },
1273
+ { command: 'sensible-browser', args: [url] },
1274
+ { command: 'gnome-open', args: [url] },
1275
+ { command: 'kde-open', args: [url] },
1276
+ { command: 'kde-open5', args: [url] },
1277
+ ];
1278
+ for (const candidate of commands) {
1279
+ const resolved = resolveExecutableOnPath(candidate.command);
1280
+ if (!resolved) {
1281
+ continue;
1099
1282
  }
1100
- const probe = spawnSync('xdg-open', ['--help'], { stdio: 'ignore' });
1101
- if (probe.error || probe.status !== 0) {
1102
- console.log(`Open this URL in your browser: ${url}`);
1103
- return false;
1283
+ if (spawnDetached(resolved, candidate.args)) {
1284
+ return true;
1104
1285
  }
1105
- const child = spawn('xdg-open', [url], { detached: true, stdio: 'ignore' });
1106
- child.on('error', () => {
1107
- console.log(`Open this URL in your browser: ${url}`);
1108
- });
1109
- child.unref();
1110
- return true;
1111
- } catch {
1112
- console.log(`Open this URL in your browser: ${url}`);
1113
- return false;
1114
1286
  }
1287
+ return false;
1115
1288
  }
1116
1289
 
1117
1290
  function handleCodexPreflightFailure(error) {
@@ -1199,7 +1372,15 @@ async function launcherMain(rawArgs) {
1199
1372
  ensureInitialized(home, venvPython);
1200
1373
  maybePrintOptionalLatexNotice(home);
1201
1374
 
1202
- const { host, port } = await readConfiguredUiAddress(home, venvPython, options.host, options.port);
1375
+ const configuredUi = await readConfiguredUiAddress(home, venvPython, options.host, options.port);
1376
+ const host = configuredUi.host;
1377
+ const port = configuredUi.port;
1378
+ const mode = normalizeMode(options.mode ?? 'web');
1379
+ const shouldOpenBrowser = options.daemonOnly
1380
+ ? false
1381
+ : options.openBrowser === null
1382
+ ? configuredUi.autoOpenBrowser !== false && mode !== 'tui'
1383
+ : options.openBrowser;
1203
1384
  if (options.restart) {
1204
1385
  await stopDaemon(home);
1205
1386
  }
@@ -1212,21 +1393,20 @@ async function launcherMain(rawArgs) {
1212
1393
  if (handleCodexPreflightFailure(error)) return true;
1213
1394
  throw error;
1214
1395
  }
1215
- console.log('');
1216
- console.log('DeepScientist is ready.');
1217
- console.log(`Web: ${started.url}`);
1218
- console.log(`Daemon bind: ${started.bindUrl}`);
1219
- console.log('The web workspace opens automatically when supported.');
1220
- console.log('Use Ctrl+O in TUI to open the web workspace again.');
1221
- console.log('');
1396
+ const browserOpened = shouldOpenBrowser ? openBrowser(started.url) : false;
1397
+ printLaunchCard({
1398
+ url: started.url,
1399
+ bindUrl: started.bindUrl,
1400
+ mode,
1401
+ autoOpenRequested: shouldOpenBrowser,
1402
+ browserOpened,
1403
+ daemonOnly: options.daemonOnly,
1404
+ });
1222
1405
 
1223
- if (options.mode === 'web' || options.mode === 'both' || options.openBrowser) {
1224
- openBrowser(started.url);
1225
- }
1226
1406
  if (options.daemonOnly) {
1227
1407
  process.exit(0);
1228
1408
  }
1229
- if (options.mode === 'web') {
1409
+ if (mode === 'web') {
1230
1410
  process.exit(0);
1231
1411
  }
1232
1412
  launchTui(started.url, options.questId, home, venvPython);
@@ -0,0 +1,134 @@
1
+ # 00 Quick Start: Launch DeepScientist and Run Your First Quest
2
+
3
+ This is the fastest way to go from installation to a running quest.
4
+
5
+ You will do four things:
6
+
7
+ 1. install DeepScientist
8
+ 2. start the local runtime
9
+ 3. create a new quest from the home page
10
+ 4. reopen old quests from the quest list
11
+
12
+ The screenshots in this guide use the current live web UI at `deepscientist.cc:20999` as an example. Your local UI at `127.0.0.1:20999` should look the same or very close.
13
+
14
+ ## 1. Install
15
+
16
+ Install Codex and DeepScientist globally:
17
+
18
+ ```bash
19
+ npm install -g @openai/codex @researai/deepscientist
20
+ ```
21
+
22
+ If you plan to compile LaTeX locally later, you can also install the lightweight PDF runtime:
23
+
24
+ ```bash
25
+ ds latex install-runtime
26
+ ```
27
+
28
+ ## 2. Start DeepScientist
29
+
30
+ Start the local daemon and web workspace:
31
+
32
+ ```bash
33
+ ds
34
+ ```
35
+
36
+ By default, the web UI is served at:
37
+
38
+ ```text
39
+ http://127.0.0.1:20999
40
+ ```
41
+
42
+ If the browser does not open automatically, paste that address into your browser manually.
43
+
44
+ ## 3. Understand the Home Page
45
+
46
+ When DeepScientist starts, open the home page at `/`.
47
+
48
+ ![DeepScientist home page](../images/quickstart/00-home.png)
49
+
50
+ The home page is intentionally simple. The two main entry buttons are:
51
+
52
+ - `Start Research`: create a new quest and launch a new research run
53
+ - `List Quest`: reopen an existing quest
54
+
55
+ If you are using DeepScientist for the first time, start with `Start Research`.
56
+
57
+ ## 4. Create a New Quest With Start Research
58
+
59
+ Click `Start Research` to open the launch dialog.
60
+
61
+ ![Start Research dialog](../images/quickstart/01-start-research.png)
62
+
63
+ This dialog creates a new quest repository and writes the startup contract for the agent.
64
+
65
+ The most important fields are:
66
+
67
+ - `Quest ID`: usually auto-generated in sequence such as `00`, `01`, `02`
68
+ - `Primary request` / research goal: the actual scientific task you want the agent to work on
69
+ - `Reuse Baseline`: optional; choose an existing baseline if you want to continue from an earlier result
70
+ - `Research intensity`: how aggressive the run should be
71
+ - `Decision mode`: `Autonomous` means the agent should keep going by itself unless a true approval is needed
72
+ - `Research paper`: choose whether the run should also aim to produce paper-style output
73
+ - `Language`: choose the user-facing language for the run
74
+
75
+ For a first test, keep it simple:
76
+
77
+ - write one clear research question
78
+ - leave baseline empty unless you already have one
79
+ - use `Balanced` or `Sprint`
80
+ - keep decision mode on `Autonomous`
81
+
82
+ Then click the final `Start Research` action in the dialog.
83
+
84
+ ## 5. Reopen an Existing Quest With List Quest
85
+
86
+ Click `List Quest` on the home page to open the existing quest list.
87
+
88
+ ![List Quest dialog](../images/quickstart/02-list-quest.png)
89
+
90
+ Use this dialog when you want to:
91
+
92
+ - reopen a quest that is already running or already finished
93
+ - search by quest title or quest id
94
+ - jump back into a previous workspace quickly
95
+
96
+ Each row corresponds to one quest repository. Click a quest card to open it.
97
+
98
+ ## 6. What Happens After Opening a Quest
99
+
100
+ After you create or open a quest, DeepScientist takes you to the workspace page for that quest.
101
+
102
+ Inside the workspace, the usual flow is:
103
+
104
+ 1. watch agent progress in Copilot / Studio
105
+ 2. inspect files, notes, and generated artifacts
106
+ 3. use Canvas to understand the current quest graph and stage progress
107
+ 4. stop the run only when you intentionally want to interrupt it
108
+
109
+ ## 7. Useful Runtime Commands
110
+
111
+ Check status:
112
+
113
+ ```bash
114
+ ds --status
115
+ ```
116
+
117
+ Stop the current local daemon:
118
+
119
+ ```bash
120
+ ds --stop
121
+ ```
122
+
123
+ Run diagnostics if something looks broken:
124
+
125
+ ```bash
126
+ ds doctor
127
+ ```
128
+
129
+ ## 8. What To Read Next
130
+
131
+ - [01 Settings Reference: Configure DeepScientist](./01_SETTINGS_REFERENCE.md)
132
+ - [02 Start Research Guide: Fill the Start Research Contract](./02_START_RESEARCH_GUIDE.md)
133
+ - [03 QQ Connector Guide: Use QQ With DeepScientist](./03_QQ_CONNECTOR_GUIDE.md)
134
+ - [05 TUI Guide: Use the Terminal Interface](./05_TUI_GUIDE.md)