@researai/deepscientist 1.5.7 → 1.5.8

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/README.md +4 -0
  2. package/bin/ds.js +220 -5
  3. package/docs/en/07_MEMORY_AND_MCP.md +40 -3
  4. package/docs/en/99_ACKNOWLEDGEMENTS.md +1 -0
  5. package/docs/zh/07_MEMORY_AND_MCP.md +40 -3
  6. package/docs/zh/99_ACKNOWLEDGEMENTS.md +1 -0
  7. package/install.sh +34 -0
  8. package/package.json +1 -1
  9. package/pyproject.toml +1 -1
  10. package/src/deepscientist/__init__.py +1 -1
  11. package/src/deepscientist/acp/envelope.py +1 -0
  12. package/src/deepscientist/artifact/metrics.py +813 -80
  13. package/src/deepscientist/artifact/schemas.py +1 -0
  14. package/src/deepscientist/artifact/service.py +1101 -99
  15. package/src/deepscientist/bash_exec/monitor.py +1 -1
  16. package/src/deepscientist/bash_exec/service.py +17 -9
  17. package/src/deepscientist/channels/qq.py +17 -0
  18. package/src/deepscientist/channels/relay.py +16 -0
  19. package/src/deepscientist/config/models.py +6 -0
  20. package/src/deepscientist/config/service.py +70 -2
  21. package/src/deepscientist/daemon/api/handlers.py +284 -14
  22. package/src/deepscientist/daemon/api/router.py +1 -0
  23. package/src/deepscientist/daemon/app.py +291 -20
  24. package/src/deepscientist/gitops/diff.py +6 -10
  25. package/src/deepscientist/mcp/server.py +188 -39
  26. package/src/deepscientist/prompts/builder.py +51 -18
  27. package/src/deepscientist/quest/service.py +83 -34
  28. package/src/deepscientist/quest/stage_views.py +74 -29
  29. package/src/deepscientist/runners/codex.py +1 -1
  30. package/src/prompts/connectors/qq.md +1 -1
  31. package/src/prompts/contracts/shared_interaction.md +14 -0
  32. package/src/prompts/system.md +106 -32
  33. package/src/skills/analysis-campaign/SKILL.md +10 -14
  34. package/src/skills/baseline/SKILL.md +51 -38
  35. package/src/skills/baseline/references/baseline-plan-template.md +2 -0
  36. package/src/skills/decision/SKILL.md +12 -8
  37. package/src/skills/experiment/SKILL.md +28 -16
  38. package/src/skills/experiment/references/main-experiment-plan-template.md +2 -0
  39. package/src/skills/figure-polish/SKILL.md +1 -0
  40. package/src/skills/finalize/SKILL.md +3 -8
  41. package/src/skills/idea/SKILL.md +2 -8
  42. package/src/skills/intake-audit/SKILL.md +2 -8
  43. package/src/skills/rebuttal/SKILL.md +2 -8
  44. package/src/skills/review/SKILL.md +2 -8
  45. package/src/skills/scout/SKILL.md +2 -8
  46. package/src/skills/write/SKILL.md +52 -16
  47. package/src/skills/write/templates/DEEPSCIENTIST_NOTES.md +21 -0
  48. package/src/skills/write/templates/README.md +408 -0
  49. package/src/skills/write/templates/UPSTREAM_LICENSE.txt +21 -0
  50. package/src/skills/write/templates/aaai2026/README.md +534 -0
  51. package/src/skills/write/templates/aaai2026/aaai2026-unified-supp.tex +144 -0
  52. package/src/skills/write/templates/aaai2026/aaai2026-unified-template.tex +952 -0
  53. package/src/skills/write/templates/aaai2026/aaai2026.bib +111 -0
  54. package/src/skills/write/templates/aaai2026/aaai2026.bst +1493 -0
  55. package/src/skills/write/templates/aaai2026/aaai2026.sty +315 -0
  56. package/src/skills/write/templates/acl/README.md +50 -0
  57. package/src/skills/write/templates/acl/acl.sty +312 -0
  58. package/src/skills/write/templates/acl/acl_latex.tex +377 -0
  59. package/src/skills/write/templates/acl/acl_lualatex.tex +101 -0
  60. package/src/skills/write/templates/acl/acl_natbib.bst +1940 -0
  61. package/src/skills/write/templates/acl/anthology.bib.txt +26 -0
  62. package/src/skills/write/templates/acl/custom.bib +70 -0
  63. package/src/skills/write/templates/acl/formatting.md +326 -0
  64. package/src/skills/write/templates/asplos2027/main.tex +459 -0
  65. package/src/skills/write/templates/asplos2027/references.bib +135 -0
  66. package/src/skills/write/templates/colm2025/README.md +3 -0
  67. package/src/skills/write/templates/colm2025/colm2025_conference.bib +11 -0
  68. package/src/skills/write/templates/colm2025/colm2025_conference.bst +1440 -0
  69. package/src/skills/write/templates/colm2025/colm2025_conference.sty +218 -0
  70. package/src/skills/write/templates/colm2025/colm2025_conference.tex +305 -0
  71. package/src/skills/write/templates/colm2025/fancyhdr.sty +485 -0
  72. package/src/skills/write/templates/colm2025/math_commands.tex +508 -0
  73. package/src/skills/write/templates/colm2025/natbib.sty +1246 -0
  74. package/src/skills/write/templates/iclr2026/fancyhdr.sty +485 -0
  75. package/src/skills/write/templates/iclr2026/iclr2026_conference.bib +24 -0
  76. package/src/skills/write/templates/iclr2026/iclr2026_conference.bst +1440 -0
  77. package/src/skills/write/templates/iclr2026/iclr2026_conference.sty +246 -0
  78. package/src/skills/write/templates/iclr2026/iclr2026_conference.tex +414 -0
  79. package/src/skills/write/templates/iclr2026/math_commands.tex +508 -0
  80. package/src/skills/write/templates/iclr2026/natbib.sty +1246 -0
  81. package/src/skills/write/templates/icml2026/algorithm.sty +79 -0
  82. package/src/skills/write/templates/icml2026/algorithmic.sty +201 -0
  83. package/src/skills/write/templates/icml2026/example_paper.bib +75 -0
  84. package/src/skills/write/templates/icml2026/example_paper.tex +662 -0
  85. package/src/skills/write/templates/icml2026/fancyhdr.sty +864 -0
  86. package/src/skills/write/templates/icml2026/icml2026.bst +1443 -0
  87. package/src/skills/write/templates/icml2026/icml2026.sty +767 -0
  88. package/src/skills/write/templates/neurips2025/Makefile +36 -0
  89. package/src/skills/write/templates/neurips2025/extra_pkgs.tex +53 -0
  90. package/src/skills/write/templates/neurips2025/main.tex +38 -0
  91. package/src/skills/write/templates/neurips2025/neurips.sty +382 -0
  92. package/src/skills/write/templates/nsdi2027/main.tex +426 -0
  93. package/src/skills/write/templates/nsdi2027/references.bib +151 -0
  94. package/src/skills/write/templates/nsdi2027/usenix-2020-09.sty +83 -0
  95. package/src/skills/write/templates/osdi2026/main.tex +429 -0
  96. package/src/skills/write/templates/osdi2026/references.bib +150 -0
  97. package/src/skills/write/templates/osdi2026/usenix-2020-09.sty +83 -0
  98. package/src/skills/write/templates/sosp2026/main.tex +532 -0
  99. package/src/skills/write/templates/sosp2026/references.bib +148 -0
  100. package/src/tui/package.json +1 -1
  101. package/src/ui/dist/assets/{AiManusChatView-BS3V4ZOk.js → AiManusChatView-m2FNtwbn.js} +110 -14
  102. package/src/ui/dist/assets/{AnalysisPlugin-DLPXQsmr.js → AnalysisPlugin-BMTF8EGL.js} +1 -1
  103. package/src/ui/dist/assets/{AutoFigurePlugin-C-Fr9knQ.js → AutoFigurePlugin-DxPdMUNb.js} +5 -5
  104. package/src/ui/dist/assets/{CliPlugin-Dd8AHzFg.js → CliPlugin-BEOWgxCI.js} +9 -9
  105. package/src/ui/dist/assets/{CodeEditorPlugin-Dg-RepTl.js → CodeEditorPlugin-BCXvjqmb.js} +8 -8
  106. package/src/ui/dist/assets/{CodeViewerPlugin-D2J_3nyt.js → CodeViewerPlugin-DaJcy3nD.js} +5 -5
  107. package/src/ui/dist/assets/{DocViewerPlugin-ChRLLKNb.js → DocViewerPlugin-ByfeIq4K.js} +3 -3
  108. package/src/ui/dist/assets/{GitDiffViewerPlugin-DgHfcved.js → GitDiffViewerPlugin-Cksf3VZ-.js} +830 -86
  109. package/src/ui/dist/assets/{ImageViewerPlugin-C89GZMBy.js → ImageViewerPlugin-CFz-OsTS.js} +5 -5
  110. package/src/ui/dist/assets/{LabCopilotPanel-BUfIwUcb.js → LabCopilotPanel-CJ1cJzoX.js} +10 -10
  111. package/src/ui/dist/assets/{LabPlugin-zvUmQUMq.js → LabPlugin-BF3dVJwa.js} +1 -1
  112. package/src/ui/dist/assets/{LatexPlugin-C1SSNuWp.js → LatexPlugin-DDkwZ6Sj.js} +7 -7
  113. package/src/ui/dist/assets/{MarkdownViewerPlugin-D2Mf5tU5.js → MarkdownViewerPlugin-HAuvurcT.js} +4 -4
  114. package/src/ui/dist/assets/{MarketplacePlugin-CF4LgiS2.js → MarketplacePlugin-BtoTYy2C.js} +3 -3
  115. package/src/ui/dist/assets/{index-Be0NAmh8.js → NotebookEditor-CSJYx7b-.js} +12 -155
  116. package/src/ui/dist/assets/{NotebookEditor-BM7Bgwlv.js → NotebookEditor-DQgRezm_.js} +1 -1
  117. package/src/ui/dist/assets/{PdfLoader-Bc5qfD-Z.js → PdfLoader-DPa_-fv6.js} +1 -1
  118. package/src/ui/dist/assets/{PdfMarkdownPlugin-sh1-IRcp.js → PdfMarkdownPlugin-BZpXOEjm.js} +3 -3
  119. package/src/ui/dist/assets/{PdfViewerPlugin-C_a7CpWG.js → PdfViewerPlugin-BT8a6wGR.js} +10 -10
  120. package/src/ui/dist/assets/{SearchPlugin-L4z3HcLf.js → SearchPlugin-D_blveZi.js} +1 -1
  121. package/src/ui/dist/assets/{Stepper-Dk4aQ3fN.js → Stepper-DH2k75Vo.js} +1 -1
  122. package/src/ui/dist/assets/{TextViewerPlugin-BsNtlKVo.js → TextViewerPlugin-Btx0M3hX.js} +4 -4
  123. package/src/ui/dist/assets/{VNCViewer-BpeDcZ5_.js → VNCViewer-DImJO4rO.js} +9 -9
  124. package/src/ui/dist/assets/{bibtex-C4QI-bbj.js → bibtex-B-Hqu0Sg.js} +1 -1
  125. package/src/ui/dist/assets/{code-DuMINRsg.js → code-BUfXGJSl.js} +1 -1
  126. package/src/ui/dist/assets/{file-content-C3N-432K.js → file-content-VqamwI3X.js} +1 -1
  127. package/src/ui/dist/assets/{file-diff-panel-CffQ4ZMg.js → file-diff-panel-C_wOoS7a.js} +1 -1
  128. package/src/ui/dist/assets/{file-socket-CRH59PCO.js → file-socket-D2bTuMVP.js} +1 -1
  129. package/src/ui/dist/assets/{file-utils-vYGtW2mI.js → file-utils--zJCPN1i.js} +1 -1
  130. package/src/ui/dist/assets/{image-DBVGaooo.js → image-BZkGJ4mM.js} +1 -1
  131. package/src/ui/dist/assets/{index-DjSFDmgB.js → index-CxkvSeKw.js} +2 -2
  132. package/src/ui/dist/assets/{index-BpjYH9Vg.js → index-D9QIGcmc.js} +1 -1
  133. package/src/ui/dist/assets/{index-Do9N28uB.css → index-DXZ1daiJ.css} +163 -34
  134. package/src/ui/dist/assets/index-DdRW6RMJ.js +159 -0
  135. package/src/ui/dist/assets/{index-B1P6hQRJ.js → index-DjggJovS.js} +3029 -1780
  136. package/src/ui/dist/assets/{message-square-BsPDBhiY.js → message-square-FUIPIhU2.js} +1 -1
  137. package/src/ui/dist/assets/{monaco-BTkdPojV.js → monaco-DHMc7kKM.js} +1 -1
  138. package/src/ui/dist/assets/{popover-cWjCk-vc.js → popover-B85oCgCS.js} +1 -1
  139. package/src/ui/dist/assets/{project-sync-CXn530xb.js → project-sync-DOMCcPac.js} +1 -1
  140. package/src/ui/dist/assets/{sigma-04Jr12jg.js → sigma-BO2rQrl3.js} +1 -1
  141. package/src/ui/dist/assets/{tooltip-BdVDl0G5.js → tooltip-B1OspAkx.js} +1 -1
  142. package/src/ui/dist/assets/{trash-CB_GlQyC.js → trash-BsVEH_dV.js} +1 -1
  143. package/src/ui/dist/assets/{useCliAccess-BL932NwS.js → useCliAccess-b8L6JuZm.js} +1 -1
  144. package/src/ui/dist/assets/{useFileDiffOverlay-B2WK7Tvq.js → useFileDiffOverlay-BY7uA9hV.js} +1 -1
  145. package/src/ui/dist/assets/{wrap-text-YC68g12z.js → wrap-text-BwyVuUIK.js} +1 -1
  146. package/src/ui/dist/assets/{zoom-out-C0RJvFiJ.js → zoom-out-RDpLugQP.js} +1 -1
  147. package/src/ui/dist/index.html +5 -2
  148. /package/src/ui/dist/assets/{index-CccQYZjX.css → NotebookEditor-CccQYZjX.css} +0 -0
