@researai/deepscientist 1.5.13 → 1.5.15
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.
- package/README.md +8 -0
- package/assets/branding/logo-raster.png +0 -0
- package/bin/ds.js +134 -49
- package/docs/en/00_QUICK_START.md +2 -2
- package/docs/en/01_SETTINGS_REFERENCE.md +20 -4
- package/docs/en/03_QQ_CONNECTOR_GUIDE.md +19 -0
- package/docs/en/05_TUI_GUIDE.md +466 -96
- package/docs/en/10_WEIXIN_CONNECTOR_GUIDE.md +20 -0
- package/docs/en/14_PROMPT_SKILLS_AND_MCP_GUIDE.md +2 -0
- package/docs/en/16_TELEGRAM_CONNECTOR_GUIDE.md +134 -0
- package/docs/en/17_WHATSAPP_CONNECTOR_GUIDE.md +126 -0
- package/docs/en/18_FEISHU_CONNECTOR_GUIDE.md +136 -0
- package/docs/en/README.md +8 -0
- package/docs/zh/00_QUICK_START.md +2 -2
- package/docs/zh/01_SETTINGS_REFERENCE.md +20 -4
- package/docs/zh/03_QQ_CONNECTOR_GUIDE.md +19 -0
- package/docs/zh/05_TUI_GUIDE.md +465 -82
- package/docs/zh/10_WEIXIN_CONNECTOR_GUIDE.md +20 -0
- package/docs/zh/14_PROMPT_SKILLS_AND_MCP_GUIDE.md +2 -0
- package/docs/zh/16_TELEGRAM_CONNECTOR_GUIDE.md +134 -0
- package/docs/zh/17_WHATSAPP_CONNECTOR_GUIDE.md +126 -0
- package/docs/zh/18_FEISHU_CONNECTOR_GUIDE.md +136 -0
- package/docs/zh/README.md +8 -0
- package/install.sh +2 -0
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/deepscientist/__init__.py +1 -1
- package/src/deepscientist/artifact/charts.py +567 -0
- package/src/deepscientist/artifact/guidance.py +50 -10
- package/src/deepscientist/artifact/metrics.py +228 -5
- package/src/deepscientist/artifact/schemas.py +3 -0
- package/src/deepscientist/artifact/service.py +4004 -538
- package/src/deepscientist/bash_exec/models.py +23 -0
- package/src/deepscientist/bash_exec/monitor.py +147 -67
- package/src/deepscientist/bash_exec/runtime.py +218 -156
- package/src/deepscientist/bash_exec/service.py +79 -64
- package/src/deepscientist/bash_exec/shells.py +87 -0
- package/src/deepscientist/bridges/connectors.py +51 -2
- package/src/deepscientist/config/models.py +6 -3
- package/src/deepscientist/config/service.py +7 -2
- package/src/deepscientist/connector/lingzhu_support.py +23 -4
- package/src/deepscientist/connector/weixin_support.py +122 -1
- package/src/deepscientist/daemon/api/handlers.py +75 -4
- package/src/deepscientist/daemon/api/router.py +1 -0
- package/src/deepscientist/daemon/app.py +869 -236
- package/src/deepscientist/doctor.py +51 -0
- package/src/deepscientist/file_lock.py +48 -0
- package/src/deepscientist/gitops/diff.py +167 -1
- package/src/deepscientist/mcp/server.py +331 -21
- package/src/deepscientist/process_control.py +161 -0
- package/src/deepscientist/prompts/builder.py +275 -491
- package/src/deepscientist/quest/service.py +2336 -145
- package/src/deepscientist/quest/stage_views.py +305 -29
- package/src/deepscientist/runners/base.py +2 -0
- package/src/deepscientist/runners/codex.py +88 -5
- package/src/deepscientist/runners/runtime_overrides.py +17 -1
- package/src/deepscientist/shared.py +6 -1
- package/src/prompts/contracts/shared_interaction.md +13 -4
- package/src/prompts/system.md +984 -1985
- package/src/skills/analysis-campaign/SKILL.md +31 -2
- package/src/skills/analysis-campaign/references/artifact-orchestration.md +1 -1
- package/src/skills/analysis-campaign/references/writing-facing-slice-examples.md +65 -0
- package/src/skills/baseline/SKILL.md +267 -994
- package/src/skills/baseline/references/baseline-checklist-template.md +21 -32
- package/src/skills/baseline/references/baseline-plan-template.md +41 -57
- package/src/skills/decision/SKILL.md +19 -2
- package/src/skills/experiment/SKILL.md +8 -2
- package/src/skills/finalize/SKILL.md +18 -0
- package/src/skills/idea/SKILL.md +78 -0
- package/src/skills/idea/references/idea-generation-playbook.md +100 -0
- package/src/skills/idea/references/outline-seeding-example.md +60 -0
- package/src/skills/intake-audit/SKILL.md +1 -1
- package/src/skills/optimize/SKILL.md +1644 -0
- package/src/skills/rebuttal/SKILL.md +2 -1
- package/src/skills/review/SKILL.md +2 -1
- package/src/skills/write/SKILL.md +80 -12
- package/src/skills/write/references/outline-evidence-contract-example.md +107 -0
- package/src/tui/dist/app/AppContainer.js +1445 -52
- package/src/tui/dist/components/Composer.js +1 -1
- package/src/tui/dist/components/ConfigScreen.js +190 -36
- package/src/tui/dist/components/GradientStatusText.js +1 -20
- package/src/tui/dist/components/InputPrompt.js +41 -32
- package/src/tui/dist/components/LoadingIndicator.js +1 -1
- package/src/tui/dist/components/Logo.js +61 -38
- package/src/tui/dist/components/MainContent.js +10 -3
- package/src/tui/dist/components/WelcomePanel.js +4 -12
- package/src/tui/dist/components/messages/AssistantMessage.js +1 -1
- package/src/tui/dist/components/messages/BashExecOperationMessage.js +3 -3
- package/src/tui/dist/components/messages/OperationMessage.js +1 -1
- package/src/tui/dist/index.js +28 -1
- package/src/tui/dist/layouts/DefaultAppLayout.js +3 -3
- package/src/tui/dist/lib/api.js +17 -0
- package/src/tui/dist/lib/connectors.js +261 -0
- package/src/tui/dist/semantic-colors.js +29 -19
- package/src/tui/package.json +1 -1
- package/src/ui/dist/assets/{AiManusChatView-CnJcXynW.js → AiManusChatView-DDjbFnbt.js} +12 -12
- package/src/ui/dist/assets/{AnalysisPlugin-DeyzPEhV.js → AnalysisPlugin-Yb5IdmaU.js} +1 -1
- package/src/ui/dist/assets/CliPlugin-e64sreyu.js +31037 -0
- package/src/ui/dist/assets/{CodeEditorPlugin-B-xicq1e.js → CodeEditorPlugin-C4D2TIkU.js} +8 -8
- package/src/ui/dist/assets/{CodeViewerPlugin-DT54ysXa.js → CodeViewerPlugin-BVoNZIvC.js} +5 -5
- package/src/ui/dist/assets/{DocViewerPlugin-DQtKT-VD.js → DocViewerPlugin-CLChbllo.js} +3 -3
- package/src/ui/dist/assets/{GitDiffViewerPlugin-hqHbCfnv.js → GitDiffViewerPlugin-C4xeFyFQ.js} +20 -20
- package/src/ui/dist/assets/{ImageViewerPlugin-OcVo33jV.js → ImageViewerPlugin-OiMUAcLi.js} +5 -5
- package/src/ui/dist/assets/{LabCopilotPanel-DdGwhEUV.js → LabCopilotPanel-BjD2ThQF.js} +11 -11
- package/src/ui/dist/assets/{LabPlugin-Ciz1gDaX.js → LabPlugin-DQPg-NrB.js} +2 -2
- package/src/ui/dist/assets/{LatexPlugin-BhmjNQRC.js → LatexPlugin-CI05XAV9.js} +7 -7
- package/src/ui/dist/assets/{MarkdownViewerPlugin-BzdVH9Bx.js → MarkdownViewerPlugin-DpeBLYZf.js} +4 -4
- package/src/ui/dist/assets/{MarketplacePlugin-DmyHspXt.js → MarketplacePlugin-DolE58Q2.js} +3 -3
- package/src/ui/dist/assets/{NotebookEditor-BTVYRGkm.js → NotebookEditor-7Qm2rSWD.js} +11 -11
- package/src/ui/dist/assets/{NotebookEditor-BMXKrDRk.js → NotebookEditor-C1kWaxKi.js} +1 -1
- package/src/ui/dist/assets/{PdfLoader-CvcjJHXv.js → PdfLoader-BfOHw8Zw.js} +1 -1
- package/src/ui/dist/assets/{PdfMarkdownPlugin-DW2ej8Vk.js → PdfMarkdownPlugin-BulDREv1.js} +2 -2
- package/src/ui/dist/assets/{PdfViewerPlugin-CmlDxbhU.js → PdfViewerPlugin-C-daaOaL.js} +10 -10
- package/src/ui/dist/assets/{SearchPlugin-DAjQZPSv.js → SearchPlugin-CjpaiJ3A.js} +1 -1
- package/src/ui/dist/assets/{TextViewerPlugin-C-nVAZb_.js → TextViewerPlugin-BxIyqPQC.js} +5 -5
- package/src/ui/dist/assets/{VNCViewer-D7-dIYon.js → VNCViewer-HAg9mF7M.js} +10 -10
- package/src/ui/dist/assets/{bot-C_G4WtNI.js → bot-0DYntytV.js} +1 -1
- package/src/ui/dist/assets/{code-Cd7WfiWq.js → code-B20Slj_w.js} +1 -1
- package/src/ui/dist/assets/{file-content-B57zsL9y.js → file-content-DT24KFma.js} +1 -1
- package/src/ui/dist/assets/{file-diff-panel-DVoheLFq.js → file-diff-panel-DK13YPql.js} +1 -1
- package/src/ui/dist/assets/{file-socket-B5kXFxZP.js → file-socket-B4T2o4nR.js} +1 -1
- package/src/ui/dist/assets/{image-LLOjkMHF.js → image-DSeR_sDS.js} +1 -1
- package/src/ui/dist/assets/{index-hOUOWbW2.js → index-BrFje2Uk.js} +2 -2
- package/src/ui/dist/assets/{index-Dxa2eYMY.js → index-BwRJaoTl.js} +1 -1
- package/src/ui/dist/assets/{index-CLQauncb.js → index-D_E4281X.js} +5418 -28620
- package/src/ui/dist/assets/{index-C3r2iGrp.js → index-DnYB3xb1.js} +12 -12
- package/src/ui/dist/assets/{index-BQG-1s2o.css → index-G7AcWcMu.css} +43 -2
- package/src/ui/dist/assets/{monaco-BGGAEii3.js → monaco-LExaAN3Y.js} +1 -1
- package/src/ui/dist/assets/{pdf-effect-queue-DlEr1_y5.js → pdf-effect-queue-BJk5okWJ.js} +1 -1
- package/src/ui/dist/assets/{popover-CWJbJuYY.js → popover-D3Gg_FoV.js} +1 -1
- package/src/ui/dist/assets/{project-sync-CRJiucYO.js → project-sync-C_ygLlVU.js} +1 -1
- package/src/ui/dist/assets/{select-CoHB7pvH.js → select-CpAK6uWm.js} +2 -2
- package/src/ui/dist/assets/{sigma-D5aJWR8J.js → sigma-DEccaSgk.js} +1 -1
- package/src/ui/dist/assets/{square-check-big-DUK_mnkS.js → square-check-big-uUfyVsbD.js} +1 -1
- package/src/ui/dist/assets/{trash-ChU3SEE3.js → trash-CXvwwSe8.js} +1 -1
- package/src/ui/dist/assets/{useCliAccess-BrJBV3tY.js → useCliAccess-Bnop4mgR.js} +1 -1
- package/src/ui/dist/assets/{useFileDiffOverlay-C2OQaVWc.js → useFileDiffOverlay-B8eUAX0I.js} +1 -1
- package/src/ui/dist/assets/{wrap-text-C7Qqh-om.js → wrap-text-9vbOBpkW.js} +1 -1
- package/src/ui/dist/assets/{zoom-out-rtX0FKya.js → zoom-out-BgVMmOW4.js} +1 -1
- package/src/ui/dist/index.html +2 -2
- package/uv.lock +1 -1
- package/src/ui/dist/assets/CliPlugin-CB1YODQn.js +0 -5905
package/README.md
CHANGED
|
@@ -26,6 +26,9 @@
|
|
|
26
26
|
<p align="center">
|
|
27
27
|
<a href="docs/en/00_QUICK_START.md">Quick Start</a> •
|
|
28
28
|
<a href="docs/en/02_START_RESEARCH_GUIDE.md">Start Research Guide</a> •
|
|
29
|
+
<a href="docs/en/16_TELEGRAM_CONNECTOR_GUIDE.md">Telegram</a> •
|
|
30
|
+
<a href="docs/en/17_WHATSAPP_CONNECTOR_GUIDE.md">WhatsApp</a> •
|
|
31
|
+
<a href="docs/en/18_FEISHU_CONNECTOR_GUIDE.md">Feishu</a> •
|
|
29
32
|
<a href="docs/en/10_WEIXIN_CONNECTOR_GUIDE.md"><img src="assets/branding/connector-weixin.png" alt="Weixin" width="14" height="14" /> Weixin</a> •
|
|
30
33
|
<a href="docs/en/03_QQ_CONNECTOR_GUIDE.md"><img src="assets/branding/connector-qq.png" alt="QQ" width="14" height="14" /> QQ</a> •
|
|
31
34
|
<a href="docs/en/04_LINGZHU_CONNECTOR_GUIDE.md"><img src="assets/branding/connector-rokid.png" alt="Rokid" width="14" height="14" /> Rokid</a> •
|
|
@@ -95,6 +98,8 @@ ds --yolo --here
|
|
|
95
98
|
|
|
96
99
|
If `codex --login` is unavailable, run `codex` once and finish authentication there. After startup, open `http://127.0.0.1:20999`.
|
|
97
100
|
|
|
101
|
+
Linux and macOS remain the most battle-tested platforms. Native Windows support is now experimental; if you need the closest Linux-like terminal behavior, prefer WSL2.
|
|
102
|
+
|
|
98
103
|
For detailed install, troubleshooting, PDF compile, and other launch modes, use:
|
|
99
104
|
|
|
100
105
|
- [Quick Start](docs/en/00_QUICK_START.md)
|
|
@@ -108,6 +113,9 @@ For detailed install, troubleshooting, PDF compile, and other launch modes, use:
|
|
|
108
113
|
- [Core Architecture Guide (English)](docs/en/13_CORE_ARCHITECTURE_GUIDE.md)
|
|
109
114
|
- [Prompt, Skills, and MCP Guide (English)](docs/en/14_PROMPT_SKILLS_AND_MCP_GUIDE.md)
|
|
110
115
|
- [Weixin Connector Guide (English)](docs/en/10_WEIXIN_CONNECTOR_GUIDE.md)
|
|
116
|
+
- [Telegram Connector Guide (English)](docs/en/16_TELEGRAM_CONNECTOR_GUIDE.md)
|
|
117
|
+
- [WhatsApp Connector Guide (English)](docs/en/17_WHATSAPP_CONNECTOR_GUIDE.md)
|
|
118
|
+
- [Feishu Connector Guide (English)](docs/en/18_FEISHU_CONNECTOR_GUIDE.md)
|
|
111
119
|
- [QQ Connector Guide (English)](docs/en/03_QQ_CONNECTOR_GUIDE.md)
|
|
112
120
|
- [Lingzhu / Rokid Guide (English)](docs/en/04_LINGZHU_CONNECTOR_GUIDE.md)
|
|
113
121
|
- [Memory and MCP Guide (English)](docs/en/07_MEMORY_AND_MCP.md)
|
|
Binary file
|
package/bin/ds.js
CHANGED
|
@@ -38,13 +38,14 @@ const UPDATE_CHECK_TTL_MS = 12 * 60 * 60 * 1000;
|
|
|
38
38
|
|
|
39
39
|
const optionsWithValues = new Set(['--home', '--host', '--port', '--quest-id', '--mode', '--proxy', '--codex-profile', '--codex']);
|
|
40
40
|
|
|
41
|
-
function buildCodexOverrideEnv({ yolo =
|
|
41
|
+
function buildCodexOverrideEnv({ yolo = true, profile = null, binary = null } = {}) {
|
|
42
42
|
const normalizedProfile = typeof profile === 'string' ? profile.trim() : '';
|
|
43
43
|
const normalizedBinary = typeof binary === 'string' ? binary.trim() : '';
|
|
44
44
|
const overrides = {};
|
|
45
45
|
if (normalizedBinary) {
|
|
46
46
|
overrides.DEEPSCIENTIST_CODEX_BINARY = normalizedBinary;
|
|
47
47
|
}
|
|
48
|
+
overrides.DEEPSCIENTIST_CODEX_YOLO = yolo ? '1' : '0';
|
|
48
49
|
if (!yolo) {
|
|
49
50
|
if (normalizedProfile) {
|
|
50
51
|
overrides.DEEPSCIENTIST_CODEX_PROFILE = normalizedProfile;
|
|
@@ -52,7 +53,6 @@ function buildCodexOverrideEnv({ yolo = false, profile = null, binary = null } =
|
|
|
52
53
|
}
|
|
53
54
|
return overrides;
|
|
54
55
|
}
|
|
55
|
-
overrides.DEEPSCIENTIST_CODEX_YOLO = '1';
|
|
56
56
|
if (normalizedProfile) {
|
|
57
57
|
overrides.DEEPSCIENTIST_CODEX_PROFILE = normalizedProfile;
|
|
58
58
|
overrides.DEEPSCIENTIST_CODEX_MODEL = 'inherit';
|
|
@@ -69,6 +69,41 @@ function readOptionValue(argv, optionName) {
|
|
|
69
69
|
return null;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
function parseBooleanFlagValue(rawValue) {
|
|
73
|
+
const normalized = String(rawValue || '').trim().toLowerCase();
|
|
74
|
+
if (!normalized) return null;
|
|
75
|
+
if (['1', 'true', 'yes', 'on', 'y'].includes(normalized)) return true;
|
|
76
|
+
if (['0', 'false', 'no', 'off', 'n'].includes(normalized)) return false;
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function parseYoloArg(args, index, currentValue = true) {
|
|
81
|
+
const arg = args[index];
|
|
82
|
+
if (arg === '--yolo') {
|
|
83
|
+
const parsed = parseBooleanFlagValue(args[index + 1]);
|
|
84
|
+
if (parsed === null) {
|
|
85
|
+
return { matched: true, value: true, consumed: 1 };
|
|
86
|
+
}
|
|
87
|
+
return { matched: true, value: parsed, consumed: 2 };
|
|
88
|
+
}
|
|
89
|
+
if (typeof arg === 'string' && arg.startsWith('--yolo=')) {
|
|
90
|
+
const parsed = parseBooleanFlagValue(arg.slice('--yolo='.length));
|
|
91
|
+
return { matched: true, value: parsed === null ? true : parsed, consumed: 1 };
|
|
92
|
+
}
|
|
93
|
+
return { matched: false, value: currentValue, consumed: 0 };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function resolveYoloFlag(args, defaultValue = true) {
|
|
97
|
+
let value = defaultValue;
|
|
98
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
99
|
+
const parsed = parseYoloArg(args, index, value);
|
|
100
|
+
if (!parsed.matched) continue;
|
|
101
|
+
value = parsed.value;
|
|
102
|
+
index += Math.max(0, parsed.consumed - 1);
|
|
103
|
+
}
|
|
104
|
+
return value;
|
|
105
|
+
}
|
|
106
|
+
|
|
72
107
|
function printLauncherHelp() {
|
|
73
108
|
console.log(`DeepScientist launcher
|
|
74
109
|
|
|
@@ -105,7 +140,7 @@ Launcher flags:
|
|
|
105
140
|
--home <path> Use a custom DeepScientist home
|
|
106
141
|
--here Create/use ./DeepScientist under the current working directory as home
|
|
107
142
|
--proxy <url> Use an outbound HTTP/WS proxy for npm and Python runtime traffic
|
|
108
|
-
--yolo
|
|
143
|
+
--yolo [true|false] Control Codex YOLO mode. Default is true; pass false to restore on-request + workspace-write
|
|
109
144
|
--codex-profile <id> Run DeepScientist with a specific Codex profile, for example \`m27\`
|
|
110
145
|
--codex <path> Run DeepScientist with a specific Codex executable path for this launch
|
|
111
146
|
--quest-id <id> Open the TUI on one quest directly
|
|
@@ -314,11 +349,11 @@ function fetchLatestPublishedVersion({ npmBinary, timeoutMs = 3500 }) {
|
|
|
314
349
|
latestVersion: null,
|
|
315
350
|
};
|
|
316
351
|
}
|
|
317
|
-
const result = spawnSync(npmBinary, ['view', UPDATE_PACKAGE_NAME, 'version', '--json'], {
|
|
352
|
+
const result = spawnSync(npmBinary, ['view', UPDATE_PACKAGE_NAME, 'version', '--json'], syncSpawnOptions({
|
|
318
353
|
encoding: 'utf8',
|
|
319
354
|
env: process.env,
|
|
320
355
|
timeout: timeoutMs,
|
|
321
|
-
});
|
|
356
|
+
}));
|
|
322
357
|
if (result.error) {
|
|
323
358
|
return {
|
|
324
359
|
ok: false,
|
|
@@ -606,7 +641,7 @@ function renderBrandArtwork() {
|
|
|
606
641
|
const result = spawnSync(
|
|
607
642
|
chafa,
|
|
608
643
|
['--size', `${width}x${height}`, '--format', 'symbols', '--colors', '16', brandPath],
|
|
609
|
-
{ encoding: 'utf8' }
|
|
644
|
+
syncSpawnOptions({ encoding: 'utf8' })
|
|
610
645
|
);
|
|
611
646
|
if (result.status === 0 && result.stdout && result.stdout.trim()) {
|
|
612
647
|
return result.stdout.replace(/\s+$/, '').split(/\r?\n/);
|
|
@@ -984,7 +1019,7 @@ function parseLauncherArgs(argv) {
|
|
|
984
1019
|
let status = false;
|
|
985
1020
|
let daemonOnly = false;
|
|
986
1021
|
let skipUpdateCheck = false;
|
|
987
|
-
let yolo =
|
|
1022
|
+
let yolo = true;
|
|
988
1023
|
let codexProfile = null;
|
|
989
1024
|
let codexBinary = null;
|
|
990
1025
|
|
|
@@ -1005,17 +1040,22 @@ function parseLauncherArgs(argv) {
|
|
|
1005
1040
|
else if (arg === '--open-browser') openBrowser = true;
|
|
1006
1041
|
else if (arg === '--daemon-only') daemonOnly = true;
|
|
1007
1042
|
else if (arg === '--skip-update-check') skipUpdateCheck = true;
|
|
1008
|
-
else
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1043
|
+
else {
|
|
1044
|
+
const parsedYolo = parseYoloArg(args, index, yolo);
|
|
1045
|
+
if (parsedYolo.matched) {
|
|
1046
|
+
yolo = parsedYolo.value;
|
|
1047
|
+
index += Math.max(0, parsedYolo.consumed - 1);
|
|
1048
|
+
} else if (arg === '--codex-profile' && args[index + 1]) codexProfile = args[++index];
|
|
1049
|
+
else if (arg === '--codex' && args[index + 1]) codexBinary = args[++index];
|
|
1050
|
+
else if (arg === '--host' && args[index + 1]) host = args[++index];
|
|
1051
|
+
else if (arg === '--port' && args[index + 1]) port = Number(args[++index]);
|
|
1052
|
+
else if (arg === '--home' && args[index + 1]) home = path.resolve(args[++index]);
|
|
1053
|
+
else if (arg === '--proxy' && args[index + 1]) proxy = args[++index];
|
|
1054
|
+
else if (arg === '--quest-id' && args[index + 1]) questId = args[++index];
|
|
1055
|
+
else if (arg === '--mode' && args[index + 1]) mode = normalizeMode(args[++index]);
|
|
1056
|
+
else if (arg === '--help' || arg === '-h') return { help: true };
|
|
1057
|
+
else if (!arg.startsWith('--')) return null;
|
|
1058
|
+
}
|
|
1019
1059
|
}
|
|
1020
1060
|
|
|
1021
1061
|
return {
|
|
@@ -1172,6 +1212,11 @@ function parseMigrateArgs(argv) {
|
|
|
1172
1212
|
function findFirstPositionalArg(args) {
|
|
1173
1213
|
for (let index = 0; index < args.length; index += 1) {
|
|
1174
1214
|
const arg = args[index];
|
|
1215
|
+
const parsedYolo = parseYoloArg(args, index);
|
|
1216
|
+
if (parsedYolo.matched) {
|
|
1217
|
+
index += Math.max(0, parsedYolo.consumed - 1);
|
|
1218
|
+
continue;
|
|
1219
|
+
}
|
|
1175
1220
|
if (optionsWithValues.has(arg)) {
|
|
1176
1221
|
index += 1;
|
|
1177
1222
|
continue;
|
|
@@ -1465,11 +1510,14 @@ function scheduleDeferredSourceCleanup({ sourceHome, targetHome }) {
|
|
|
1465
1510
|
' }',
|
|
1466
1511
|
'})();',
|
|
1467
1512
|
].join('\n');
|
|
1468
|
-
const child = spawn(
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1513
|
+
const child = spawn(
|
|
1514
|
+
process.execPath,
|
|
1515
|
+
['-e', helperScript, String(process.pid), sourceHome, logPath],
|
|
1516
|
+
detachedSpawnOptions({
|
|
1517
|
+
stdio: 'ignore',
|
|
1518
|
+
env: process.env,
|
|
1519
|
+
})
|
|
1520
|
+
);
|
|
1473
1521
|
child.unref();
|
|
1474
1522
|
}
|
|
1475
1523
|
|
|
@@ -1554,10 +1602,10 @@ function probePython(binary) {
|
|
|
1554
1602
|
' "patch": sys.version_info[2],',
|
|
1555
1603
|
'}, ensure_ascii=False))',
|
|
1556
1604
|
].join('\n');
|
|
1557
|
-
const result = spawnSync(binary, ['-c', snippet], {
|
|
1605
|
+
const result = spawnSync(binary, ['-c', snippet], syncSpawnOptions({
|
|
1558
1606
|
encoding: 'utf8',
|
|
1559
1607
|
env: process.env,
|
|
1560
|
-
});
|
|
1608
|
+
}));
|
|
1561
1609
|
if (result.error) {
|
|
1562
1610
|
return {
|
|
1563
1611
|
ok: false,
|
|
@@ -1830,6 +1878,7 @@ function runSync(binary, args, options = {}) {
|
|
|
1830
1878
|
env: options.env || process.env,
|
|
1831
1879
|
encoding: 'utf8',
|
|
1832
1880
|
input: options.input,
|
|
1881
|
+
windowsHide: process.platform === 'win32',
|
|
1833
1882
|
});
|
|
1834
1883
|
if (result.error) {
|
|
1835
1884
|
throw result.error;
|
|
@@ -1847,12 +1896,30 @@ function step(index, total, message) {
|
|
|
1847
1896
|
console.log(`[${index}/${total}] ${message}`);
|
|
1848
1897
|
}
|
|
1849
1898
|
|
|
1899
|
+
function detachedSpawnOptions(options = {}) {
|
|
1900
|
+
return {
|
|
1901
|
+
...options,
|
|
1902
|
+
detached: true,
|
|
1903
|
+
windowsHide: process.platform === 'win32',
|
|
1904
|
+
};
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1907
|
+
function syncSpawnOptions(options = {}) {
|
|
1908
|
+
return {
|
|
1909
|
+
...options,
|
|
1910
|
+
windowsHide: process.platform === 'win32',
|
|
1911
|
+
};
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1850
1914
|
function verifyPythonRuntime(runtimePython) {
|
|
1851
1915
|
const result = runSync(
|
|
1852
1916
|
runtimePython,
|
|
1853
1917
|
['-c', 'import deepscientist.cli; import cryptography; import _cffi_backend; print("ok")'],
|
|
1854
1918
|
{ capture: true, allowFailure: true }
|
|
1855
1919
|
);
|
|
1920
|
+
if (result.status !== 0 && result.stderr) {
|
|
1921
|
+
process.stderr.write(result.stderr);
|
|
1922
|
+
}
|
|
1856
1923
|
return result.status === 0;
|
|
1857
1924
|
}
|
|
1858
1925
|
|
|
@@ -1999,11 +2066,11 @@ function downloadFileWithNode(url, destinationPath) {
|
|
|
1999
2066
|
' process.exit(1);',
|
|
2000
2067
|
'});',
|
|
2001
2068
|
].join('\n');
|
|
2002
|
-
const result = spawnSync(process.execPath, ['-e', downloader, url, destinationPath, '45000'], {
|
|
2069
|
+
const result = spawnSync(process.execPath, ['-e', downloader, url, destinationPath, '45000'], syncSpawnOptions({
|
|
2003
2070
|
cwd: repoRoot,
|
|
2004
2071
|
stdio: 'inherit',
|
|
2005
2072
|
env: process.env,
|
|
2006
|
-
});
|
|
2073
|
+
}));
|
|
2007
2074
|
if (result.error) {
|
|
2008
2075
|
throw result.error;
|
|
2009
2076
|
}
|
|
@@ -2054,11 +2121,11 @@ function installLocalUv(home) {
|
|
|
2054
2121
|
shellArgs = [installerPath];
|
|
2055
2122
|
}
|
|
2056
2123
|
|
|
2057
|
-
const installResult = spawnSync(shellBinary, shellArgs, {
|
|
2124
|
+
const installResult = spawnSync(shellBinary, shellArgs, syncSpawnOptions({
|
|
2058
2125
|
cwd: repoRoot,
|
|
2059
2126
|
stdio: 'inherit',
|
|
2060
2127
|
env: installEnv,
|
|
2061
|
-
});
|
|
2128
|
+
}));
|
|
2062
2129
|
if (installResult.error) {
|
|
2063
2130
|
throw installResult.error;
|
|
2064
2131
|
}
|
|
@@ -2155,6 +2222,20 @@ function ensureUvManagedPython(home, uvBinary, minimumVersionRequest) {
|
|
|
2155
2222
|
return probe;
|
|
2156
2223
|
}
|
|
2157
2224
|
|
|
2225
|
+
function resolveBackgroundPythonExecutable(runtimePython) {
|
|
2226
|
+
const normalized = String(runtimePython || '').trim();
|
|
2227
|
+
if (process.platform !== 'win32' || !normalized) {
|
|
2228
|
+
return normalized;
|
|
2229
|
+
}
|
|
2230
|
+
const runtimePath = path.resolve(normalized);
|
|
2231
|
+
const runtimeDir = path.dirname(runtimePath);
|
|
2232
|
+
const pythonwCandidate = path.join(runtimeDir, 'pythonw.exe');
|
|
2233
|
+
if (fs.existsSync(pythonwCandidate)) {
|
|
2234
|
+
return pythonwCandidate;
|
|
2235
|
+
}
|
|
2236
|
+
return runtimePath;
|
|
2237
|
+
}
|
|
2238
|
+
|
|
2158
2239
|
function syncUvProjectEnvironment(home, uvBinary, pythonTarget, editable) {
|
|
2159
2240
|
const args = ['sync', '--frozen', '--no-dev', '--compile-bytecode', '--python', pythonTarget];
|
|
2160
2241
|
if (!editable) {
|
|
@@ -2323,6 +2404,13 @@ function normalizePythonCliArgs(args, home) {
|
|
|
2323
2404
|
continue;
|
|
2324
2405
|
}
|
|
2325
2406
|
if (arg === '--yolo') {
|
|
2407
|
+
const parsed = parseBooleanFlagValue(args[index + 1]);
|
|
2408
|
+
if (parsed !== null) {
|
|
2409
|
+
index += 1;
|
|
2410
|
+
}
|
|
2411
|
+
continue;
|
|
2412
|
+
}
|
|
2413
|
+
if (typeof arg === 'string' && arg.startsWith('--yolo=')) {
|
|
2326
2414
|
continue;
|
|
2327
2415
|
}
|
|
2328
2416
|
if (arg === '--codex-profile') {
|
|
@@ -2598,8 +2686,9 @@ function spawnManagedDaemonProcess({ home, runtimePython, host, port, proxy = nu
|
|
|
2598
2686
|
const out = fs.openSync(logPath, 'a');
|
|
2599
2687
|
const resolvedDaemonId = String(daemonId || crypto.randomUUID()).trim();
|
|
2600
2688
|
const launcherPath = path.join(repoRoot, 'bin', 'ds.js');
|
|
2689
|
+
const backgroundPython = resolveBackgroundPythonExecutable(runtimePython);
|
|
2601
2690
|
const child = spawn(
|
|
2602
|
-
|
|
2691
|
+
backgroundPython,
|
|
2603
2692
|
[
|
|
2604
2693
|
'-m',
|
|
2605
2694
|
'deepscientist.cli',
|
|
@@ -2612,9 +2701,8 @@ function spawnManagedDaemonProcess({ home, runtimePython, host, port, proxy = nu
|
|
|
2612
2701
|
'--port',
|
|
2613
2702
|
String(port),
|
|
2614
2703
|
],
|
|
2615
|
-
{
|
|
2704
|
+
detachedSpawnOptions({
|
|
2616
2705
|
cwd: repoRoot,
|
|
2617
|
-
detached: true,
|
|
2618
2706
|
stdio: ['ignore', out, out],
|
|
2619
2707
|
env: {
|
|
2620
2708
|
...process.env,
|
|
@@ -2625,7 +2713,7 @@ function spawnManagedDaemonProcess({ home, runtimePython, host, port, proxy = nu
|
|
|
2625
2713
|
DS_DAEMON_ID: resolvedDaemonId,
|
|
2626
2714
|
DS_DAEMON_MANAGED_BY: 'ds-launcher',
|
|
2627
2715
|
},
|
|
2628
|
-
}
|
|
2716
|
+
})
|
|
2629
2717
|
);
|
|
2630
2718
|
child.unref();
|
|
2631
2719
|
const statePayload = {
|
|
@@ -2673,9 +2761,8 @@ function spawnDaemonSupervisor({ home, runtimePython, host, port, proxy = null,
|
|
|
2673
2761
|
if (envPayload) {
|
|
2674
2762
|
args.push('--env-json', envPayload);
|
|
2675
2763
|
}
|
|
2676
|
-
const child = spawn(process.execPath, args, {
|
|
2764
|
+
const child = spawn(process.execPath, args, detachedSpawnOptions({
|
|
2677
2765
|
cwd: repoRoot,
|
|
2678
|
-
detached: true,
|
|
2679
2766
|
stdio: 'ignore',
|
|
2680
2767
|
env: {
|
|
2681
2768
|
...process.env,
|
|
@@ -2683,7 +2770,7 @@ function spawnDaemonSupervisor({ home, runtimePython, host, port, proxy = null,
|
|
|
2683
2770
|
DEEPSCIENTIST_NODE_BINARY: process.execPath,
|
|
2684
2771
|
DEEPSCIENTIST_LAUNCHER_PATH: launcherPath,
|
|
2685
2772
|
},
|
|
2686
|
-
});
|
|
2773
|
+
}));
|
|
2687
2774
|
child.unref();
|
|
2688
2775
|
return child.pid || null;
|
|
2689
2776
|
}
|
|
@@ -2902,7 +2989,7 @@ function killManagedProcess(pid, signal) {
|
|
|
2902
2989
|
if (signal === 'SIGKILL') {
|
|
2903
2990
|
taskkillArgs.push('/T', '/F');
|
|
2904
2991
|
}
|
|
2905
|
-
const result = spawnSync('taskkill', taskkillArgs, { stdio: 'ignore' });
|
|
2992
|
+
const result = spawnSync('taskkill', taskkillArgs, syncSpawnOptions({ stdio: 'ignore' }));
|
|
2906
2993
|
return result.status === 0;
|
|
2907
2994
|
}
|
|
2908
2995
|
try {
|
|
@@ -3034,11 +3121,11 @@ function summarizeUpdateFailure(result) {
|
|
|
3034
3121
|
function runNpmInstallLatest(home, npmBinary) {
|
|
3035
3122
|
const args = ['install', '-g', `${UPDATE_PACKAGE_NAME}@latest`, '--no-audit', '--no-fund'];
|
|
3036
3123
|
const startedAt = new Date().toISOString();
|
|
3037
|
-
const result = spawnSync(npmBinary, args, {
|
|
3124
|
+
const result = spawnSync(npmBinary, args, syncSpawnOptions({
|
|
3038
3125
|
encoding: 'utf8',
|
|
3039
3126
|
env: process.env,
|
|
3040
3127
|
timeout: 15 * 60 * 1000,
|
|
3041
|
-
});
|
|
3128
|
+
}));
|
|
3042
3129
|
const finishedAt = new Date().toISOString();
|
|
3043
3130
|
const logPath = writeUpdateLog(
|
|
3044
3131
|
home,
|
|
@@ -3132,12 +3219,11 @@ async function promptYesNo(question, { defaultValue = false } = {}) {
|
|
|
3132
3219
|
|
|
3133
3220
|
function spawnDetachedNode(args, options = {}) {
|
|
3134
3221
|
const out = options.logPath ? fs.openSync(options.logPath, 'a') : 'ignore';
|
|
3135
|
-
const child = spawn(process.execPath, args, {
|
|
3222
|
+
const child = spawn(process.execPath, args, detachedSpawnOptions({
|
|
3136
3223
|
cwd: options.cwd || repoRoot,
|
|
3137
|
-
detached: true,
|
|
3138
3224
|
stdio: ['ignore', out, out],
|
|
3139
3225
|
env: options.env || process.env,
|
|
3140
|
-
});
|
|
3226
|
+
}));
|
|
3141
3227
|
child.unref();
|
|
3142
3228
|
return child;
|
|
3143
3229
|
}
|
|
@@ -3351,11 +3437,11 @@ function relaunchLauncherAfterUpdate(rawArgs, home) {
|
|
|
3351
3437
|
message: 'DeepScientist was updated, but the new launcher path could not be resolved for relaunch.',
|
|
3352
3438
|
};
|
|
3353
3439
|
}
|
|
3354
|
-
const result = spawnSync(process.execPath, [launcherPath, ...normalizeLauncherRelaunchArgs(rawArgs, home)], {
|
|
3440
|
+
const result = spawnSync(process.execPath, [launcherPath, ...normalizeLauncherRelaunchArgs(rawArgs, home)], syncSpawnOptions({
|
|
3355
3441
|
cwd: repoRoot,
|
|
3356
3442
|
stdio: 'inherit',
|
|
3357
3443
|
env: process.env,
|
|
3358
|
-
});
|
|
3444
|
+
}));
|
|
3359
3445
|
if (result.error) {
|
|
3360
3446
|
return {
|
|
3361
3447
|
ok: false,
|
|
@@ -3619,7 +3705,7 @@ async function startDaemon(home, runtimePython, host, port, proxy = null, envOve
|
|
|
3619
3705
|
function openBrowser(url) {
|
|
3620
3706
|
const spawnDetached = (command, args) => {
|
|
3621
3707
|
try {
|
|
3622
|
-
const child = spawn(command, args, {
|
|
3708
|
+
const child = spawn(command, args, detachedSpawnOptions({ stdio: 'ignore' }));
|
|
3623
3709
|
child.unref();
|
|
3624
3710
|
return true;
|
|
3625
3711
|
} catch {
|
|
@@ -3933,12 +4019,11 @@ async function migrateMain(rawArgs) {
|
|
|
3933
4019
|
const child = spawn(
|
|
3934
4020
|
process.execPath,
|
|
3935
4021
|
[migratedLauncher, '--home', targetHome, '--daemon-only', '--no-browser', '--skip-update-check'],
|
|
3936
|
-
{
|
|
4022
|
+
detachedSpawnOptions({
|
|
3937
4023
|
cwd: path.join(targetHome, 'cli'),
|
|
3938
|
-
detached: true,
|
|
3939
4024
|
stdio: 'ignore',
|
|
3940
4025
|
env: process.env,
|
|
3941
|
-
}
|
|
4026
|
+
})
|
|
3942
4027
|
);
|
|
3943
4028
|
child.unref();
|
|
3944
4029
|
restartMessage = 'Managed daemon restart scheduled from the migrated home.';
|
|
@@ -4097,7 +4182,7 @@ async function main() {
|
|
|
4097
4182
|
const pythonRuntime = ensurePythonRuntime(home);
|
|
4098
4183
|
const runtimePython = pythonRuntime.runtimePython;
|
|
4099
4184
|
const codexOverrideEnv = buildCodexOverrideEnv({
|
|
4100
|
-
yolo: args
|
|
4185
|
+
yolo: resolveYoloFlag(args, true),
|
|
4101
4186
|
profile: readOptionValue(args, '--codex-profile'),
|
|
4102
4187
|
binary: readOptionValue(args, '--codex'),
|
|
4103
4188
|
});
|
|
@@ -13,7 +13,7 @@ You will do four things:
|
|
|
13
13
|
|
|
14
14
|
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.
|
|
15
15
|
|
|
16
|
-
Current platform support: DeepScientist
|
|
16
|
+
Current platform support: DeepScientist fully supports Linux and macOS. Native Windows support is currently experimental; WSL2 remains the most battle-tested option when you need the closest Linux-like terminal behavior.
|
|
17
17
|
|
|
18
18
|
## Safety First: Isolate Before You Start
|
|
19
19
|
|
|
@@ -60,7 +60,7 @@ If you plan to use a provider-backed Codex profile instead of the default OpenAI
|
|
|
60
60
|
|
|
61
61
|
## 1. Install Node.js and DeepScientist
|
|
62
62
|
|
|
63
|
-
DeepScientist
|
|
63
|
+
DeepScientist fully supports Linux and macOS. Native Windows support is currently experimental, and WSL2 is still the most battle-tested option when you want Linux-like shell behavior.
|
|
64
64
|
|
|
65
65
|
Before installing DeepScientist itself, install Node.js from the official page:
|
|
66
66
|
|
|
@@ -395,8 +395,8 @@ codex:
|
|
|
395
395
|
profile: ""
|
|
396
396
|
model: gpt-5.4
|
|
397
397
|
model_reasoning_effort: xhigh
|
|
398
|
-
approval_policy:
|
|
399
|
-
sandbox_mode:
|
|
398
|
+
approval_policy: never
|
|
399
|
+
sandbox_mode: danger-full-access
|
|
400
400
|
retry_on_failure: true
|
|
401
401
|
retry_max_attempts: 5
|
|
402
402
|
retry_initial_backoff_sec: 1.0
|
|
@@ -473,19 +473,35 @@ claude:
|
|
|
473
473
|
**`approval_policy`**
|
|
474
474
|
|
|
475
475
|
- Type: `string`
|
|
476
|
-
- Default: `
|
|
476
|
+
- Default: `never`
|
|
477
477
|
- UI label: `Approval policy`
|
|
478
478
|
- Allowed values: `never`, `on-failure`, `on-request`, `untrusted`
|
|
479
479
|
- Meaning: how the runner should ask for permission on privileged actions.
|
|
480
|
+
- Runtime note: the launcher now starts Codex in YOLO mode by default. Passing `ds --yolo false` temporarily restores the non-YOLO pair `approval_policy=on-request` and `sandbox_mode=workspace-write`.
|
|
480
481
|
|
|
481
482
|
**`sandbox_mode`**
|
|
482
483
|
|
|
483
484
|
- Type: `string`
|
|
484
|
-
- Default: `
|
|
485
|
+
- Default: `danger-full-access`
|
|
485
486
|
- UI label: `Sandbox mode`
|
|
486
487
|
- Allowed values: `read-only`, `workspace-write`, `danger-full-access`
|
|
487
488
|
- Meaning: filesystem / process access mode for the runner.
|
|
488
489
|
|
|
490
|
+
**`env`**
|
|
491
|
+
|
|
492
|
+
- Type: `mapping<string, string>`
|
|
493
|
+
- Default: `{}`
|
|
494
|
+
- UI availability:
|
|
495
|
+
- global settings: editable in the `runners` structured form as `env`
|
|
496
|
+
- project settings: `Project settings -> Codex environment`
|
|
497
|
+
- Project-settings behavior:
|
|
498
|
+
- click `Add` to create a new variable row
|
|
499
|
+
- `OPENAI_BASE_URL` and `OPENAI_API_KEY` are shown by default
|
|
500
|
+
- changes are not auto-saved; click `Save env vars`
|
|
501
|
+
- empty values are ignored and are not injected into the Codex process
|
|
502
|
+
- Meaning: extra environment variables passed to Codex when DeepScientist starts a Codex run.
|
|
503
|
+
- Common use: provider-backed Codex setups that need API keys or custom base URLs.
|
|
504
|
+
|
|
489
505
|
**`retry_on_failure`**
|
|
490
506
|
|
|
491
507
|
- Type: `boolean`
|
|
@@ -20,6 +20,7 @@ After finishing this guide, you should be able to:
|
|
|
20
20
|
- use `/new`, `/use latest`, `/status`, and related commands from QQ
|
|
21
21
|
- see the detected `openid` in the `Settings` page
|
|
22
22
|
- run safe readiness checks and send probes from the `Settings` page
|
|
23
|
+
- receive auto-generated metric timeline images after each recorded main experiment when QQ is the bound quest connector
|
|
23
24
|
|
|
24
25
|
### Deployment checklist before you start
|
|
25
26
|
|
|
@@ -221,6 +222,24 @@ When the connector is fully working, you should usually see all of these:
|
|
|
221
222
|
- clicking `Send probe` again no longer reports an empty delivery target
|
|
222
223
|
- if a latest project already exists, plain text continues that project automatically; if no project exists yet, the bot returns help instead
|
|
223
224
|
|
|
225
|
+
## 5.3 Automatic main-experiment metric charts
|
|
226
|
+
|
|
227
|
+
When QQ is the bound quest connector, DeepScientist now auto-sends metric timeline charts after each recorded main experiment.
|
|
228
|
+
|
|
229
|
+
Current behavior:
|
|
230
|
+
|
|
231
|
+
- one chart per metric
|
|
232
|
+
- the baseline is drawn as a horizontal dashed reference line when a baseline value exists
|
|
233
|
+
- the system automatically respects whether the metric is `higher is better` or `lower is better`
|
|
234
|
+
- any point that beats baseline gets a star marker
|
|
235
|
+
- the latest point is filled with a deep Morandi red
|
|
236
|
+
- earlier points are filled with a deep Morandi blue
|
|
237
|
+
- if multiple metrics are present, DeepScientist sends them sequentially with about a 2 second gap
|
|
238
|
+
|
|
239
|
+
These charts are generated from quest-local files and delivered as native QQ images.
|
|
240
|
+
|
|
241
|
+
If you need to disable this automatic chart delivery, turn off `auto_send_main_experiment_png` in the QQ connector config.
|
|
242
|
+
|
|
224
243
|
### 5.2 Error quick decoder
|
|
225
244
|
|
|
226
245
|
| Message | What it usually means | What to do |
|