@researai/deepscientist 1.5.1 → 1.5.3

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 (116) hide show
  1. package/README.md +69 -1
  2. package/bin/ds.js +2239 -153
  3. package/docs/en/00_QUICK_START.md +60 -20
  4. package/docs/en/01_SETTINGS_REFERENCE.md +20 -20
  5. package/docs/en/02_START_RESEARCH_GUIDE.md +11 -11
  6. package/docs/en/03_QQ_CONNECTOR_GUIDE.md +10 -10
  7. package/docs/en/05_TUI_GUIDE.md +1 -1
  8. package/docs/en/09_DOCTOR.md +48 -4
  9. package/docs/en/90_ARCHITECTURE.md +4 -2
  10. package/docs/zh/00_QUICK_START.md +60 -20
  11. package/docs/zh/01_SETTINGS_REFERENCE.md +21 -21
  12. package/docs/zh/02_START_RESEARCH_GUIDE.md +19 -19
  13. package/docs/zh/03_QQ_CONNECTOR_GUIDE.md +10 -10
  14. package/docs/zh/05_TUI_GUIDE.md +1 -1
  15. package/docs/zh/09_DOCTOR.md +46 -4
  16. package/install.sh +125 -8
  17. package/package.json +2 -1
  18. package/pyproject.toml +1 -1
  19. package/src/deepscientist/__init__.py +6 -1
  20. package/src/deepscientist/artifact/service.py +553 -26
  21. package/src/deepscientist/bash_exec/monitor.py +23 -4
  22. package/src/deepscientist/bash_exec/runtime.py +3 -0
  23. package/src/deepscientist/bash_exec/service.py +132 -4
  24. package/src/deepscientist/bridges/base.py +10 -19
  25. package/src/deepscientist/channels/discord_gateway.py +25 -2
  26. package/src/deepscientist/channels/feishu_long_connection.py +41 -3
  27. package/src/deepscientist/channels/qq.py +524 -64
  28. package/src/deepscientist/channels/qq_gateway.py +22 -3
  29. package/src/deepscientist/channels/relay.py +429 -90
  30. package/src/deepscientist/channels/slack_socket.py +29 -5
  31. package/src/deepscientist/channels/telegram_polling.py +25 -2
  32. package/src/deepscientist/channels/whatsapp_local_session.py +32 -4
  33. package/src/deepscientist/cli.py +27 -0
  34. package/src/deepscientist/config/models.py +6 -40
  35. package/src/deepscientist/config/service.py +165 -156
  36. package/src/deepscientist/connector_profiles.py +346 -0
  37. package/src/deepscientist/connector_runtime.py +88 -43
  38. package/src/deepscientist/daemon/api/handlers.py +65 -11
  39. package/src/deepscientist/daemon/api/router.py +4 -2
  40. package/src/deepscientist/daemon/app.py +772 -219
  41. package/src/deepscientist/doctor.py +69 -2
  42. package/src/deepscientist/gitops/diff.py +3 -0
  43. package/src/deepscientist/home.py +25 -2
  44. package/src/deepscientist/mcp/context.py +3 -1
  45. package/src/deepscientist/mcp/server.py +66 -7
  46. package/src/deepscientist/migration.py +114 -0
  47. package/src/deepscientist/prompts/builder.py +71 -3
  48. package/src/deepscientist/qq_profiles.py +186 -0
  49. package/src/deepscientist/quest/layout.py +1 -0
  50. package/src/deepscientist/quest/service.py +70 -12
  51. package/src/deepscientist/quest/stage_views.py +46 -0
  52. package/src/deepscientist/runners/codex.py +2 -0
  53. package/src/deepscientist/shared.py +44 -17
  54. package/src/prompts/connectors/lingzhu.md +3 -0
  55. package/src/prompts/connectors/qq.md +42 -2
  56. package/src/prompts/system.md +123 -10
  57. package/src/skills/analysis-campaign/SKILL.md +35 -6
  58. package/src/skills/baseline/SKILL.md +73 -32
  59. package/src/skills/decision/SKILL.md +4 -3
  60. package/src/skills/experiment/SKILL.md +28 -6
  61. package/src/skills/finalize/SKILL.md +5 -2
  62. package/src/skills/idea/SKILL.md +2 -2
  63. package/src/skills/intake-audit/SKILL.md +2 -2
  64. package/src/skills/rebuttal/SKILL.md +4 -2
  65. package/src/skills/review/SKILL.md +4 -2
  66. package/src/skills/scout/SKILL.md +2 -2
  67. package/src/skills/write/SKILL.md +2 -2
  68. package/src/tui/package.json +1 -1
  69. package/src/ui/dist/assets/{AiManusChatView-w5lF2Ttt.js → AiManusChatView-qzChi9uh.js} +67 -94
  70. package/src/ui/dist/assets/{AnalysisPlugin-DJOED79I.js → AnalysisPlugin-CcC_-UqN.js} +1 -1
  71. package/src/ui/dist/assets/{AutoFigurePlugin-DaG61Y0M.js → AutoFigurePlugin-DD8LkJLe.js} +5 -5
  72. package/src/ui/dist/assets/{CliPlugin-CV4LqUB_.js → CliPlugin-DJJFfVmW.js} +17 -110
  73. package/src/ui/dist/assets/{CodeEditorPlugin-DylfAea4.js → CodeEditorPlugin-CrjkHNLh.js} +8 -8
  74. package/src/ui/dist/assets/{CodeViewerPlugin-F7saY0LM.js → CodeViewerPlugin-obnD6G5R.js} +5 -5
  75. package/src/ui/dist/assets/{DocViewerPlugin-COP0c7jf.js → DocViewerPlugin-DB9SUQVd.js} +3 -3
  76. package/src/ui/dist/assets/{GitDiffViewerPlugin-CAS05pT9.js → GitDiffViewerPlugin-DZLlNlD2.js} +1 -1
  77. package/src/ui/dist/assets/{ImageViewerPlugin-Bco1CN_w.js → ImageViewerPlugin-BGwfDZ0Y.js} +5 -5
  78. package/src/ui/dist/assets/{LabCopilotPanel-CvMlCD99.js → LabCopilotPanel-dfLptQcR.js} +10 -10
  79. package/src/ui/dist/assets/{LabPlugin-BYankkE4.js → LabPlugin-CeGjAl3A.js} +1 -1
  80. package/src/ui/dist/assets/{LatexPlugin-LDSMR-t-.js → LatexPlugin-BBJ7kd1V.js} +7 -7
  81. package/src/ui/dist/assets/{MarkdownViewerPlugin-B7o80jgm.js → MarkdownViewerPlugin-DKZi7BcB.js} +4 -4
  82. package/src/ui/dist/assets/{MarketplacePlugin-CM6ZOcpC.js → MarketplacePlugin-C_k-9jD0.js} +3 -3
  83. package/src/ui/dist/assets/{NotebookEditor-Dc61cXmK.js → NotebookEditor-4R88_BMO.js} +1 -1
  84. package/src/ui/dist/assets/{PdfLoader-DWowuQwx.js → PdfLoader-DwEFQLrw.js} +1 -1
  85. package/src/ui/dist/assets/{PdfMarkdownPlugin-BsJM1q_a.js → PdfMarkdownPlugin-D-jdsqF8.js} +3 -3
  86. package/src/ui/dist/assets/{PdfViewerPlugin-DB2eEEFQ.js → PdfViewerPlugin-CmeBGDY0.js} +10 -10
  87. package/src/ui/dist/assets/{SearchPlugin-CraThSvt.js → SearchPlugin-Dlz2WKJ4.js} +1 -1
  88. package/src/ui/dist/assets/{Stepper-CgocRTPq.js → Stepper-ClOgzWM3.js} +1 -1
  89. package/src/ui/dist/assets/{TextViewerPlugin-B1JGhKtd.js → TextViewerPlugin-DDQWxibk.js} +4 -4
  90. package/src/ui/dist/assets/{VNCViewer-CclFC7FM.js → VNCViewer-CJXT0Nm8.js} +9 -9
  91. package/src/ui/dist/assets/{bibtex-D3IKsMl7.js → bibtex-DLr4Rtk4.js} +1 -1
  92. package/src/ui/dist/assets/{code-BP37Xx0p.js → code-DgKK408Y.js} +1 -1
  93. package/src/ui/dist/assets/{file-content-BAJSu-9r.js → file-content-6HBqQnvQ.js} +1 -1
  94. package/src/ui/dist/assets/{file-diff-panel-DUGeCTuy.js → file-diff-panel-Dhu0TbBM.js} +1 -1
  95. package/src/ui/dist/assets/{file-socket-CXc1Ojf7.js → file-socket-CP3iwVZG.js} +1 -1
  96. package/src/ui/dist/assets/{file-utils-2J21jt7M.js → file-utils-BsS-Aw68.js} +1 -1
  97. package/src/ui/dist/assets/{image-CMMmgvcn.js → image-ByeK-Zcv.js} +1 -1
  98. package/src/ui/dist/assets/{index-DmwmJmbW.js → index-BLjo5--a.js} +33610 -31016
  99. package/src/ui/dist/assets/{index-CWgMgpow.js → index-BdsE0uRz.js} +11 -11
  100. package/src/ui/dist/assets/{index-s7aHnNQ4.js → index-C-eX-N6A.js} +1 -1
  101. package/src/ui/dist/assets/{index-KGt-z-dD.css → index-CuQhlrR-.css} +2747 -2
  102. package/src/ui/dist/assets/{index-BaVumsQT.js → index-DyremSIv.js} +2 -2
  103. package/src/ui/dist/assets/{message-square-CQRfX0Am.js → message-square-DnagiLnc.js} +1 -1
  104. package/src/ui/dist/assets/{monaco-B4TbdsrF.js → monaco-4kBFeprs.js} +1 -1
  105. package/src/ui/dist/assets/{popover-B8Rokodk.js → popover-hRCXZzs2.js} +1 -1
  106. package/src/ui/dist/assets/{project-sync-D_i96KH4.js → project-sync-O_85YuP6.js} +1 -1
  107. package/src/ui/dist/assets/{sigma-D12PnzCN.js → sigma-DvKopSnL.js} +1 -1
  108. package/src/ui/dist/assets/{tooltip-B6YrI4aJ.js → tooltip-BmlPc6kc.js} +1 -1
  109. package/src/ui/dist/assets/{trash-Bc8jGp0V.js → trash-n-UvdZFR.js} +1 -1
  110. package/src/ui/dist/assets/{useCliAccess-mXVCYSZ-.js → useCliAccess-WDd3_wIh.js} +1 -1
  111. package/src/ui/dist/assets/{useFileDiffOverlay-Bg6b9H9K.js → useFileDiffOverlay-rXLIL2NF.js} +1 -1
  112. package/src/ui/dist/assets/{wrap-text-Drh5GEnL.js → wrap-text-qIYQ4a_W.js} +1 -1
  113. package/src/ui/dist/assets/{zoom-out-CJj9DZLn.js → zoom-out-fZXCEFsy.js} +1 -1
  114. package/src/ui/dist/index.html +2 -2
  115. package/uv.lock +1155 -0
  116. package/src/ui/dist/assets/LabPlugin-D9jVIo0A.css +0 -2698