package/README.md CHANGED
@@ -17,6 +17,8 @@ Install DeepScientist:
17
17
  npm install -g @researai/deepscientist
18
18
  ```
19
19
 
20
+ For the best experience, we recommend using GPT-5.4 in `xhigh` mode (for example, via the $20 GPT Plus plan or the $200 GPT Pro plan); if you are in China, we recommend the MiniMax-M2.7 Token Plan (Max plan): https://platform.minimaxi.com/subscribe/token-plan
21
+
20
22
  ## Start
21
23
 
22
24
  ```bash
@@ -124,6 +126,8 @@ This installs a lightweight TinyTeX `pdflatex` runtime for local paper compilati
124
126
  - [快速开始(中文)](docs/zh/00_QUICK_START.md)
125
127
  - [QQ Connector Guide (English)](docs/en/03_QQ_CONNECTOR_GUIDE.md)
126
128
  - [QQ Connector Guide (中文)](docs/zh/03_QQ_CONNECTOR_GUIDE.md)
129
+ - [Memory and MCP Guide (English)](docs/en/07_MEMORY_AND_MCP.md)
130
+ - [Memory 与 MCP 指南(中文)](docs/zh/07_MEMORY_AND_MCP.md)
127
131
 
128
132
  ## Maintainers
129
133
 
