@researai/deepscientist 1.5.8 → 1.5.11

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 (148) hide show
  1. package/LICENSE +186 -21
  2. package/README.md +108 -95
  3. package/assets/branding/connector-qq.png +0 -0
  4. package/assets/branding/connector-rokid.png +0 -0
  5. package/assets/branding/connector-weixin.png +0 -0
  6. package/assets/branding/projects.png +0 -0
  7. package/bin/ds.js +172 -13
  8. package/docs/assets/branding/projects.png +0 -0
  9. package/docs/en/00_QUICK_START.md +308 -70
  10. package/docs/en/01_SETTINGS_REFERENCE.md +3 -0
  11. package/docs/en/02_START_RESEARCH_GUIDE.md +112 -0
  12. package/docs/en/04_LINGZHU_CONNECTOR_GUIDE.md +62 -179
  13. package/docs/en/09_DOCTOR.md +41 -5
  14. package/docs/en/10_WEIXIN_CONNECTOR_GUIDE.md +137 -0
  15. package/docs/en/11_LICENSE_AND_RISK.md +256 -0
  16. package/docs/en/12_GUIDED_WORKFLOW_TOUR.md +427 -0
  17. package/docs/en/13_CORE_ARCHITECTURE_GUIDE.md +297 -0
  18. package/docs/en/14_PROMPT_SKILLS_AND_MCP_GUIDE.md +506 -0
  19. package/docs/en/99_ACKNOWLEDGEMENTS.md +4 -1
  20. package/docs/en/README.md +79 -0
  21. package/docs/images/lingzhu/rokid-agent-platform-create.png +0 -0
  22. package/docs/images/weixin/weixin-plugin-entry.png +0 -0
  23. package/docs/images/weixin/weixin-plugin-entry.svg +33 -0
  24. package/docs/images/weixin/weixin-qr-confirm.svg +30 -0
  25. package/docs/images/weixin/weixin-quest-media-flow.svg +44 -0
  26. package/docs/images/weixin/weixin-settings-bind.svg +57 -0
  27. package/docs/zh/00_QUICK_START.md +315 -74
  28. package/docs/zh/01_SETTINGS_REFERENCE.md +3 -0
  29. package/docs/zh/02_START_RESEARCH_GUIDE.md +112 -0
  30. package/docs/zh/04_LINGZHU_CONNECTOR_GUIDE.md +62 -193
  31. package/docs/zh/09_DOCTOR.md +41 -5
  32. package/docs/zh/10_WEIXIN_CONNECTOR_GUIDE.md +144 -0
  33. package/docs/zh/11_LICENSE_AND_RISK.md +256 -0
  34. package/docs/zh/12_GUIDED_WORKFLOW_TOUR.md +423 -0
  35. package/docs/zh/13_CORE_ARCHITECTURE_GUIDE.md +296 -0
  36. package/docs/zh/14_PROMPT_SKILLS_AND_MCP_GUIDE.md +506 -0
  37. package/docs/zh/99_ACKNOWLEDGEMENTS.md +4 -1
  38. package/docs/zh/README.md +126 -0
  39. package/install.sh +0 -34
  40. package/package.json +3 -3
  41. package/pyproject.toml +2 -2
  42. package/src/deepscientist/__init__.py +1 -1
  43. package/src/deepscientist/annotations.py +343 -0
  44. package/src/deepscientist/artifact/arxiv.py +484 -37
  45. package/src/deepscientist/artifact/metrics.py +1 -3
  46. package/src/deepscientist/artifact/service.py +1347 -111
  47. package/src/deepscientist/arxiv_library.py +275 -0
  48. package/src/deepscientist/bash_exec/service.py +9 -0
  49. package/src/deepscientist/bridges/builtins.py +2 -0
  50. package/src/deepscientist/bridges/connectors.py +447 -0
  51. package/src/deepscientist/channels/__init__.py +2 -0
  52. package/src/deepscientist/channels/builtins.py +3 -1
  53. package/src/deepscientist/channels/qq.py +1 -1
  54. package/src/deepscientist/channels/qq_gateway.py +1 -1
  55. package/src/deepscientist/channels/relay.py +7 -1
  56. package/src/deepscientist/channels/weixin.py +59 -0
  57. package/src/deepscientist/channels/weixin_ilink.py +317 -0
  58. package/src/deepscientist/config/models.py +22 -2
  59. package/src/deepscientist/config/service.py +431 -60
  60. package/src/deepscientist/connector/__init__.py +4 -0
  61. package/src/deepscientist/connector/connector_profiles.py +481 -0
  62. package/src/deepscientist/connector/lingzhu_support.py +668 -0
  63. package/src/deepscientist/connector/qq_profiles.py +206 -0
  64. package/src/deepscientist/connector/weixin_support.py +663 -0
  65. package/src/deepscientist/connector_profiles.py +1 -374
  66. package/src/deepscientist/connector_runtime.py +2 -0
  67. package/src/deepscientist/daemon/api/handlers.py +295 -5
  68. package/src/deepscientist/daemon/api/router.py +16 -1
  69. package/src/deepscientist/daemon/app.py +1130 -61
  70. package/src/deepscientist/doctor.py +5 -2
  71. package/src/deepscientist/gitops/diff.py +120 -29
  72. package/src/deepscientist/lingzhu_support.py +1 -182
  73. package/src/deepscientist/mcp/server.py +14 -5
  74. package/src/deepscientist/prompts/builder.py +29 -1
  75. package/src/deepscientist/qq_profiles.py +1 -196
  76. package/src/deepscientist/quest/node_traces.py +152 -2
  77. package/src/deepscientist/quest/service.py +169 -43
  78. package/src/deepscientist/quest/stage_views.py +172 -9
  79. package/src/deepscientist/registries/baseline.py +56 -4
  80. package/src/deepscientist/runners/codex.py +55 -3
  81. package/src/deepscientist/weixin_support.py +1 -0
  82. package/src/prompts/connectors/lingzhu.md +3 -1
  83. package/src/prompts/connectors/weixin.md +230 -0
  84. package/src/prompts/system.md +9 -0
  85. package/src/skills/idea/SKILL.md +16 -0
  86. package/src/skills/idea/references/literature-survey-template.md +24 -0
  87. package/src/skills/idea/references/related-work-playbook.md +4 -0
  88. package/src/skills/idea/references/selection-gate.md +9 -0
  89. package/src/skills/write/SKILL.md +1 -1
  90. package/src/tui/package.json +1 -1
  91. package/src/ui/dist/assets/{AiManusChatView-m2FNtwbn.js → AiManusChatView-D0mTXG4-.js} +156 -48
  92. package/src/ui/dist/assets/{AnalysisPlugin-BMTF8EGL.js → AnalysisPlugin-Db0cTXxm.js} +1 -1
  93. package/src/ui/dist/assets/{CliPlugin-BEOWgxCI.js → CliPlugin-DrV8je02.js} +164 -9
  94. package/src/ui/dist/assets/{CodeEditorPlugin-BCXvjqmb.js → CodeEditorPlugin-QXMSCH71.js} +8 -8
  95. package/src/ui/dist/assets/{CodeViewerPlugin-DaJcy3nD.js → CodeViewerPlugin-7hhtWj_E.js} +5 -5
  96. package/src/ui/dist/assets/{DocViewerPlugin-ByfeIq4K.js → DocViewerPlugin-BWMSnRJe.js} +3 -3
  97. package/src/ui/dist/assets/{GitDiffViewerPlugin-Cksf3VZ-.js → GitDiffViewerPlugin-7J9h9Vy_.js} +20 -21
  98. package/src/ui/dist/assets/{ImageViewerPlugin-CFz-OsTS.js → ImageViewerPlugin-CHJl_0lr.js} +5 -5
  99. package/src/ui/dist/assets/{LabCopilotPanel-CJ1cJzoX.js → LabCopilotPanel-1qSow1es.js} +11 -11
  100. package/src/ui/dist/assets/{LabPlugin-BF3dVJwa.js → LabPlugin-eQpPPCEp.js} +2 -1
  101. package/src/ui/dist/assets/{LatexPlugin-DDkwZ6Sj.js → LatexPlugin-BwRfi89Z.js} +7 -7
  102. package/src/ui/dist/assets/{MarkdownViewerPlugin-HAuvurcT.js → MarkdownViewerPlugin-836PVQWV.js} +4 -4
  103. package/src/ui/dist/assets/{MarketplacePlugin-BtoTYy2C.js → MarketplacePlugin-C2y_556i.js} +3 -3
  104. package/src/ui/dist/assets/{NotebookEditor-CSJYx7b-.js → NotebookEditor-BRzJbGsn.js} +12 -12
  105. package/src/ui/dist/assets/{NotebookEditor-DQgRezm_.js → NotebookEditor-DIX7Mlzu.js} +1 -1
  106. package/src/ui/dist/assets/{PdfLoader-DPa_-fv6.js → PdfLoader-DzRaTAlq.js} +14 -7
  107. package/src/ui/dist/assets/{PdfMarkdownPlugin-BZpXOEjm.js → PdfMarkdownPlugin-DZUfIUnp.js} +73 -6
  108. package/src/ui/dist/assets/{PdfViewerPlugin-BT8a6wGR.js → PdfViewerPlugin-BwtICzue.js} +103 -34
  109. package/src/ui/dist/assets/PdfViewerPlugin-DQ11QcSf.css +3627 -0
  110. package/src/ui/dist/assets/{SearchPlugin-D_blveZi.js → SearchPlugin-DHeIAMsx.js} +1 -1
  111. package/src/ui/dist/assets/{TextViewerPlugin-Btx0M3hX.js → TextViewerPlugin-C3tCmFox.js} +5 -4
  112. package/src/ui/dist/assets/{VNCViewer-DImJO4rO.js → VNCViewer-CQsKVm3t.js} +10 -10
  113. package/src/ui/dist/assets/bot-BEA2vWuK.js +21 -0
  114. package/src/ui/dist/assets/branding/logo-rokid.png +0 -0
  115. package/src/ui/dist/assets/browser-BAcuE0Xj.js +2895 -0
  116. package/src/ui/dist/assets/{code-BUfXGJSl.js → code-XfbSR8K2.js} +1 -1
  117. package/src/ui/dist/assets/{file-content-VqamwI3X.js → file-content-BjxNaIfy.js} +1 -1
  118. package/src/ui/dist/assets/{file-diff-panel-C_wOoS7a.js → file-diff-panel-D_lLVQk0.js} +1 -1
  119. package/src/ui/dist/assets/{file-socket-D2bTuMVP.js → file-socket-D9x_5vlY.js} +1 -1
  120. package/src/ui/dist/assets/{image-BZkGJ4mM.js → image-BhWT33W1.js} +1 -1
  121. package/src/ui/dist/assets/{index-DdRW6RMJ.js → index--c4iXtuy.js} +12 -12
  122. package/src/ui/dist/assets/{index-CxkvSeKw.js → index-BDxipwrC.js} +2 -2
  123. package/src/ui/dist/assets/{index-DjggJovS.js → index-DZTZ8mWP.js} +14934 -9613
  124. package/src/ui/dist/assets/{index-DXZ1daiJ.css → index-Dqj-Mjb4.css} +2 -13
  125. package/src/ui/dist/assets/index-PJbSbPTy.js +25 -0
  126. package/src/ui/dist/assets/{monaco-DHMc7kKM.js → monaco-K8izTGgo.js} +1 -1
  127. package/src/ui/dist/assets/{pdf-effect-queue-DSw_D3RV.js → pdf-effect-queue-DfBors6y.js} +16 -1
  128. package/src/ui/dist/assets/pdf.worker.min-yatZIOMy.mjs +21 -0
  129. package/src/ui/dist/assets/{popover-B85oCgCS.js → popover-yFK1J4fL.js} +1 -1
  130. package/src/ui/dist/assets/{project-sync-DOMCcPac.js → project-sync-PENr2zcz.js} +1 -74
  131. package/src/ui/dist/assets/select-CAbJDfYv.js +1690 -0
  132. package/src/ui/dist/assets/{sigma-BO2rQrl3.js → sigma-DEuYJqTl.js} +1 -1
  133. package/src/ui/dist/assets/{index-D9QIGcmc.js → square-check-big-omoSUmcd.js} +2 -13
  134. package/src/ui/dist/assets/{trash-BsVEH_dV.js → trash--F119N47.js} +1 -1
  135. package/src/ui/dist/assets/{useCliAccess-b8L6JuZm.js → useCliAccess-D31UR23I.js} +1 -1
  136. package/src/ui/dist/assets/{useFileDiffOverlay-BY7uA9hV.js → useFileDiffOverlay-BH6KcMzq.js} +1 -1
  137. package/src/ui/dist/assets/{wrap-text-BwyVuUIK.js → wrap-text-CZ613PM5.js} +1 -1
  138. package/src/ui/dist/assets/{zoom-out-RDpLugQP.js → zoom-out-BgDLAv3z.js} +1 -1
  139. package/src/ui/dist/index.html +2 -2
  140. package/src/ui/dist/assets/AutoFigurePlugin-BGxN8Umr.css +0 -3056
  141. package/src/ui/dist/assets/AutoFigurePlugin-DxPdMUNb.js +0 -8149
  142. package/src/ui/dist/assets/PdfViewerPlugin-BJXtIwj_.css +0 -260
  143. package/src/ui/dist/assets/Stepper-DH2k75Vo.js +0 -158
  144. package/src/ui/dist/assets/bibtex-B-Hqu0Sg.js +0 -189
  145. package/src/ui/dist/assets/file-utils--zJCPN1i.js +0 -109
  146. package/src/ui/dist/assets/message-square-FUIPIhU2.js +0 -16
  147. package/src/ui/dist/assets/pdfjs-DU1YE8WO.js +0 -3
  148. package/src/ui/dist/assets/tooltip-B1OspAkx.js +0 -108