@@ -92,9 +92,9 @@ acp:
92
92
  - 类型:`string`
93
93
  - 默认值:安装时的 DeepScientist 主目录,通常为 `~/DeepScientist`
94
94
  - 页面标签:`Home path`
95
- - 作用:这是配置、quests、memory、plugins、logs、cache 的根路径。
95
+ - 作用:这是配置、项目、memory、plugins、logs、cache 的根路径。
96
96
  - 何时修改:仅在你明确使用自定义安装目录时修改。
97
- - 注意事项:这不是单个 quest 路径,而是整个 DeepScientist 的运行时根目录。
97
+ - 注意事项:这不是单个项目路径,而是整个 DeepScientist 的运行时根目录。
98
98
 
99
99
  **`default_runner`**
100
100
 
@@ -102,7 +102,7 @@ acp:
102
102
  - 默认值:`codex`
103
103
  - 允许值:当前页面预设为 `codex`、`claude`
104
104
  - 页面标签:`Default runner`
105
- - 作用:当 quest 没有单独覆盖 runner 时,默认走这里指定的 runner。
105
+ - 作用:当项目没有单独覆盖 runner 时,默认走这里指定的 runner。
106
106
  - 何时修改:只有在你真的接通并启用了其他 runner 时才需要改。
107
107
  - 注意事项:当前仓库的真实主路径仍然是 `codex`;`claude` 仍是预留位。