package/bin/ds.js CHANGED
@@ -220,6 +220,17 @@ function compareVersions(left, right) {
220
220
  return 0;
221
221
  }
222
222
 
223
+ function hasActiveBusyUpdate(state, currentVersion) {
224
+ if (!state || !state.busy) {
225
+ return false;
226
+ }
227
+ const targetVersion = normalizeVersion(state.target_version || state.latest_version || '');
228
+ if (!targetVersion) {
229
+ return false;
230
+ }
231
+ return compareVersions(targetVersion, currentVersion) > 0;
232
+ }
233
+
223
234
  function detectInstallMode(rootPath = repoRoot) {
224
235
  const normalized = String(rootPath || '');
225
236
  return normalized.includes(`${path.sep}node_modules${path.sep}`) ? 'npm-package' : 'source-checkout';
@@ -326,6 +337,8 @@ function buildUpdateStatus(home, statePatch = {}) {
326
337
  const support = updateSupportSummary(installMode, npmBinary, launcherPath);
327
338
  const currentVersion = normalizeVersion(state.current_version || packageJson.version);
328
339
  const latestVersion = normalizeVersion(state.latest_version || '');
340
+ const targetVersion = normalizeVersion(state.target_version || '');
341
+ const busy = hasActiveBusyUpdate(state, currentVersion);
329
342
  const promptedVersion = normalizeVersion(state.last_prompted_version || '');
330
343
  const updateAvailable = Boolean(latestVersion) && compareVersions(latestVersion, currentVersion) > 0;
331
344
  const skippedVersion = normalizeVersion(state.last_skipped_version || '');
@@ -333,7 +346,7 @@ function buildUpdateStatus(home, statePatch = {}) {
333
346
  const skippedCurrentTarget = Boolean(updateAvailable && skippedVersion && skippedVersion === latestVersion);
334
347
  const promptRecommended =
335
348
  Boolean(updateAvailable)
336
- && !Boolean(state.busy)
349
+ && !busy
337
350
  && !promptedCurrentTarget
338
351
  && !skippedCurrentTarget
339
352
  ;
@@ -348,7 +361,7 @@ function buildUpdateStatus(home, statePatch = {}) {
348
361
  latest_version: latestVersion || null,
349
362
  update_available: updateAvailable,
350
363
  prompt_recommended: promptRecommended,
351
- busy: Boolean(state.busy),
364
+ busy,
352
365
  last_checked_at: state.last_checked_at || null,
353
366
  last_check_error: state.last_check_error || null,
354
367
  last_prompted_at: state.last_prompted_at || null,
@@ -358,7 +371,7 @@ function buildUpdateStatus(home, statePatch = {}) {
358
371
  last_update_started_at: state.last_update_started_at || null,
359
372
  last_update_finished_at: state.last_update_finished_at || null,
360
373
  last_update_result: state.last_update_result || null,
361
- target_version: normalizeVersion(state.target_version || '') || null,
374
+ target_version: busy ? targetVersion || latestVersion || null : null,
362
375
  manual_update_command: updateManualCommand(installMode),
363
376
  reason: support.reason,
364
377
  };
@@ -371,8 +384,16 @@ function checkForUpdates(home, { force = false, timeoutMs = 3500 } = {}) {
371
384
  const npmBinary = resolveNpmBinary();
372
385
  const launcherPath = resolveLauncherPath();
373
386
  const support = updateSupportSummary(installMode, npmBinary, launcherPath);
387
+ const existingBusyIsStale = Boolean(existing.busy) && !hasActiveBusyUpdate(existing, currentVersion);
374
388
 
375
389
  if (!force && existing.current_version === currentVersion && !isExpired(existing.last_checked_at, UPDATE_CHECK_TTL_MS)) {
390
+ if (existingBusyIsStale) {
391
+ const repaired = mergeUpdateState(home, {
392
+ busy: false,
393
+ target_version: null,
394
+ });
395
+ return buildUpdateStatus(home, repaired);
396
+ }
376
397
  return buildUpdateStatus(home);
377
398
  }
378
399
 
@@ -392,6 +413,13 @@ function checkForUpdates(home, { force = false, timeoutMs = 3500 } = {}) {
392
413
  last_checked_at: new Date().toISOString(),
393
414
  last_check_error: probe.ok ? null : probe.error,
394
415
  });
416
+ if (Boolean(patched.busy) && !hasActiveBusyUpdate(patched, currentVersion)) {
417
+ const repaired = mergeUpdateState(home, {
418
+ busy: false,
419
+ target_version: null,
420
+ });
421
+ return buildUpdateStatus(home, repaired);
422
+ }
395
423
  return buildUpdateStatus(home, patched);
396
424
  }
397
425
 
@@ -1142,6 +1170,40 @@ function buildGlobalWrapperScript({ installDir, home, commandName }) {
1142
1170
  return [
1143
1171
  '#!/usr/bin/env bash',
1144
1172
  'set -euo pipefail',
1173
+ 'WRAPPER_PATH="${BASH_SOURCE[0]}"',
1174
+ 'WRAPPER_DIR="$(cd "$(dirname "$WRAPPER_PATH")" && pwd)"',
1175
+ `PREFERRED_COMMAND="${commandName}"`,
1176
+ 'LOOKUP_PATH=""',
1177
+ 'OLD_IFS="$IFS"',
1178
+ 'IFS=:',
1179
+ 'for ENTRY in $PATH; do',
1180
+ ' if [ -z "$ENTRY" ]; then',
1181
+ ' continue',
1182
+ ' fi',
1183
+ ' ENTRY_REAL="$ENTRY"',
1184
+ ' if ENTRY_CANONICAL="$(cd "$ENTRY" 2>/dev/null && pwd)"; then',
1185
+ ' ENTRY_REAL="$ENTRY_CANONICAL"',
1186
+ ' fi',
1187
+ ' if [ "$ENTRY_REAL" = "$WRAPPER_DIR" ]; then',
1188
+ ' continue',
1189
+ ' fi',
1190
+ ' if [ -z "$LOOKUP_PATH" ]; then',
1191
+ ' LOOKUP_PATH="$ENTRY"',
1192
+ ' else',
1193
+ ' LOOKUP_PATH="$LOOKUP_PATH:$ENTRY"',
1194
+ ' fi',
1195
+ 'done',
1196
+ 'IFS="$OLD_IFS"',
1197
+ 'if [ -n "$LOOKUP_PATH" ]; then',
1198
+ ' if RESOLVED_LAUNCHER="$(PATH="$LOOKUP_PATH" command -v "$PREFERRED_COMMAND" 2>/dev/null)"; then',
1199
+ ' if [ -n "$RESOLVED_LAUNCHER" ] && [ "$RESOLVED_LAUNCHER" != "$WRAPPER_PATH" ]; then',
1200
+ ' if [ -z "${DEEPSCIENTIST_HOME:-}" ]; then',
1201
+ ` export DEEPSCIENTIST_HOME="${home}"`,
1202
+ ' fi',
1203
+ ' exec "$RESOLVED_LAUNCHER" "$@"',
1204
+ ' fi',
1205
+ ' fi',
1206
+ 'fi',
1145
1207
  'if [ -z "${DEEPSCIENTIST_HOME:-}" ]; then',
1146
1208
  ` export DEEPSCIENTIST_HOME="${home}"`,
1147
1209
  'fi',
@@ -1150,6 +1212,18 @@ function buildGlobalWrapperScript({ installDir, home, commandName }) {
1150
1212
  ].join('\n');
1151
1213
  }
1152
1214
 
1215
+ function buildLauncherWrapperScript({ launcherPath, home }) {
1216
+ return [
1217
+ '#!/usr/bin/env bash',
1218
+ 'set -euo pipefail',
1219
+ 'if [ -z "${DEEPSCIENTIST_HOME:-}" ]; then',
1220
+ ` export DEEPSCIENTIST_HOME="${home}"`,
1221
+ 'fi',
1222
+ `exec "${launcherPath}" "$@"`,
1223
+ '',
1224
+ ].join('\n');
1225
+ }
1226
+
1153
1227
  function writeExecutableScript(targetPath, content) {
1154
1228
  ensureDir(path.dirname(targetPath));
1155
1229
  fs.writeFileSync(targetPath, content, { encoding: 'utf8', mode: 0o755 });
@@ -1186,6 +1260,94 @@ function candidateWrapperPathsForCommand(commandName) {
1186
1260
  return candidates;
1187
1261
  }
1188
1262
 
1263
+ function parseLegacyWrapperCandidate(candidatePath) {
1264
+ let stat = null;
1265
+ try {
1266
+ stat = fs.lstatSync(candidatePath);
1267
+ } catch {
1268
+ return null;
1269
+ }
1270
+
1271
+ if (stat.isSymbolicLink()) {
1272
+ let resolved = null;
1273
+ try {
1274
+ resolved = fs.realpathSync(candidatePath);
1275
+ } catch {
1276
+ return null;
1277
+ }
1278
+ if (!/[\\/]cli[\\/]bin[\\/](?:ds|ds-cli|research|resear)(?:\.cmd)?$/.test(resolved)) {
1279
+ return null;
1280
+ }
1281
+ return {
1282
+ source: 'symlink',
1283
+ execPath: resolved,
1284
+ home: path.dirname(path.dirname(path.dirname(resolved))),
1285
+ };
1286
+ }
1287
+
1288
+ if (!stat.isFile()) {
1289
+ return null;
1290
+ }
1291
+
1292
+ let text = '';
1293
+ try {
1294
+ text = fs.readFileSync(candidatePath, 'utf8');
1295
+ } catch {
1296
+ return null;
1297
+ }
1298
+
1299
+ const execMatch = text.match(/exec "([^"\n]+[\\/]bin[\\/](?:ds|ds-cli|research|resear))" "\$@"/);
1300
+ if (!execMatch) {
1301
+ return null;
1302
+ }
1303
+ const execPath = execMatch[1];
1304
+ if (!/[\\/]cli[\\/]bin[\\/](?:ds|ds-cli|research|resear)$/.test(execPath)) {
1305
+ return null;
1306
+ }
1307
+ const homeMatch = text.match(/export DEEPSCIENTIST_HOME="([^"\n]+)"/);
1308
+ return {
1309
+ source: 'script',
1310
+ execPath,
1311
+ home: homeMatch ? homeMatch[1] : path.dirname(path.dirname(path.dirname(execPath))),
1312
+ };
1313
+ }
1314
+
1315
+ function repairLegacyPathWrappers({ home, launcherPath, force = false }) {
1316
+ if (process.platform === 'win32') {
1317
+ return [];
1318
+ }
1319
+ if (!launcherPath || !fs.existsSync(launcherPath)) {
1320
+ return [];
1321
+ }
1322
+ if (!force && detectInstallMode(repoRoot) !== 'npm-package') {
1323
+ return [];
1324
+ }
1325
+
1326
+ const rewritten = [];
1327
+ const seen = new Set();
1328
+ for (const commandName of launcherWrapperCommands) {
1329
+ for (const candidate of candidateWrapperPathsForCommand(commandName)) {
1330
+ if (seen.has(candidate)) {
1331
+ continue;
1332
+ }
1333
+ seen.add(candidate);
1334
+ const legacy = parseLegacyWrapperCandidate(candidate);
1335
+ if (!legacy) {
1336
+ continue;
1337
+ }
1338
+ writeExecutableScript(
1339
+ candidate,
1340
+ buildLauncherWrapperScript({
1341
+ launcherPath,
1342
+ home: legacy.home || home,
1343
+ })
1344
+ );
1345
+ rewritten.push(candidate);
1346
+ }
1347
+ }
1348
+ return rewritten;
1349
+ }
1350
+
1189
1351
  function rewriteLauncherWrappersIfPointingAtSource({ sourceHome, targetHome }) {
1190
1352
  if (process.platform === 'win32') {
1191
1353
  return [];
@@ -2622,19 +2784,45 @@ function spawnDetachedNode(args, options = {}) {
2622
2784
  async function performSelfUpdate(home, options = {}) {
2623
2785
  const status = checkForUpdates(home, { force: true });
2624
2786
  if (!status.update_available) {
2787
+ const message = `DeepScientist is already on the latest version (${status.current_version}).`;
2788
+ mergeUpdateState(home, {
2789
+ current_version: status.current_version,
2790
+ latest_version: status.latest_version,
2791
+ busy: false,
2792
+ target_version: null,
2793
+ last_update_finished_at: new Date().toISOString(),
2794
+ last_update_result: {
2795
+ ok: true,
2796
+ target_version: null,
2797
+ message,
2798
+ },
2799
+ });
2625
2800
  return {
2626
2801
  ok: true,
2627
2802
  updated: false,
2628
2803
  status,
2629
- message: `DeepScientist is already on the latest version (${status.current_version}).`,
2804
+ message,
2630
2805
  };
2631
2806
  }
2632
2807
  if (!status.can_self_update) {
2808
+ const message = status.reason || `Manual update required: ${status.manual_update_command}`;
2809
+ mergeUpdateState(home, {
2810
+ current_version: status.current_version,
2811
+ latest_version: status.latest_version,
2812
+ busy: false,
2813
+ target_version: null,
2814
+ last_update_finished_at: new Date().toISOString(),
2815
+ last_update_result: {
2816
+ ok: false,
2817
+ target_version: status.latest_version || null,
2818
+ message,
2819
+ },
2820
+ });
2633
2821
  return {
2634
2822
  ok: false,
2635
2823
  updated: false,
2636
2824
  status,
2637
- message: status.reason || `Manual update required: ${status.manual_update_command}`,
2825
+ message,
2638
2826
  };
2639
2827
  }
2640
2828
 
@@ -2697,6 +2885,11 @@ async function performSelfUpdate(home, options = {}) {
2697
2885
  };
2698
2886
  }
2699
2887
 
2888
+ repairLegacyPathWrappers({
2889
+ home,
2890
+ launcherPath: resolveLauncherPath(),
2891
+ });
2892
+
2700
2893
  const restartDaemon =
2701
2894
  options.restartDaemon === true
2702
2895
  || (options.restartDaemon !== false && Boolean(daemonState?.pid || daemonState?.daemon_id));
@@ -2799,6 +2992,22 @@ async function startBackgroundUpdateWorker(home, options = {}) {
2799
2992
  };
2800
2993
  }
2801
2994
  const status = checkForUpdates(home, { force: false });
2995
+ if (!status.update_available) {
2996
+ return {
2997
+ ok: true,
2998
+ started: false,
2999
+ message: `DeepScientist is already on the latest version (${status.current_version}).`,
3000
+ status,
3001
+ };
3002
+ }
3003
+ if (!status.can_self_update) {
3004
+ return {
3005
+ ok: false,
3006
+ started: false,
3007
+ message: status.reason || `Manual update required: ${status.manual_update_command}`,
3008
+ status,
3009
+ };
3010
+ }
2802
3011
  mergeUpdateState(home, {
2803
3012
  current_version: status.current_version,
2804
3013
  latest_version: status.latest_version,
@@ -3311,6 +3520,10 @@ async function launcherMain(rawArgs) {
3311
3520
  const home = options.home || resolveHome(rawArgs);
3312
3521
  applyLauncherProxy(options.proxy);
3313
3522
  ensureDir(home);
3523
+ repairLegacyPathWrappers({
3524
+ home,
3525
+ launcherPath: resolveLauncherPath(),
3526
+ });
3314
3527
 
3315
3528
  if (options.stop) {
3316
3529
  await stopDaemon(home);
@@ -3460,6 +3673,8 @@ module.exports = {
3460
3673
  parseLauncherArgs,
3461
3674
  normalizeProxyUrl,
3462
3675
  parseMigrateArgs,
3676
+ parseLegacyWrapperCandidate,
3677
+ repairLegacyPathWrappers,
3463
3678
  useEditableProjectInstall,
3464
3679
  compareVersions,
3465
3680
  detectInstallMode,
@@ -209,7 +209,44 @@ Example:
209
209
  Do not replace an experiment artifact with a memory card.
210
210
  Do not replace a reusable lesson with a progress artifact.
211
211
 
212
- ## 4. Bash exec usage
212
+ ## 4. Artifact metric-contract rules
213
+
214
+ Use `artifact` as the authoritative submission surface for baseline and main-experiment metrics.
215
+
216
+ ### `artifact.confirm_baseline(...)`
217
+
218
+ For a confirmed baseline:
219
+
220
+ - the canonical metric contract should live in `<baseline_root>/json/metric_contract.json`
221
+ - the canonical `metrics_summary` should be a flat top-level dictionary keyed by the paper-facing metric ids
222
+ - if the raw evaluator output is nested, map each required canonical metric through explicit `origin_path` fields inside `metric_contract.metrics`
223
+ - every canonical baseline metric entry should explain where the number came from:
224
+ - `description`
225
+ - either `derivation` or `origin_path`
226
+ - `source_ref`
227
+ - keep `primary_metric` as the headline metric only; do not use it to erase the rest of the accepted paper-facing comparison surface
228
+
229
+ ### `artifact.record_main_experiment(...)`
230
+
231
+ For a main experiment recorded against a confirmed baseline:
232
+
233
+ - use the confirmed baseline metric-contract JSON as the canonical comparison contract
234
+ - report every required baseline metric id in the main experiment submission
235
+ - extra metrics are allowed, but missing required baseline metrics are not
236
+ - keep the original evaluation code and metric definitions for the canonical baseline metrics
237
+ - if an extra evaluator is genuinely necessary, record it as supplementary evidence instead of replacing the canonical comparator
238
+
239
+ ### Validation and temporary notes
240
+
241
+ - when the MCP tool runs strict validation, contract failures return structured error payloads such as:
242
+ - `missing_metric_ids`
243
+ - `baseline_metric_ids`
244
+ - `baseline_metric_details`
245
+ - `evaluation_protocol_mismatch`
246
+ - `Result/metric.md` may be used as temporary scratch memory while working, but it is optional and not authoritative
247
+ - if `Result/metric.md` exists, reconcile it against the final baseline or main-experiment submission before calling the artifact tool
248
+
249
+ ## 5. Bash exec usage
213
250
 
214
251
  Use `bash_exec` for monitored commands:
215
252
 
@@ -226,7 +263,7 @@ bash_exec.bash_exec(mode="read", id="<bash_id>")
226
263
 
227
264
  Use `kill` only when the quest truly needs to stop the session.
228
265
 
229
- ## 5. Prompt-level expectations
266
+ ## 6. Prompt-level expectations
230
267
 
231
268
  The agent should normally follow this discipline:
232
269
 
@@ -237,7 +274,7 @@ The agent should normally follow this discipline:
237
274
  5. `bash_exec` for durable shell work
238
275
  6. `memory.write(...)` only after a real durable finding appears
239
276
 
240
- ## 6. UI expectation
277
+ ## 7. UI expectation
241
278
 
242
279
  In `/projects/{id}` Studio trace:
243
280
 
@@ -11,6 +11,7 @@ We especially thank the following projects for their ideas, research direction,
11
11
  - AlphaEvolve
12
12
  - OpenEvolve
13
13
  - EvoScientist
14
+ - Orchestra-Research
14
15
  - Orchestra-Research/AI-Research-SKILLs
15
16
 
16
17
  These projects have been important references for thinking about automated research, open-ended exploration, evolutionary search, experiment organization, and long-horizon research agents.
@@ -192,7 +192,44 @@ updated_at: 2026-03-11T18:00:00+00:00
192
192
  不要用 memory 代替实验 artifact。
193
193
  不要用 artifact 代替可复用知识卡。
194
194
 
195
- ## 4. Bash exec 的基本用法
195
+ ## 4. Artifact 指标契约规则
196
+
197
+ baseline 与主实验的正式指标提交,应以 `artifact` 为唯一权威入口。
198
+
199
+ ### `artifact.confirm_baseline(...)`
200
+
201
+ 对于已确认的 baseline:
202
+
203
+ - canonical metric contract 应保存在 `<baseline_root>/json/metric_contract.json`
204
+ - canonical `metrics_summary` 应是顶层扁平字典,key 直接使用论文面对比时的 metric id
205
+ - 如果原始评测输出是嵌套结构,应在 `metric_contract.metrics` 中为每个必需 canonical metric 提供显式 `origin_path`,而不是直接提交嵌套 blob
206
+ - 每个 canonical baseline metric 都应说明数值来源,至少包含:
207
+ - `description`
208
+ - `derivation` 或 `origin_path`
209
+ - `source_ref`
210
+ - `primary_metric` 只是 headline metric,不能借此删掉其他论文面对比所需指标
211
+
212
+ ### `artifact.record_main_experiment(...)`
213
+
214
+ 对于基于已确认 baseline 的主实验:
215
+
216
+ - 默认以已确认 baseline 的 metric-contract JSON 作为 canonical comparison contract
217
+ - 主实验提交时必须覆盖 baseline 的全部必需 metric id
218
+ - 可以多报额外指标,但不能缺少 baseline 的必需指标
219
+ - canonical baseline metrics 应继续使用原有评测代码和指标定义
220
+ - 如果确实需要额外评测器,应把它作为 supplementary evidence 记录,而不是替换 canonical comparator
221
+
222
+ ### 校验失败与临时记录
223
+
224
+ - 当 MCP 工具开启严格校验时,失败会返回结构化错误字段,例如:
225
+ - `missing_metric_ids`
226
+ - `baseline_metric_ids`
227
+ - `baseline_metric_details`
228
+ - `evaluation_protocol_mismatch`
229
+ - `Result/metric.md` 只可作为工作过程中的临时草稿/记忆文件,不是必需文件,也不是权威来源
230
+ - 如果存在 `Result/metric.md`,请在调用 artifact 提交前用它核对最终 baseline 或主实验提交内容,避免遗漏或写错
231
+
232
+ ## 5. Bash exec 的基本用法
196
233
 
197
234
  用于可监控命令:
198
235
 
@@ -209,7 +246,7 @@ bash_exec.bash_exec(mode="read", id="<bash_id>")
209
246
 
210
247
  只有在确实需要停止时才使用 `kill`。
211
248
 
212
- ## 5. Prompt 级纪律(建议)
249
+ ## 6. Prompt 级纪律(建议)
213
250
 
214
251
  通常推荐遵循:
215
252
 
@@ -220,7 +257,7 @@ bash_exec.bash_exec(mode="read", id="<bash_id>")
220
257
  5. 长任务 shell 用 `bash_exec`
221
258
  6. 有真正的可复用发现才 `memory.write(...)`
222
259
 
223
- ## 6. UI 期望
260
+ ## 7. UI 期望
224
261
 
225
262
  在 `/projects/{id}` 的 Studio trace 中:
226
263
 
@@ -11,6 +11,7 @@ DeepScientist 的构思、架构设计与实现过程中,受到了许多优秀
11
11
  - AlphaEvolve
12
12
  - OpenEvolve
13
13
  - EvoScientist
14
+ - Orchestra-Research
14
15
  - Orchestra-Research/AI-Research-SKILLs
15
16
 
16
17
  这些项目在自动化科研、开放式探索、进化式搜索、实验组织与智能研究代理等方向上的探索,为 DeepScientist 的设计提供了重要参照。
package/install.sh CHANGED
@@ -421,6 +421,40 @@ write_global_wrapper() {
421
421
  cat >"$target_path" <<EOF
422
422
  #!/usr/bin/env bash
423
423
  set -euo pipefail
424
+ WRAPPER_PATH="\${BASH_SOURCE[0]}"
425
+ WRAPPER_DIR="\$(cd "\$(dirname "\$WRAPPER_PATH")" && pwd)"
426
+ PREFERRED_COMMAND="$command_name"
427
+ LOOKUP_PATH=""
428
+ OLD_IFS="\$IFS"
429
+ IFS=:
430
+ for ENTRY in \$PATH; do
431
+ if [ -z "\$ENTRY" ]; then
432
+ continue
433
+ fi
434
+ ENTRY_REAL="\$ENTRY"
435
+ if ENTRY_CANONICAL="\$(cd "\$ENTRY" 2>/dev/null && pwd)"; then
436
+ ENTRY_REAL="\$ENTRY_CANONICAL"
437
+ fi
438
+ if [ "\$ENTRY_REAL" = "\$WRAPPER_DIR" ]; then
439
+ continue
440
+ fi
441
+ if [ -z "\$LOOKUP_PATH" ]; then
442
+ LOOKUP_PATH="\$ENTRY"
443
+ else
444
+ LOOKUP_PATH="\$LOOKUP_PATH:\$ENTRY"
445
+ fi
446
+ done
447
+ IFS="\$OLD_IFS"
448
+ if [ -n "\$LOOKUP_PATH" ]; then
449
+ if RESOLVED_LAUNCHER="\$(PATH="\$LOOKUP_PATH" command -v "\$PREFERRED_COMMAND" 2>/dev/null)"; then
450
+ if [ -n "\$RESOLVED_LAUNCHER" ] && [ "\$RESOLVED_LAUNCHER" != "\$WRAPPER_PATH" ]; then
451
+ if [ -z "\${DEEPSCIENTIST_HOME:-}" ]; then
452
+ export DEEPSCIENTIST_HOME="$BASE_DIR"
453
+ fi
454
+ exec "\$RESOLVED_LAUNCHER" "\$@"
455
+ fi
456
+ fi
457
+ fi
424
458
  if [ -z "\${DEEPSCIENTIST_HOME:-}" ]; then
425
459
  export DEEPSCIENTIST_HOME="$BASE_DIR"
426
460
  fi
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@researai/deepscientist",
3
- "version": "1.5.7",
3
+ "version": "1.5.8",
4
4
  "description": "Local-first research operating system with a Python runtime and npm launcher",
5
5
  "license": "MIT",
6
6
  "files": [
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.7"
7
+ version = "1.5.8"
8
8
  description = "DeepScientist Core skeleton"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -5,4 +5,4 @@ __all__ = ["__version__"]
5
5
  try:
6
6
  __version__ = _package_version("deepscientist")
7
7
  except PackageNotFoundError: # pragma: no cover - source checkout fallback
8
- __version__ = "1.5.7"
8
+ __version__ = "1.5.8"
@@ -85,6 +85,7 @@ def build_session_descriptor(
85
85
  "mcp_servers": [
86
86
  {"name": "memory", "transport": "stdio", "scope": "quest-local"},
87
87
  {"name": "artifact", "transport": "stdio", "scope": "quest-local"},
88
+ {"name": "bash_exec", "transport": "stdio", "scope": "quest-local"},
88
89
  ],
89
90
  "slash_commands": build_slash_commands(quest_id),
90
91
  "meta": {