package/bin/ds.js CHANGED
@@ -81,7 +81,7 @@ Launcher flags:
81
81
  --stop Stop the managed daemon
82
82
  --restart Restart the managed daemon
83
83
  --home <path> Use a custom DeepScientist home
84
- --here Use the current working directory as DeepScientist home
84
+ --here Create/use ./DeepScientist under the current working directory as home
85
85
  --proxy <url> Use an outbound HTTP/WS proxy for npm and Python runtime traffic
86
86
  --yolo Run Codex in YOLO mode: approval_policy=never and sandbox_mode=danger-full-access
87
87
  --quest-id <id> Open the TUI on one quest directly
@@ -467,7 +467,7 @@ function resolveHome(args) {
467
467
  return path.resolve(args[index + 1]);
468
468
  }
469
469
  if (args.includes('--here')) {
470
- return process.cwd();
470
+ return path.join(process.cwd(), 'DeepScientist');
471
471
  }
472
472
  if (process.env.DEEPSCIENTIST_HOME) {
473
473
  return path.resolve(process.env.DEEPSCIENTIST_HOME);
@@ -564,6 +564,12 @@ function colorize(code, text) {
564
564
  return `${code}${text}\u001B[0m`;
565
565
  }
566
566
 
567
+ const OFFICIAL_REPOSITORY_URL = 'https://github.com/ResearAI/DeepScientist';
568
+
569
+ function officialRepositoryLine() {
570
+ return `Official open-source repository: ${hyperlink(OFFICIAL_REPOSITORY_URL, OFFICIAL_REPOSITORY_URL)}`;
571
+ }
572
+
567
573
  function renderBrandArtwork() {
568
574
  const brandPath = path.join(repoRoot, 'assets', 'branding', 'deepscientist-mark.png');
569
575
  const chafa = resolveExecutableOnPath('chafa');
@@ -638,10 +644,10 @@ function renderLaunchHints({ home, url, bindUrl, pythonSelection, yolo }) {
638
644
 
639
645
  console.log(colorize('\u001B[1;38;5;39m', 'Quick Flags'));
640
646
  renderKeyValueRows([
641
- ['ds --yolo --port 20999 --here', 'Start in the current directory with YOLO Codex access'],
647
+ ['ds --yolo --port 20999 --here', 'Start in ./DeepScientist under the current directory with YOLO Codex access'],
642
648
  ['ds --port 21000', 'Change the web port'],
643
649
  ['ds --host 0.0.0.0 --port 21000', 'Bind on all interfaces'],
644
- ['ds --here', 'Use the current directory as home'],
650
+ ['ds --here', 'Use ./DeepScientist under the current directory as home'],
645
651
  ['ds --both', 'Start web + TUI together'],
646
652
  ['ds --tui', 'Start the terminal workspace only'],
647
653
  ['ds --no-browser', 'Do not auto-open the browser'],
@@ -668,7 +674,10 @@ function printLaunchCard({
668
674
  const width = Math.max(72, Math.min(process.stdout.columns || 100, 108));
669
675
  const divider = colorize('\u001B[38;5;245m', '─'.repeat(Math.max(36, width - 6)));
670
676
  const title = colorize('\u001B[1;38;5;39m', 'ResearAI');
671
- const subtitle = colorize('\u001B[38;5;110m', 'Local-first research operating system');
677
+ const subtitleLines = [
678
+ colorize('\u001B[38;5;110m', 'DeepScientist is not just a fully open-source autonomous scientific discovery system.'),
679
+ colorize('\u001B[38;5;110m', 'It is also a research map that keeps growing from every round.'),
680
+ ];
672
681
  const versionLine = colorize('\u001B[38;5;245m', `Version ${packageJson.version}`);
673
682
  const urlLabel = colorize('\u001B[1;38;5;45m', hyperlink(url, url));
674
683
  const workspaceMode =
@@ -711,7 +720,9 @@ function printLaunchCard({
711
720
  for (const line of wordmark) {
712
721
  console.log(centerText(colorize('\u001B[1;38;5;39m', line), width));
713
722
  }
714
- console.log(centerText(subtitle, width));
723
+ for (const line of subtitleLines) {
724
+ console.log(centerText(line, width));
725
+ }
715
726
  console.log('');
716
727
  console.log(centerText(divider, width));
717
728
  console.log(centerText(colorize('\u001B[1m', workspaceMode), width));
@@ -721,6 +732,7 @@ function printLaunchCard({
721
732
  console.log(centerText(nextStep, width));
722
733
  console.log(centerText('Run ds --stop to stop the managed daemon.', width));
723
734
  console.log(centerText('Need to move this installation later? Use ds migrate /new/path.', width));
735
+ console.log(centerText(officialRepositoryLine(), width));
724
736
  console.log('');
725
737
  renderLaunchHints({ home, url, bindUrl, pythonSelection, yolo });
726
738
  }
@@ -802,8 +814,8 @@ function writeCodexPreflightReport(home, probe) {
802
814
  <main class="page">
803
815
  <section class="panel">
804
816
  <h1>DeepScientist could not start Codex</h1>
805
- <p class="meta">DeepScientist blocked startup because the Codex hello probe did not pass. Please run <code>codex</code>, complete login, then launch <code>ds</code> again.</p>
806
- <p class="meta">DeepScientist 启动前进行了 Codex 可用性检查,但 hello 探测没有通过。请先手动运行 <code>codex</code> 并完成登录,再重新启动 <code>ds</code>。</p>
817
+ <p class="meta">DeepScientist blocked startup because the Codex hello probe did not pass. In most installs, <code>npm install -g @researai/deepscientist</code> also installs the bundled Codex dependency. If <code>codex</code> is still missing, repair it with <code>npm install -g @openai/codex</code>. Then run <code>codex --login</code> (or <code>codex</code>), finish authentication, run <code>ds doctor</code>, and launch <code>ds</code> again.</p>
818
+ <p class="meta">DeepScientist 启动前进行了 Codex 可用性检查,但 hello 探测没有通过。正常情况下,<code>npm install -g @researai/deepscientist</code> 也会一并安装 bundled Codex 依赖;如果此后 <code>codex</code> 仍不可用,请再执行 <code>npm install -g @openai/codex</code> 修复。然后运行 <code>codex --login</code>(或 <code>codex</code>)完成认证,再执行 <code>ds doctor</code>,最后重新启动 <code>ds</code>。</p>
807
819
 
808
820
  <h2>Summary</h2>
809
821
  <p>${escapeHtml(probe?.summary || 'Codex startup probe failed.')}</p>
@@ -1002,6 +1014,8 @@ Flags:
1002
1014
  --force-check Ignore the cached version probe
1003
1015
  --remind-later Defer prompts for the current published version
1004
1016
  --skip-version Skip reminders for the current published version
1017
+
1018
+ Without \`--yes\`, \`ds update\` will ask for a \`Y/N\` confirmation on interactive terminals.
1005
1019
  `);
1006
1020
  }
1007
1021
 
@@ -2769,6 +2783,33 @@ function printUpdateStatus(status, { compact = false } = {}) {
2769
2783
  }
2770
2784
  }
2771
2785
 
2786
+ function parseYesNoAnswer(answer, defaultValue = false) {
2787
+ const normalized = String(answer || '').trim().toLowerCase();
2788
+ if (!normalized) {
2789
+ return defaultValue;
2790
+ }
2791
+ if (normalized === 'y' || normalized === 'yes') {
2792
+ return true;
2793
+ }
2794
+ if (normalized === 'n' || normalized === 'no') {
2795
+ return false;
2796
+ }
2797
+ return defaultValue;
2798
+ }
2799
+
2800
+ async function promptYesNo(question, { defaultValue = false } = {}) {
2801
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
2802
+ return defaultValue;
2803
+ }
2804
+ return new Promise((resolve) => {
2805
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
2806
+ rl.question(question, (answer) => {
2807
+ rl.close();
2808
+ resolve(parseYesNoAnswer(answer, defaultValue));
2809
+ });
2810
+ });
2811
+ }
2812
+
2772
2813
  function spawnDetachedNode(args, options = {}) {
2773
2814
  const out = options.logPath ? fs.openSync(options.logPath, 'a') : 'ignore';
2774
2815
  const child = spawn(process.execPath, args, {
@@ -2965,6 +3006,50 @@ async function performSelfUpdate(home, options = {}) {
2965
3006
  };
2966
3007
  }
2967
3008
 
3009
+ function normalizeLauncherRelaunchArgs(rawArgs, home) {
3010
+ const normalized = [];
3011
+ for (let index = 0; index < rawArgs.length; index += 1) {
3012
+ const arg = rawArgs[index];
3013
+ if (arg === '--home') {
3014
+ index += 1;
3015
+ continue;
3016
+ }
3017
+ if (arg === '--here' || arg === '--skip-update-check') {
3018
+ continue;
3019
+ }
3020
+ normalized.push(arg);
3021
+ }
3022
+ return ['--home', home, ...normalized, '--skip-update-check'];
3023
+ }
3024
+
3025
+ function relaunchLauncherAfterUpdate(rawArgs, home) {
3026
+ const launcherPath = resolveLauncherPath();
3027
+ if (!launcherPath) {
3028
+ return {
3029
+ ok: false,
3030
+ exitCode: 1,
3031
+ message: 'DeepScientist was updated, but the new launcher path could not be resolved for relaunch.',
3032
+ };
3033
+ }
3034
+ const result = spawnSync(process.execPath, [launcherPath, ...normalizeLauncherRelaunchArgs(rawArgs, home)], {
3035
+ cwd: repoRoot,
3036
+ stdio: 'inherit',
3037
+ env: process.env,
3038
+ });
3039
+ if (result.error) {
3040
+ return {
3041
+ ok: false,
3042
+ exitCode: 1,
3043
+ message: result.error.message,
3044
+ };
3045
+ }
3046
+ return {
3047
+ ok: true,
3048
+ exitCode: result.status ?? 0,
3049
+ message: null,
3050
+ };
3051
+ }
3052
+
2968
3053
  async function maybeHandleStartupUpdate(home, rawArgs, options = {}) {
2969
3054
  if (options.skipUpdateCheck || process.env.DS_SKIP_UPDATE_PROMPT === '1') {
2970
3055
  return false;
@@ -2978,8 +3063,43 @@ async function maybeHandleStartupUpdate(home, rawArgs, options = {}) {
2978
3063
  }
2979
3064
 
2980
3065
  printUpdateStatus(status, { compact: true });
2981
- markUpdateDeferred(home, status.latest_version);
2982
- return false;
3066
+ if (!status.can_self_update || !process.stdin.isTTY || !process.stdout.isTTY) {
3067
+ markUpdateDeferred(home, status.latest_version);
3068
+ return false;
3069
+ }
3070
+
3071
+ const confirmed = await promptYesNo(`Install DeepScientist ${status.latest_version} now? [y/N]: `, {
3072
+ defaultValue: false,
3073
+ });
3074
+ if (!confirmed) {
3075
+ markUpdateDeferred(home, status.latest_version);
3076
+ console.log(`DeepScientist will remind you later about ${status.latest_version || 'the next release'}.`);
3077
+ return false;
3078
+ }
3079
+
3080
+ console.log('Updating DeepScientist now...');
3081
+ const payload = await performSelfUpdate(home, {
3082
+ host: options.host,
3083
+ port: options.port,
3084
+ restartDaemon: false,
3085
+ });
3086
+ console.log(payload.message);
3087
+ if (payload.log_path) {
3088
+ console.log(`Update log: ${payload.log_path}`);
3089
+ }
3090
+ if (!payload.ok) {
3091
+ console.log('DeepScientist will continue launching with the current session.');
3092
+ return false;
3093
+ }
3094
+
3095
+ console.log('Relaunching DeepScientist...');
3096
+ const relaunch = relaunchLauncherAfterUpdate(rawArgs, home);
3097
+ if (!relaunch.ok) {
3098
+ console.error(relaunch.message);
3099
+ process.exit(relaunch.exitCode || 1);
3100
+ }
3101
+ process.exit(relaunch.exitCode || 0);
3102
+ return true;
2983
3103
  }
2984
3104
 
2985
3105
  async function startBackgroundUpdateWorker(home, options = {}) {
@@ -3244,14 +3364,27 @@ function handleCodexPreflightFailure(error) {
3244
3364
  if (!error || error.code !== 'DS_CODEX_PREFLIGHT') {
3245
3365
  return false;
3246
3366
  }
3367
+ const errorLabel = colorize('\u001B[1;38;5;196m', 'ERROR');
3368
+ const warningLabel = colorize('\u001B[1;38;5;214m', 'WARNING');
3247
3369
  console.error('');
3248
- console.error('DeepScientist could not start because Codex is not ready yet.');
3370
+ console.error(`${errorLabel} DeepScientist could not start because Codex is not ready yet.`);
3249
3371
  console.error(`Report: ${error.reportPath}`);
3250
3372
  if (Array.isArray(error.probe?.errors)) {
3251
3373
  for (const item of error.probe.errors) {
3252
- console.error(` - ${item}`);
3374
+ console.error(`${errorLabel} ${item}`);
3375
+ }
3376
+ }
3377
+ if (Array.isArray(error.probe?.warnings)) {
3378
+ for (const item of error.probe.warnings) {
3379
+ console.error(`${warningLabel} ${item}`);
3253
3380
  }
3254
3381
  }
3382
+ console.error(`${warningLabel} Recommended fix:`);
3383
+ console.error(`${warningLabel} 1. In most installs, \`npm install -g @researai/deepscientist\` also installs the bundled Codex dependency.`);
3384
+ console.error(`${warningLabel} 2. If \`codex\` is still missing, run \`npm install -g @openai/codex\`.`);
3385
+ console.error(`${warningLabel} 3. Run \`codex --login\` (or \`codex\`) and finish authentication.`);
3386
+ console.error(`${warningLabel} 4. Run \`ds doctor\` and confirm the Codex check passes.`);
3387
+ console.error(`${warningLabel} 5. Run \`ds\` again.`);
3255
3388
  openBrowser(error.reportUrl);
3256
3389
  process.exit(1);
3257
3390
  return true;
@@ -3375,7 +3508,29 @@ async function updateMain(rawArgs) {
3375
3508
  process.exit(0);
3376
3509
  }
3377
3510
  printUpdateStatus(status, { compact: true });
3378
- process.exit(0);
3511
+ if (!status.can_self_update) {
3512
+ process.exit(0);
3513
+ }
3514
+
3515
+ const confirmed = await promptYesNo(`Install DeepScientist ${status.latest_version} now? [y/N]: `, {
3516
+ defaultValue: false,
3517
+ });
3518
+ if (!confirmed) {
3519
+ const payload = markUpdateDeferred(home, status.latest_version);
3520
+ console.log(`DeepScientist will remind you later about ${payload.latest_version || 'the next release'}.`);
3521
+ process.exit(0);
3522
+ }
3523
+
3524
+ const payload = await performSelfUpdate(home, {
3525
+ host: options.host,
3526
+ port: options.port,
3527
+ restartDaemon: options.restartDaemon,
3528
+ });
3529
+ console.log(payload.message);
3530
+ if (payload.log_path) {
3531
+ console.log(`Update log: ${payload.log_path}`);
3532
+ }
3533
+ process.exit(payload.ok ? 0 : 1);
3379
3534
  }
3380
3535
 
3381
3536
  async function migrateMain(rawArgs) {
@@ -3680,6 +3835,10 @@ module.exports = {
3680
3835
  detectInstallMode,
3681
3836
  updateManualCommand,
3682
3837
  buildUpdateStatus,
3838
+ parseYesNoAnswer,
3839
+ normalizeLauncherRelaunchArgs,
3840
+ officialRepositoryLine,
3841
+ stripAnsi,
3683
3842
  },
3684
3843
  };
3685
3844