108
108
 
@@ -122,17 +122,17 @@ acp:
122
122
  - 类型:`boolean`
123
123
  - 默认值:`true`
124
124
  - 页面标签:`Restore sessions on start`
125
- - 作用:daemon 启动时尝试恢复之前的 quest 会话状态。
125
+ - 作用:daemon 启动时尝试恢复之前的项目会话状态。
126
126
  - 何时关闭:你希望每次启动都从干净的运行时状态进入。
127
127
 
128
128
  **`daemon.max_concurrent_quests`**
129
129
 
130
130
  - 类型:`number`
131
131
  - 默认值:`1`
132
- - 页面标签:`Max concurrent quests`
133
- - 作用:限制同时活跃的 quest 数量。
132
+ - 页面标签:`Max concurrent projects`
133
+ - 作用:限制同时活跃的项目数量。
134
134
  - 推荐值:大多数情况下保持 `1`。
135
- - 风险:并发 quest 越多,资源竞争、连接器串扰和观察复杂度越高。
135
+ - 风险:并发项目越多,资源竞争、连接器串扰和观察复杂度越高。
136
136
 
137
137
  **`daemon.ack_timeout_ms`**
138
138
 
@@ -212,7 +212,7 @@ acp:
212
212
  - 类型:`boolean`
213
213
  - 默认值:`true`
214
214
  - 页面标签:`Auto-checkpoint`
215
- - 作用:quest 过程中自动做 Git 检查点。
215
+ - 作用:项目过程中自动做 Git 检查点。
216
216
  - 何时关闭:你完全希望手动控制提交节奏。
217
217
 
218
218
  **`git.auto_push`**
@@ -263,15 +263,15 @@ acp:
263
263
 
264
264
  - 类型:`boolean`
265
265
  - 默认值:`true`
266
- - 页面标签:`Sync quest skills on create`
267
- - 作用:创建 quest 时,把技能镜像到 quest 本地 `.codex/skills` / `.claude/agents`。
266
+ - 页面标签:`Sync project skills on create`
267
+ - 作用:创建项目时,把技能镜像到项目本地 `.codex/skills` / `.claude/agents`。
268
268
 
269
269
  **`skills.sync_quest_on_open`**
270
270
 
271
271
  - 类型:`boolean`
272
272
  - 默认值:`true`
273
- - 页面标签:`Sync quest skills on open`
274
- - 作用:打开已有 quest 时刷新本地技能镜像。
273
+ - 页面标签:`Sync project skills on open`
274
+ - 作用:打开已有项目时刷新本地技能镜像。
275
275
 
276
276
  ### Connector policy
277
277
 
@@ -296,7 +296,7 @@ acp:
296
296
  - 类型:`boolean`
297
297
  - 默认值:`true`
298
298
  - 页面标签:`Enable direct chat`
299
- - 作用:允许 connector 私聊直接驱动 quest。
299
+ - 作用:允许 connector 私聊直接驱动项目。
300
300
 
301
301
  ### Cloud link
302
302
 
@@ -385,7 +385,7 @@ acp:
385
385
 
386
386
  ### 摘要
387
387
 
388
- `runners.yaml` 定义 quest 实际由哪个 runner 执行,以及 runner 的模型默认值、审批策略、沙箱策略和失败重试策略。在当前开源版本中:
388
+ `runners.yaml` 定义项目实际由哪个 runner 执行,以及 runner 的模型默认值、审批策略、沙箱策略和失败重试策略。在当前开源版本中:
389
389
 
390
390
  - `codex`:主路径,默认启用。
391
391
  - `claude`:TODO / 预留条目,默认禁用,暂时不能运行。
@@ -447,7 +447,7 @@ claude:
447
447
  - 类型:`string`
448
448
  - 默认值:`codex=gpt-5.4`,`claude=inherit`
449
449
  - 页面标签:`Default model`
450
- - 作用:quest 和单次请求没有覆盖时的默认模型。
450
+ - 作用:项目和单次请求没有覆盖时的默认模型。
451
451
 
452
452
  **`model_reasoning_effort`**
453
453
 
@@ -539,7 +539,7 @@ claude:
539
539
  - 第一版部署一般保持 `codex.enabled: true`、`claude.enabled: false`。
540
540
  - 当前版本不要把 `default_runner` 从 `codex` 改走。
541
541
  - 如果你不希望任何自动审批,才把 `approval_policy` 调成更严格模式。
542
- - 如果 quest 经常需要长时间工具调用,不要随意把 `mcp_tool_timeout_sec` 改小。
542
+ - 如果项目经常需要长时间工具调用,不要随意把 `mcp_tool_timeout_sec` 改小。
543
543
 
544
544
  ## `connectors.yaml`
545
545
 
@@ -549,7 +549,7 @@ claude:
549
549
 
550
550
  - 优先使用无需公网回调的原生传输路径。
551
551
  - legacy webhook / relay 字段只作为兼容或兜底。
552
- - 所有连接器最终都属于同一个 quest 交互系统,而不是各自独立的一套消息逻辑。
552
+ - 所有连接器最终都属于同一个项目交互系统,而不是各自独立的一套消息逻辑。
553
553
 
554
554
  ### 顶层路由字段
555
555
 
@@ -602,7 +602,7 @@ claude:
602
602
 
603
603
  - 类型:`boolean`
604
604
  - 默认值:大多数 connector 为 `true`
605
- - 作用:私聊默认自动跟随当前活跃 quest。
605
+ - 作用:私聊默认自动跟随当前活跃项目。
606
606
 
607
607
  ### `telegram`
608
608
 
@@ -902,7 +902,7 @@ legacy Meta Cloud 字段:
902
902
 
903
903
  - 类型:`boolean`
904
904
  - 默认值:`true`
905
- - 作用:QQ 私聊默认跟随最新活跃 quest。
905
+ - 作用:QQ 私聊默认跟随最新活跃项目。
906
906
 
907
907
  ### QQ 里程碑媒体策略
908
908
 
@@ -1000,7 +1000,7 @@ allow_unsigned: false
1000
1000
 
1001
1001
  ### 摘要
1002
1002
 
1003
- 这个文件管理外部 MCP 服务。它不控制内置 `memory`、`artifact`、`bash_exec`,也不保存 quest 内部工具调用历史。
1003
+ 这个文件管理外部 MCP 服务。它不控制内置 `memory`、`artifact`、`bash_exec`,也不保存项目内部工具调用历史。
1004
1004
 
1005
1005
  ### 结构
1006
1006
 
@@ -1023,7 +1023,7 @@ servers:
1023
1023
 
1024
1024
  - 类型:`boolean`
1025
1025
  - 默认值:新卡片默认为 `false`
1026
- - 作用:只有启用的外部 MCP 才会暴露给 quest 或 runner。
1026
+ - 作用:只有启用的外部 MCP 才会暴露给项目或 runner。
1027
1027
 
1028
1028
  **`servers.<server_id>.transport`**
1029
1029
 
@@ -9,10 +9,10 @@
9
9
 
10
10
  ## 这个弹窗实际做什么
11
11
 
12
- `Start Research` 不只是“新建 quest 表单”,它同时完成四件事:
12
+ `Start Research` 不只是“新建项目表单”,它同时完成四件事:
13
13
 
14
14
  1. 收集结构化启动上下文
15
- 2. 把这些上下文编译成 quest 的第一条 kickoff prompt
15
+ 2. 把这些上下文编译成项目的第一条 kickoff prompt
16
16
  3. 绑定一个可选的可复用 baseline
17
17
  4. 持久化 `startup_contract`,供后续 prompt builder 持续读取
18
18
 
@@ -113,17 +113,17 @@ type StartResearchContractFields = {
113
113
 
114
114
  ## 字段说明
115
115
 
116
- ### Quest 基本身份
116
+ ### 项目基本身份
117
117
 
118
118
  **`title`**
119
119
 
120
- - Quest 的人类可读标题。
120
+ - 项目的人类可读标题。
121
121
  - 用于卡片和工作区标题。
122
122
  - 不要求与 `quest_id` 一致。
123
123
 
124
124
  **`quest_id`**
125
125
 
126
- - Quest 的稳定标识,也是目录名。
126
+ - 项目的稳定标识,保存在 `quest_id` 中,同时也是目录名。
127
127
  - 默认由 runtime 提供下一个顺序编号。
128
128
  - 允许用户手动覆盖。
129
129
 
@@ -256,17 +256,17 @@ type StartResearchContractFields = {
256
256
 
257
257
  `compileStartResearchPrompt(...)` 会生成一段可读 kickoff prompt,包含:
258
258
 
259
- - quest bootstrap
260
- - primary research request
261
- - research goals
262
- - baseline context
263
- - reference papers / repositories
264
- - operational constraints
265
- - research delivery mode
266
- - decision handling mode
267
- - launch mode
268
- - research contract
269
- - mandatory working rules
259
+ - 项目启动上下文
260
+ - 核心研究请求
261
+ - 研究目标
262
+ - baseline 上下文
263
+ - 参考论文 / 仓库
264
+ - 运行约束
265
+ - 研究交付模式
266
+ - 决策处理模式
267
+ - 启动模式
268
+ - 研究合同
269
+ - 必须遵守的工作规则
270
270
 
271
271
  其中自定义启动会被明确写出来:
272
272
 
@@ -327,8 +327,8 @@ type StartResearchContractFields = {
327
327
 
328
328
  ```json
329
329
  {
330
- "title": "Continue retrieval quest",
331
- "goal": "Continue the existing retrieval quest and decide whether a fresh main run is still needed.",
330
+ "title": "Continue retrieval project",
331
+ "goal": "Continue the existing retrieval project and decide whether a fresh main run is still needed.",
332
332
  "quest_id": "013",
333
333
  "requested_baseline_ref": null,
334
334
  "startup_contract": {
@@ -396,7 +396,7 @@ type StartResearchContractFields = {
396
396
 
397
397
  ## 运行时意义
398
398
 
399
- - `startup_contract` quest 的持久状态,不只是 UI 临时字段。
399
+ - `startup_contract` 是项目的持久状态,不只是 UI 临时字段。
400
400
  - 后续 prompt builder 还会继续读取 `launch_mode`、`custom_profile`、`entry_state_summary`、`review_summary`、`custom_brief`。
401
401
  - 所以 `Start Research` 不只影响第一轮,还会影响后续路由判断。
402
402
 
@@ -16,7 +16,7 @@
16
16
  完成本文档后,你应该可以做到:
17
17
 
18
18
  - 用 QQ 私聊 DeepScientist
19
- - 让 QQ 自动绑定到当前最新 quest
19
+ - 让 QQ 自动绑定到当前最新项目
20
20
  - 在 QQ 中使用 `/new`、`/use latest`、`/status` 等命令
21
21
  - 在 `Settings` 页面看到自动检测到的 `openid`
22
22
  - 从 `Settings` 页面执行非破坏性的连接测试
@@ -219,7 +219,7 @@ QQ readiness is healthy, but no OpenID has been learned yet. Save credentials, t
219
219
  - `Settings > Connectors > QQ` 中的 `Detected OpenID` 不再为空
220
220
  - `Snapshot` 里出现已经发现的目标会话,且绑定目标不是空
221
221
  - 再次点击“发送测试消息”时,不再提示 target 为空
222
- - 如果当前已经有最新 quest,普通文本会自动进入该 quest;如果还没有 quest,则优先返回帮助信息
222
+ - 如果当前已经有最新项目,普通文本会自动进入该项目;如果还没有项目,则优先返回帮助信息
223
223
 
224
224
  ### 5.2 报错提示速查
225
225
 
@@ -239,17 +239,17 @@ QQ readiness is healthy, but no OpenID has been learned yet. Save credentials, t
239
239
  | 命令 | 作用 |
240
240
  | --- | --- |
241
241
  | `/help` | 查看帮助 |
242
- | `/projects` 或 `/list` | 查看 quest 列表 |
243
- | `/use <quest_id>` | 绑定指定 quest |
244
- | `/use latest` | 绑定最新 quest |
245
- | `/new <goal>` | 新建 quest 并把当前 QQ 会话绑定过去 |
246
- | `/status` | 查看当前 quest 状态 |
242
+ | `/projects` 或 `/list` | 查看项目列表 |
243
+ | `/use <quest_id>` | 绑定指定项目 |
244
+ | `/use latest` | 绑定最新项目 |
245
+ | `/new <goal>` | 新建项目并把当前 QQ 会话绑定过去 |
246
+ | `/status` | 查看当前项目状态 |
247
247
 
248
248
  日常沟通建议:
249
249
 
250
- - 如果已经有最新 quest,普通文本通常会继续那个 quest
251
- - 如果还没有 quest,优先发送 `/new <goal>`
252
- - 如果你想切换到另一个 quest,显式发送 `/use <quest_id>`
250
+ - 如果已经有最新项目,普通文本通常会继续那个项目
251
+ - 如果还没有项目,优先发送 `/new <goal>`
252
+ - 如果你想切换到另一个项目,显式发送 `/use <quest_id>`
253
253
 
254
254
  ## 7. 最容易踩坑的地方
255
255
 
@@ -9,7 +9,7 @@
9
9
  在当前仓库目录中:
10
10
 
11
11
  ```bash
12
- pip install -e .
12
+ uv sync
13
13
  npm install
14
14
  ```
15
15
 
@@ -4,10 +4,10 @@
4
4
 
5
5
  ## 推荐使用流程
6
6
 
7
- 1. 先安装 DeepScientist 和 Codex
7
+ 1. 先安装 DeepScientist:
8
8
 
9
9
  ```bash
10
- npm install -g @openai/codex @researai/deepscientist
10
+ npm install -g @researai/deepscientist
11
11
  ```
12
12
 
13
13
  2. 先直接尝试启动:
@@ -30,6 +30,7 @@
30
30
 
31
31
  - 本地 Python 运行时是否健康
32
32
  - `~/DeepScientist` 是否存在且可写
33
+ - `uv` 是否可用,以便管理本地 Python 运行时
33
34
  - `git` 是否安装并完成基本配置
34
35
  - 必需配置文件是否有效
35
36
  - 当前开源版本是否仍然使用 `codex` 作为可运行 runner
@@ -42,10 +43,10 @@
42
43
 
43
44
  ### 没有安装 Codex
44
45
 
45
- 运行:
46
+ 重新安装 DeepScientist,让随包的 Codex 依赖一起装好:
46
47
 
47
48
  ```bash
48
- npm install -g @openai/codex
49
+ npm install -g @researai/deepscientist
49
50
  ```
50
51
 
51
52
  ### 已安装 Codex,但还没有登录
@@ -58,6 +59,20 @@ codex
58
59
 
59
60
  先完成一次登录,再重新执行 `ds doctor`。
60
61
 
62
+ ### 没有安装 `uv`
63
+
64
+ 正常情况下,第一次运行 `ds` 会自动在本地安装 `uv`。如果自动安装失败,再手动执行:
65
+
66
+ ```bash
67
+ curl -LsSf https://astral.sh/uv/install.sh | sh
68
+ ```
69
+
70
+ 如果你在 Windows PowerShell:
71
+
72
+ ```powershell
73
+ powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
74
+ ```
75
+
61
76
  ### 本地论文 PDF 编译暂时不可用
62
77
 
63
78
  如果你希望直接在 DeepScientist 里本地编译论文,可以安装一个轻量级 TinyTeX `pdflatex` 运行时:
@@ -86,6 +101,33 @@ ds --stop
86
101
 
87
102
  里的 `ui.port`。
88
103
 
104
+ 也可以直接临时换一个端口启动:
105
+
106
+ ```bash
107
+ ds --port 21000
108
+ ```
109
+
110
+ ### 当前激活的是 Python `3.10` 或更低版本
111
+
112
+ 如果你已经在使用 conda,而当前环境过旧,请先激活正确环境:
113
+
114
+ ```bash
115
+ conda activate ds311
116
+ python3 --version
117
+ which python3
118
+ ds
119
+ ```
120
+
121
+ 或者新建一个可用环境:
122
+
123
+ ```bash
124
+ conda create -n ds311 python=3.11 -y
125
+ conda activate ds311
126
+ ds
127
+ ```
128
+
129
+ 如果你不手动切换,`ds` 也可以在 DeepScientist home 下自动准备受管的 `uv` + Python 运行时。
130
+
89
131
  ### Git 用户身份没有配置
90
132
 
91
133
  运行:
package/install.sh CHANGED
@@ -233,10 +233,8 @@ copy_source_tree() {
233
233
  --exclude='./node_modules' \
234
234
  --exclude='./ui' \
235
235
  --exclude='./src/ui/node_modules' \
236
- --exclude='./src/ui/dist' \
237
236
  --exclude='./src/ui/lib/node_modules' \
238
237
  --exclude='./src/tui/node_modules' \
239
- --exclude='./src/tui/dist' \
240
238
  --exclude='./src/deepscientist.egg-info' \
241
239
  . | tar -C "$target" -xf -
242
240
  else
@@ -252,16 +250,18 @@ prune_tree() {
252
250
  "$target/node_modules" \
253
251
  "$target/ui" \
254
252
  "$target/src/ui/node_modules" \
255
- "$target/src/ui/dist" \
256
253
  "$target/src/ui/lib/node_modules" \
257
254
  "$target/src/tui/node_modules" \
258
- "$target/src/tui/dist" \
259
255
  "$target/src/deepscientist.egg-info"
260
256
  find "$target" -type d -name '__pycache__' -prune -exec rm -rf {} +
261
257
  find "$target" -type f \( -name '*.pyc' -o -name '*.pyo' \) -delete
262
258
  }
263
259
 
264
260
  build_ui() {
261
+ if should_use_prebuilt_bundle "$1/src/ui" "$1/src/ui/dist" "index.html" "${DEEPSCIENTIST_FORCE_UI_BUILD:-}"; then
262
+ print_step "Using up-to-date web UI bundle from source tree"
263
+ return
264
+ fi
265
265
  print_step "Building web UI in install tree"
266
266
  npm --prefix "$1/src/ui" install --include=dev --no-audit --no-fund
267
267
  npm --prefix "$1/src/ui" run build
@@ -274,12 +274,125 @@ install_root_runtime() {
274
274
  }
275
275
 
276
276
  build_tui() {
277
+ local tui_entry=""
278
+ if [ -f "$1/src/tui/dist/index.js" ]; then
279
+ tui_entry="index.js"
280
+ elif [ -f "$1/src/tui/dist/index.cjs" ]; then
281
+ tui_entry="index.cjs"
282
+ elif [ -d "$1/src/tui/dist/components" ]; then
283
+ tui_entry="components"
284
+ fi
285
+ if [ -n "$tui_entry" ] && should_use_prebuilt_bundle "$1/src/tui" "$1/src/tui/dist" "$tui_entry" "${DEEPSCIENTIST_FORCE_TUI_BUILD:-}"; then
286
+ print_step "Using up-to-date TUI bundle from source tree"
287
+ return
288
+ fi
277
289
  print_step "Building TUI in install tree"
278
290
  npm --prefix "$1/src/tui" install --include=dev --no-audit --no-fund
279
291
  npm --prefix "$1/src/tui" run build
280
292
  npm --prefix "$1/src/tui" prune --omit=dev --no-audit --no-fund
281
293
  }
282
294
 
295
+ truthy_env() {
296
+ case "$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')" in
297
+ 1|true|yes|on)
298
+ return 0
299
+ ;;
300
+ *)
301
+ return 1
302
+ ;;
303
+ esac
304
+ }
305
+
306
+ should_use_prebuilt_bundle() {
307
+ local source_root="$1"
308
+ local dist_root="$2"
309
+ local dist_entry="$3"
310
+ local force_value="${4:-}"
311
+
312
+ if truthy_env "$force_value"; then
313
+ return 1
314
+ fi
315
+
316
+ if [ ! -e "$dist_root/$dist_entry" ]; then
317
+ return 1
318
+ fi
319
+
320
+ local freshness_output=""
321
+ if command -v python3 >/dev/null 2>&1; then
322
+ freshness_output="$(python3 - "$source_root" "$dist_root" <<'PY'
323
+ from pathlib import Path
324
+ import sys
325
+
326
+ source_root = Path(sys.argv[1])
327
+ dist_root = Path(sys.argv[2])
328
+ ignore_names = {"dist", "node_modules", ".git", "__pycache__"}
329
+
330
+ if not source_root.exists() or not dist_root.exists():
331
+ print("stale")
332
+ raise SystemExit(0)
333
+
334
+ def iter_files(root: Path):
335
+ for path in root.rglob("*"):
336
+ if not path.is_file():
337
+ continue
338
+ if any(part in ignore_names for part in path.relative_to(root).parts):
339
+ continue
340
+ yield path
341
+
342
+ source_mtime = 0.0
343
+ for path in iter_files(source_root):
344
+ source_mtime = max(source_mtime, path.stat().st_mtime)
345
+
346
+ dist_mtime = 0.0
347
+ for path in dist_root.rglob("*"):
348
+ if not path.is_file():
349
+ continue
350
+ dist_mtime = max(dist_mtime, path.stat().st_mtime)
351
+
352
+ print("fresh" if dist_mtime >= source_mtime else "stale")
353
+ PY
354
+ )"
355
+ elif command -v python >/dev/null 2>&1; then
356
+ freshness_output="$(python - "$source_root" "$dist_root" <<'PY'
357
+ from pathlib import Path
358
+ import sys
359
+
360
+ source_root = Path(sys.argv[1])
361
+ dist_root = Path(sys.argv[2])
362
+ ignore_names = {"dist", "node_modules", ".git", "__pycache__"}
363
+
364
+ if not source_root.exists() or not dist_root.exists():
365
+ print("stale")
366
+ raise SystemExit(0)
367
+
368
+ def iter_files(root: Path):
369
+ for path in root.rglob("*"):
370
+ if not path.is_file():
371
+ continue
372
+ if any(part in ignore_names for part in path.relative_to(root).parts):
373
+ continue
374
+ yield path
375
+
376
+ source_mtime = 0.0
377
+ for path in iter_files(source_root):
378
+ source_mtime = max(source_mtime, path.stat().st_mtime)
379
+
380
+ dist_mtime = 0.0
381
+ for path in dist_root.rglob("*"):
382
+ if not path.is_file():
383
+ continue
384
+ dist_mtime = max(dist_mtime, path.stat().st_mtime)
385
+
386
+ print("fresh" if dist_mtime >= source_mtime else "stale")
387
+ PY
388
+ )"
389
+ else
390
+ return 1
391
+ fi
392
+
393
+ [ "$freshness_output" = "fresh" ]
394
+ }
395
+
283
396
  write_install_wrappers() {
284
397
  local target="$1"
285
398
  mkdir -p "$target/bin"
@@ -288,6 +401,10 @@ write_install_wrappers() {
288
401
  #!/usr/bin/env bash
289
402
  set -euo pipefail
290
403
  SCRIPT_DIR="\$(cd "\$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
404
+ HOME_DIR="\$(cd "\$SCRIPT_DIR/../.." && pwd)"
405
+ if [ -z "\${DEEPSCIENTIST_HOME:-}" ]; then
406
+ export DEEPSCIENTIST_HOME="\$HOME_DIR"
407
+ fi
291
408
  NODE_BIN="\${DEEPSCIENTIST_NODE:-node}"
292
409
  exec "\$NODE_BIN" "\$SCRIPT_DIR/ds.js" "\$@"
293
410
  EOF
@@ -304,6 +421,9 @@ write_global_wrapper() {
304
421
  cat >"$target_path" <<EOF
305
422
  #!/usr/bin/env bash
306
423
  set -euo pipefail
424
+ if [ -z "\${DEEPSCIENTIST_HOME:-}" ]; then
425
+ export DEEPSCIENTIST_HOME="$BASE_DIR"
426
+ fi
307
427
  exec "$INSTALL_DIR/bin/$command_name" "\$@"
308
428
  EOF
309
429
  chmod +x "$target_path"
@@ -311,10 +431,6 @@ EOF
311
431
 
312
432
  require_command node
313
433
  require_command npm
314
- if ! command -v python3 >/dev/null 2>&1 && ! command -v python >/dev/null 2>&1; then
315
- echo "Python 3 is required to run DeepScientist." >&2
316
- exit 1
317
- fi
318
434
 
319
435
  SOURCE_ROOT_RESOLVED="$(resolve_path "$SOURCE_ROOT")"
320
436
  INSTALL_DIR_RESOLVED="$(resolve_path "$INSTALL_DIR")"
@@ -356,6 +472,7 @@ printf 'Run: %s\n' "$BIN_DIR/ds"
356
472
  printf 'Start web workspace: %s\n' "$BIN_DIR/ds --web"
357
473
  printf 'Default start: %s\n' "$BIN_DIR/ds"
358
474
  printf 'When `ds` starts, it prints the local Web URL and opens it automatically when supported.\n'
475
+ printf 'If `uv` is missing, the first `ds` start will bootstrap a local copy automatically under the DeepScientist home.\n'
359
476
  if [ "$WITH_TINYTEX" -eq 1 ]; then
360
477
  print_step "Installing TinyTeX pdflatex runtime"
361
478
  "$INSTALL_DIR/bin/ds" latex install-runtime
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@researai/deepscientist",
3
- "version": "1.5.1",
3
+ "version": "1.5.3",
4
4
  "description": "Local-first research operating system with a Python runtime and npm launcher",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -9,6 +9,7 @@
9
9
  "docs/en/",
10
10
  "docs/zh/",
11
11
  "install.sh",
12
+ "uv.lock",
12
13
  "assets/branding/",
13
14
  "assets/connectors/",
14
15
  "bin/",
package/pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "deepscientist"
7
- version = "1.5.1"
7
+ version = "1.5.3"
8
8
  description = "DeepScientist Core skeleton"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -1,3 +1,8 @@
1
+ from importlib.metadata import PackageNotFoundError, version as _package_version
2
+
1
3
  __all__ = ["__version__"]
2
4
 
3
- __version__ = "0.1.0"
5
+ try:
6
+ __version__ = _package_version("deepscientist")
7
+ except PackageNotFoundError: # pragma: no cover - source checkout fallback
8
+ __version__ = "1.5.3"