@researai/deepscientist 1.5.6 → 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.
- package/README.md +32 -0
- package/bin/ds.js +274 -18
- package/docs/en/07_MEMORY_AND_MCP.md +40 -3
- package/docs/en/99_ACKNOWLEDGEMENTS.md +1 -0
- package/docs/zh/07_MEMORY_AND_MCP.md +40 -3
- package/docs/zh/99_ACKNOWLEDGEMENTS.md +1 -0
- package/install.sh +34 -0
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/deepscientist/__init__.py +1 -1
- package/src/deepscientist/acp/envelope.py +1 -0
- package/src/deepscientist/artifact/metrics.py +813 -80
- package/src/deepscientist/artifact/schemas.py +1 -0
- package/src/deepscientist/artifact/service.py +1101 -99
- package/src/deepscientist/bash_exec/monitor.py +1 -1
- package/src/deepscientist/bash_exec/service.py +17 -9
- package/src/deepscientist/channels/qq.py +17 -0
- package/src/deepscientist/channels/relay.py +16 -0
- package/src/deepscientist/cli.py +1 -1
- package/src/deepscientist/config/models.py +12 -6
- package/src/deepscientist/config/service.py +75 -2
- package/src/deepscientist/connector_profiles.py +34 -6
- package/src/deepscientist/daemon/api/handlers.py +290 -15
- package/src/deepscientist/daemon/api/router.py +2 -0
- package/src/deepscientist/daemon/app.py +521 -23
- package/src/deepscientist/gitops/diff.py +6 -10
- package/src/deepscientist/mcp/server.py +188 -39
- package/src/deepscientist/prompts/builder.py +71 -22
- package/src/deepscientist/qq_profiles.py +19 -9
- package/src/deepscientist/quest/layout.py +1 -0
- package/src/deepscientist/quest/service.py +83 -34
- package/src/deepscientist/quest/stage_views.py +74 -29
- package/src/deepscientist/runners/codex.py +32 -14
- package/src/deepscientist/runners/runtime_overrides.py +46 -0
- package/src/deepscientist/skills/installer.py +7 -0
- package/src/prompts/connectors/qq.md +1 -1
- package/src/prompts/contracts/shared_interaction.md +14 -0
- package/src/prompts/system.md +134 -30
- package/src/skills/analysis-campaign/SKILL.md +34 -8
- package/src/skills/analysis-campaign/references/campaign-checklist-template.md +41 -0
- package/src/skills/analysis-campaign/references/campaign-plan-template.md +68 -0
- package/src/skills/baseline/SKILL.md +145 -32
- package/src/skills/baseline/references/baseline-checklist-template.md +57 -0
- package/src/skills/baseline/references/baseline-plan-template.md +105 -0
- package/src/skills/decision/SKILL.md +12 -8
- package/src/skills/experiment/SKILL.md +51 -9
- package/src/skills/experiment/references/main-experiment-checklist-template.md +52 -0
- package/src/skills/experiment/references/main-experiment-plan-template.md +79 -0
- package/src/skills/figure-polish/SKILL.md +1 -0
- package/src/skills/finalize/SKILL.md +3 -8
- package/src/skills/idea/SKILL.md +2 -8
- package/src/skills/intake-audit/SKILL.md +2 -8
- package/src/skills/rebuttal/SKILL.md +2 -8
- package/src/skills/review/SKILL.md +2 -8
- package/src/skills/scout/SKILL.md +2 -8
- package/src/skills/write/SKILL.md +52 -16
- package/src/skills/write/templates/DEEPSCIENTIST_NOTES.md +21 -0
- package/src/skills/write/templates/README.md +408 -0
- package/src/skills/write/templates/UPSTREAM_LICENSE.txt +21 -0
- package/src/skills/write/templates/aaai2026/README.md +534 -0
- package/src/skills/write/templates/aaai2026/aaai2026-unified-supp.tex +144 -0
- package/src/skills/write/templates/aaai2026/aaai2026-unified-template.tex +952 -0
- package/src/skills/write/templates/aaai2026/aaai2026.bib +111 -0
- package/src/skills/write/templates/aaai2026/aaai2026.bst +1493 -0
- package/src/skills/write/templates/aaai2026/aaai2026.sty +315 -0
- package/src/skills/write/templates/acl/README.md +50 -0
- package/src/skills/write/templates/acl/acl.sty +312 -0
- package/src/skills/write/templates/acl/acl_latex.tex +377 -0
- package/src/skills/write/templates/acl/acl_lualatex.tex +101 -0
- package/src/skills/write/templates/acl/acl_natbib.bst +1940 -0
- package/src/skills/write/templates/acl/anthology.bib.txt +26 -0
- package/src/skills/write/templates/acl/custom.bib +70 -0
- package/src/skills/write/templates/acl/formatting.md +326 -0
- package/src/skills/write/templates/asplos2027/main.tex +459 -0
- package/src/skills/write/templates/asplos2027/references.bib +135 -0
- package/src/skills/write/templates/colm2025/README.md +3 -0
- package/src/skills/write/templates/colm2025/colm2025_conference.bib +11 -0
- package/src/skills/write/templates/colm2025/colm2025_conference.bst +1440 -0
- package/src/skills/write/templates/colm2025/colm2025_conference.sty +218 -0
- package/src/skills/write/templates/colm2025/colm2025_conference.tex +305 -0
- package/src/skills/write/templates/colm2025/fancyhdr.sty +485 -0
- package/src/skills/write/templates/colm2025/math_commands.tex +508 -0
- package/src/skills/write/templates/colm2025/natbib.sty +1246 -0
- package/src/skills/write/templates/iclr2026/fancyhdr.sty +485 -0
- package/src/skills/write/templates/iclr2026/iclr2026_conference.bib +24 -0
- package/src/skills/write/templates/iclr2026/iclr2026_conference.bst +1440 -0
- package/src/skills/write/templates/iclr2026/iclr2026_conference.sty +246 -0
- package/src/skills/write/templates/iclr2026/iclr2026_conference.tex +414 -0
- package/src/skills/write/templates/iclr2026/math_commands.tex +508 -0
- package/src/skills/write/templates/iclr2026/natbib.sty +1246 -0
- package/src/skills/write/templates/icml2026/algorithm.sty +79 -0
- package/src/skills/write/templates/icml2026/algorithmic.sty +201 -0
- package/src/skills/write/templates/icml2026/example_paper.bib +75 -0
- package/src/skills/write/templates/icml2026/example_paper.tex +662 -0
- package/src/skills/write/templates/icml2026/fancyhdr.sty +864 -0
- package/src/skills/write/templates/icml2026/icml2026.bst +1443 -0
- package/src/skills/write/templates/icml2026/icml2026.sty +767 -0
- package/src/skills/write/templates/neurips2025/Makefile +36 -0
- package/src/skills/write/templates/neurips2025/extra_pkgs.tex +53 -0
- package/src/skills/write/templates/neurips2025/main.tex +38 -0
- package/src/skills/write/templates/neurips2025/neurips.sty +382 -0
- package/src/skills/write/templates/nsdi2027/main.tex +426 -0
- package/src/skills/write/templates/nsdi2027/references.bib +151 -0
- package/src/skills/write/templates/nsdi2027/usenix-2020-09.sty +83 -0
- package/src/skills/write/templates/osdi2026/main.tex +429 -0
- package/src/skills/write/templates/osdi2026/references.bib +150 -0
- package/src/skills/write/templates/osdi2026/usenix-2020-09.sty +83 -0
- package/src/skills/write/templates/sosp2026/main.tex +532 -0
- package/src/skills/write/templates/sosp2026/references.bib +148 -0
- package/src/tui/package.json +1 -1
- package/src/ui/dist/assets/{AiManusChatView-BGLArZRn.js → AiManusChatView-m2FNtwbn.js} +110 -14
- package/src/ui/dist/assets/{AnalysisPlugin-BgDGSigG.js → AnalysisPlugin-BMTF8EGL.js} +1 -1
- package/src/ui/dist/assets/{AutoFigurePlugin-B65HD7L4.js → AutoFigurePlugin-DxPdMUNb.js} +5 -5
- package/src/ui/dist/assets/{CliPlugin-CUqgsFHC.js → CliPlugin-BEOWgxCI.js} +9 -9
- package/src/ui/dist/assets/{CodeEditorPlugin-CF5EdvaS.js → CodeEditorPlugin-BCXvjqmb.js} +8 -8
- package/src/ui/dist/assets/{CodeViewerPlugin-DEeU063D.js → CodeViewerPlugin-DaJcy3nD.js} +5 -5
- package/src/ui/dist/assets/{DocViewerPlugin-Df-FuDlZ.js → DocViewerPlugin-ByfeIq4K.js} +3 -3
- package/src/ui/dist/assets/{GitDiffViewerPlugin-RAnNaRxM.js → GitDiffViewerPlugin-Cksf3VZ-.js} +830 -86
- package/src/ui/dist/assets/{ImageViewerPlugin-DXJ0ZJGg.js → ImageViewerPlugin-CFz-OsTS.js} +5 -5
- package/src/ui/dist/assets/{LabCopilotPanel-BlO-sKsj.js → LabCopilotPanel-CJ1cJzoX.js} +10 -10
- package/src/ui/dist/assets/{LabPlugin-BajPZW5v.js → LabPlugin-BF3dVJwa.js} +1 -1
- package/src/ui/dist/assets/{LatexPlugin-F1OEol8D.js → LatexPlugin-DDkwZ6Sj.js} +7 -7
- package/src/ui/dist/assets/{MarkdownViewerPlugin-MhUupqwT.js → MarkdownViewerPlugin-HAuvurcT.js} +4 -4
- package/src/ui/dist/assets/{MarketplacePlugin-DxhIEsv0.js → MarketplacePlugin-BtoTYy2C.js} +3 -3
- package/src/ui/dist/assets/{index-B-2scqCJ.js → NotebookEditor-CSJYx7b-.js} +12 -155
- package/src/ui/dist/assets/{NotebookEditor-q7TkhewC.js → NotebookEditor-DQgRezm_.js} +1 -1
- package/src/ui/dist/assets/{PdfLoader-B8ZOTKFc.js → PdfLoader-DPa_-fv6.js} +1 -1
- package/src/ui/dist/assets/{PdfMarkdownPlugin-xFPvzvWh.js → PdfMarkdownPlugin-BZpXOEjm.js} +3 -3
- package/src/ui/dist/assets/{PdfViewerPlugin-EjEcsIB8.js → PdfViewerPlugin-BT8a6wGR.js} +10 -10
- package/src/ui/dist/assets/{SearchPlugin-ixY-1lgW.js → SearchPlugin-D_blveZi.js} +1 -1
- package/src/ui/dist/assets/{Stepper-gYFK2Pgz.js → Stepper-DH2k75Vo.js} +1 -1
- package/src/ui/dist/assets/{TextViewerPlugin-Cym6pv_n.js → TextViewerPlugin-Btx0M3hX.js} +4 -4
- package/src/ui/dist/assets/{VNCViewer-BPmIHcmK.js → VNCViewer-DImJO4rO.js} +9 -9
- package/src/ui/dist/assets/{bibtex-Btv6Wi7f.js → bibtex-B-Hqu0Sg.js} +1 -1
- package/src/ui/dist/assets/{code-BlG7g85c.js → code-BUfXGJSl.js} +1 -1
- package/src/ui/dist/assets/{file-content-DBT5OfTZ.js → file-content-VqamwI3X.js} +1 -1
- package/src/ui/dist/assets/{file-diff-panel-BWXYzqHk.js → file-diff-panel-C_wOoS7a.js} +1 -1
- package/src/ui/dist/assets/{file-socket-wDlx6byM.js → file-socket-D2bTuMVP.js} +1 -1
- package/src/ui/dist/assets/{file-utils-Ba3nJmH0.js → file-utils--zJCPN1i.js} +1 -1
- package/src/ui/dist/assets/{image-BwtCyguk.js → image-BZkGJ4mM.js} +1 -1
- package/src/ui/dist/assets/{index-CfRpE209.js → index-CxkvSeKw.js} +2 -2
- package/src/ui/dist/assets/{index-DcqvKzeJ.js → index-D9QIGcmc.js} +1 -1
- package/src/ui/dist/assets/{index-DpMZw8aM.css → index-DXZ1daiJ.css} +163 -34
- package/src/ui/dist/assets/index-DdRW6RMJ.js +159 -0
- package/src/ui/dist/assets/{index-Bz5AaWL7.js → index-DjggJovS.js} +2948 -1565
- package/src/ui/dist/assets/{message-square-BnlyWVH0.js → message-square-FUIPIhU2.js} +1 -1
- package/src/ui/dist/assets/{monaco-CXe0pAVe.js → monaco-DHMc7kKM.js} +1 -1
- package/src/ui/dist/assets/{popover-BCHmVhHj.js → popover-B85oCgCS.js} +1 -1
- package/src/ui/dist/assets/{project-sync-Brk6kaOD.js → project-sync-DOMCcPac.js} +1 -1
- package/src/ui/dist/assets/{sigma-D72eSUep.js → sigma-BO2rQrl3.js} +1 -1
- package/src/ui/dist/assets/{tooltip-BMWd0dqX.js → tooltip-B1OspAkx.js} +1 -1
- package/src/ui/dist/assets/{trash-BIt_eWIS.js → trash-BsVEH_dV.js} +1 -1
- package/src/ui/dist/assets/{useCliAccess-N1hkTRrR.js → useCliAccess-b8L6JuZm.js} +1 -1
- package/src/ui/dist/assets/{useFileDiffOverlay-DPRPv6rv.js → useFileDiffOverlay-BY7uA9hV.js} +1 -1
- package/src/ui/dist/assets/{wrap-text-E5-UheyP.js → wrap-text-BwyVuUIK.js} +1 -1
- package/src/ui/dist/assets/{zoom-out-D4TR-ZZ_.js → zoom-out-RDpLugQP.js} +1 -1
- package/src/ui/dist/index.html +5 -2
- /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
|
|
@@ -25,6 +27,20 @@ ds
|
|
|
25
27
|
|
|
26
28
|
DeepScientist starts the local web workspace at `http://127.0.0.1:20999` by default.
|
|
27
29
|
|
|
30
|
+
By default, DeepScientist keeps Codex on the standard profile: `approval_policy=on-request` and `sandbox_mode=workspace-write`. Use `--yolo` only when you want explicit full-access execution.
|
|
31
|
+
|
|
32
|
+
Recommended command when you want the current directory as the home and Codex full-access execution:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
ds --yolo --port 20999 --here
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Parameter meanings:
|
|
39
|
+
|
|
40
|
+
- `--yolo`: run Codex in YOLO mode, which sets `approval_policy=never` and `sandbox_mode=danger-full-access`
|
|
41
|
+
- `--port 20999`: bind the local web workspace to port `20999`
|
|
42
|
+
- `--here`: use the current working directory as the DeepScientist home
|
|
43
|
+
|
|
28
44
|
On first start, `ds` will:
|
|
29
45
|
|
|
30
46
|
- bootstrap a local `uv` runtime manager automatically if your machine does not already have one
|
|
@@ -37,6 +53,12 @@ If you want another port:
|
|
|
37
53
|
ds --port 21000
|
|
38
54
|
```
|
|
39
55
|
|
|
56
|
+
If you want YOLO mode on another port:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
ds --yolo --port 21000
|
|
60
|
+
```
|
|
61
|
+
|
|
40
62
|
If you want to bind on all interfaces:
|
|
41
63
|
|
|
42
64
|
```bash
|
|
@@ -60,6 +82,14 @@ ds --here
|
|
|
60
82
|
|
|
61
83
|
This is equivalent to launching with `ds --home "$PWD"`.
|
|
62
84
|
|
|
85
|
+
Useful launch examples:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
ds --yolo --port 20999 --here
|
|
89
|
+
ds --host 0.0.0.0 --port 21000
|
|
90
|
+
ds --yolo --host 0.0.0.0 --port 21000 --here
|
|
91
|
+
```
|
|
92
|
+
|
|
63
93
|
If you want to install the bundled CLI tree into another base path from a source checkout:
|
|
64
94
|
|
|
65
95
|
```bash
|
|
@@ -96,6 +126,8 @@ This installs a lightweight TinyTeX `pdflatex` runtime for local paper compilati
|
|
|
96
126
|
- [快速开始(中文)](docs/zh/00_QUICK_START.md)
|
|
97
127
|
- [QQ Connector Guide (English)](docs/en/03_QQ_CONNECTOR_GUIDE.md)
|
|
98
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)
|
|
99
131
|
|
|
100
132
|
## Maintainers
|
|
101
133
|
|
package/bin/ds.js
CHANGED
|
@@ -38,6 +38,15 @@ const UPDATE_CHECK_TTL_MS = 12 * 60 * 60 * 1000;
|
|
|
38
38
|
|
|
39
39
|
const optionsWithValues = new Set(['--home', '--host', '--port', '--quest-id', '--mode', '--proxy']);
|
|
40
40
|
|
|
41
|
+
function buildCodexOverrideEnv({ yolo = false } = {}) {
|
|
42
|
+
if (!yolo) {
|
|
43
|
+
return {};
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
DEEPSCIENTIST_CODEX_YOLO: '1',
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
41
50
|
function printLauncherHelp() {
|
|
42
51
|
console.log(`DeepScientist launcher
|
|
43
52
|
|
|
@@ -48,6 +57,7 @@ Usage:
|
|
|
48
57
|
ds update --yes
|
|
49
58
|
ds migrate /data/DeepScientist
|
|
50
59
|
ds --here
|
|
60
|
+
ds --yolo --port 20999 --here
|
|
51
61
|
ds --here doctor
|
|
52
62
|
ds --tui
|
|
53
63
|
ds --both
|
|
@@ -73,6 +83,7 @@ Launcher flags:
|
|
|
73
83
|
--home <path> Use a custom DeepScientist home
|
|
74
84
|
--here Use the current working directory as DeepScientist home
|
|
75
85
|
--proxy <url> Use an outbound HTTP/WS proxy for npm and Python runtime traffic
|
|
86
|
+
--yolo Run Codex in YOLO mode: approval_policy=never and sandbox_mode=danger-full-access
|
|
76
87
|
--quest-id <id> Open the TUI on one quest directly
|
|
77
88
|
|
|
78
89
|
Update:
|
|
@@ -209,6 +220,17 @@ function compareVersions(left, right) {
|
|
|
209
220
|
return 0;
|
|
210
221
|
}
|
|
211
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
|
+
|
|
212
234
|
function detectInstallMode(rootPath = repoRoot) {
|
|
213
235
|
const normalized = String(rootPath || '');
|
|
214
236
|
return normalized.includes(`${path.sep}node_modules${path.sep}`) ? 'npm-package' : 'source-checkout';
|
|
@@ -315,6 +337,8 @@ function buildUpdateStatus(home, statePatch = {}) {
|
|
|
315
337
|
const support = updateSupportSummary(installMode, npmBinary, launcherPath);
|
|
316
338
|
const currentVersion = normalizeVersion(state.current_version || packageJson.version);
|
|
317
339
|
const latestVersion = normalizeVersion(state.latest_version || '');
|
|
340
|
+
const targetVersion = normalizeVersion(state.target_version || '');
|
|
341
|
+
const busy = hasActiveBusyUpdate(state, currentVersion);
|
|
318
342
|
const promptedVersion = normalizeVersion(state.last_prompted_version || '');
|
|
319
343
|
const updateAvailable = Boolean(latestVersion) && compareVersions(latestVersion, currentVersion) > 0;
|
|
320
344
|
const skippedVersion = normalizeVersion(state.last_skipped_version || '');
|
|
@@ -322,7 +346,7 @@ function buildUpdateStatus(home, statePatch = {}) {
|
|
|
322
346
|
const skippedCurrentTarget = Boolean(updateAvailable && skippedVersion && skippedVersion === latestVersion);
|
|
323
347
|
const promptRecommended =
|
|
324
348
|
Boolean(updateAvailable)
|
|
325
|
-
&& !
|
|
349
|
+
&& !busy
|
|
326
350
|
&& !promptedCurrentTarget
|
|
327
351
|
&& !skippedCurrentTarget
|
|
328
352
|
;
|
|
@@ -337,7 +361,7 @@ function buildUpdateStatus(home, statePatch = {}) {
|
|
|
337
361
|
latest_version: latestVersion || null,
|
|
338
362
|
update_available: updateAvailable,
|
|
339
363
|
prompt_recommended: promptRecommended,
|
|
340
|
-
busy
|
|
364
|
+
busy,
|
|
341
365
|
last_checked_at: state.last_checked_at || null,
|
|
342
366
|
last_check_error: state.last_check_error || null,
|
|
343
367
|
last_prompted_at: state.last_prompted_at || null,
|
|
@@ -347,7 +371,7 @@ function buildUpdateStatus(home, statePatch = {}) {
|
|
|
347
371
|
last_update_started_at: state.last_update_started_at || null,
|
|
348
372
|
last_update_finished_at: state.last_update_finished_at || null,
|
|
349
373
|
last_update_result: state.last_update_result || null,
|
|
350
|
-
target_version:
|
|
374
|
+
target_version: busy ? targetVersion || latestVersion || null : null,
|
|
351
375
|
manual_update_command: updateManualCommand(installMode),
|
|
352
376
|
reason: support.reason,
|
|
353
377
|
};
|
|
@@ -360,8 +384,16 @@ function checkForUpdates(home, { force = false, timeoutMs = 3500 } = {}) {
|
|
|
360
384
|
const npmBinary = resolveNpmBinary();
|
|
361
385
|
const launcherPath = resolveLauncherPath();
|
|
362
386
|
const support = updateSupportSummary(installMode, npmBinary, launcherPath);
|
|
387
|
+
const existingBusyIsStale = Boolean(existing.busy) && !hasActiveBusyUpdate(existing, currentVersion);
|
|
363
388
|
|
|
364
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
|
+
}
|
|
365
397
|
return buildUpdateStatus(home);
|
|
366
398
|
}
|
|
367
399
|
|
|
@@ -381,6 +413,13 @@ function checkForUpdates(home, { force = false, timeoutMs = 3500 } = {}) {
|
|
|
381
413
|
last_checked_at: new Date().toISOString(),
|
|
382
414
|
last_check_error: probe.ok ? null : probe.error,
|
|
383
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
|
+
}
|
|
384
423
|
return buildUpdateStatus(home, patched);
|
|
385
424
|
}
|
|
386
425
|
|
|
@@ -581,13 +620,14 @@ function pythonVersionText(probe) {
|
|
|
581
620
|
return version;
|
|
582
621
|
}
|
|
583
622
|
|
|
584
|
-
function renderLaunchHints({ home, url, bindUrl, pythonSelection }) {
|
|
623
|
+
function renderLaunchHints({ home, url, bindUrl, pythonSelection, yolo }) {
|
|
585
624
|
const runtimeRows = [
|
|
586
625
|
['Version', packageJson.version],
|
|
587
626
|
['Home', truncateMiddle(home)],
|
|
588
627
|
['Browser URL', url],
|
|
589
628
|
['Bind URL', bindUrl],
|
|
590
629
|
['Python', truncateMiddle(pythonVersionText(pythonSelection))],
|
|
630
|
+
['Codex mode', yolo ? 'YOLO (never + danger-full-access)' : 'Default (on-request + workspace-write)'],
|
|
591
631
|
];
|
|
592
632
|
if (pythonSelection && pythonSelection.sourceLabel) {
|
|
593
633
|
runtimeRows.push(['Python source', pythonSelection.sourceLabel]);
|
|
@@ -598,6 +638,7 @@ function renderLaunchHints({ home, url, bindUrl, pythonSelection }) {
|
|
|
598
638
|
|
|
599
639
|
console.log(colorize('\u001B[1;38;5;39m', 'Quick Flags'));
|
|
600
640
|
renderKeyValueRows([
|
|
641
|
+
['ds --yolo --port 20999 --here', 'Start in the current directory with YOLO Codex access'],
|
|
601
642
|
['ds --port 21000', 'Change the web port'],
|
|
602
643
|
['ds --host 0.0.0.0 --port 21000', 'Bind on all interfaces'],
|
|
603
644
|
['ds --here', 'Use the current directory as home'],
|
|
@@ -622,6 +663,7 @@ function printLaunchCard({
|
|
|
622
663
|
daemonOnly,
|
|
623
664
|
home,
|
|
624
665
|
pythonSelection,
|
|
666
|
+
yolo,
|
|
625
667
|
}) {
|
|
626
668
|
const width = Math.max(72, Math.min(process.stdout.columns || 100, 108));
|
|
627
669
|
const divider = colorize('\u001B[38;5;245m', '─'.repeat(Math.max(36, width - 6)));
|
|
@@ -680,7 +722,7 @@ function printLaunchCard({
|
|
|
680
722
|
console.log(centerText('Run ds --stop to stop the managed daemon.', width));
|
|
681
723
|
console.log(centerText('Need to move this installation later? Use ds migrate /new/path.', width));
|
|
682
724
|
console.log('');
|
|
683
|
-
renderLaunchHints({ home, url, bindUrl, pythonSelection });
|
|
725
|
+
renderLaunchHints({ home, url, bindUrl, pythonSelection, yolo });
|
|
684
726
|
}
|
|
685
727
|
|
|
686
728
|
function escapeHtml(value) {
|
|
@@ -803,7 +845,7 @@ function writeCodexPreflightReport(home, probe) {
|
|
|
803
845
|
};
|
|
804
846
|
}
|
|
805
847
|
|
|
806
|
-
function readCodexBootstrapState(home, runtimePython) {
|
|
848
|
+
function readCodexBootstrapState(home, runtimePython, envOverrides = {}) {
|
|
807
849
|
const snippet = [
|
|
808
850
|
'import json, pathlib, sys',
|
|
809
851
|
'from deepscientist.config import ConfigManager',
|
|
@@ -811,7 +853,14 @@ function readCodexBootstrapState(home, runtimePython) {
|
|
|
811
853
|
'manager = ConfigManager(home)',
|
|
812
854
|
'print(json.dumps(manager.codex_bootstrap_state(), ensure_ascii=False))',
|
|
813
855
|
].join('\n');
|
|
814
|
-
const result = runSync(runtimePython, ['-c', snippet, home], {
|
|
856
|
+
const result = runSync(runtimePython, ['-c', snippet, home], {
|
|
857
|
+
capture: true,
|
|
858
|
+
allowFailure: true,
|
|
859
|
+
env: {
|
|
860
|
+
...process.env,
|
|
861
|
+
...envOverrides,
|
|
862
|
+
},
|
|
863
|
+
});
|
|
815
864
|
if (result.status !== 0) {
|
|
816
865
|
return { codex_ready: false, codex_last_checked_at: null, codex_last_result: {} };
|
|
817
866
|
}
|
|
@@ -822,7 +871,7 @@ function readCodexBootstrapState(home, runtimePython) {
|
|
|
822
871
|
}
|
|
823
872
|
}
|
|
824
873
|
|
|
825
|
-
function probeCodexBootstrap(home, runtimePython) {
|
|
874
|
+
function probeCodexBootstrap(home, runtimePython, envOverrides = {}) {
|
|
826
875
|
const snippet = [
|
|
827
876
|
'import json, pathlib, sys',
|
|
828
877
|
'from deepscientist.config import ConfigManager',
|
|
@@ -830,7 +879,14 @@ function probeCodexBootstrap(home, runtimePython) {
|
|
|
830
879
|
'manager = ConfigManager(home)',
|
|
831
880
|
'print(json.dumps(manager.probe_codex_bootstrap(persist=True), ensure_ascii=False))',
|
|
832
881
|
].join('\n');
|
|
833
|
-
const result = runSync(runtimePython, ['-c', snippet, home], {
|
|
882
|
+
const result = runSync(runtimePython, ['-c', snippet, home], {
|
|
883
|
+
capture: true,
|
|
884
|
+
allowFailure: true,
|
|
885
|
+
env: {
|
|
886
|
+
...process.env,
|
|
887
|
+
...envOverrides,
|
|
888
|
+
},
|
|
889
|
+
});
|
|
834
890
|
let payload = null;
|
|
835
891
|
try {
|
|
836
892
|
payload = JSON.parse(result.stdout || '{}');
|
|
@@ -881,6 +937,7 @@ function parseLauncherArgs(argv) {
|
|
|
881
937
|
let status = false;
|
|
882
938
|
let daemonOnly = false;
|
|
883
939
|
let skipUpdateCheck = false;
|
|
940
|
+
let yolo = false;
|
|
884
941
|
|
|
885
942
|
if (args[0] === 'ui') {
|
|
886
943
|
args.shift();
|
|
@@ -899,6 +956,7 @@ function parseLauncherArgs(argv) {
|
|
|
899
956
|
else if (arg === '--open-browser') openBrowser = true;
|
|
900
957
|
else if (arg === '--daemon-only') daemonOnly = true;
|
|
901
958
|
else if (arg === '--skip-update-check') skipUpdateCheck = true;
|
|
959
|
+
else if (arg === '--yolo') yolo = true;
|
|
902
960
|
else if (arg === '--host' && args[index + 1]) host = args[++index];
|
|
903
961
|
else if (arg === '--port' && args[index + 1]) port = Number(args[++index]);
|
|
904
962
|
else if (arg === '--home' && args[index + 1]) home = path.resolve(args[++index]);
|
|
@@ -923,6 +981,7 @@ function parseLauncherArgs(argv) {
|
|
|
923
981
|
questId,
|
|
924
982
|
daemonOnly,
|
|
925
983
|
skipUpdateCheck,
|
|
984
|
+
yolo,
|
|
926
985
|
};
|
|
927
986
|
}
|
|
928
987
|
|
|
@@ -1111,6 +1170,40 @@ function buildGlobalWrapperScript({ installDir, home, commandName }) {
|
|
|
1111
1170
|
return [
|
|
1112
1171
|
'#!/usr/bin/env bash',
|
|
1113
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',
|
|
1114
1207
|
'if [ -z "${DEEPSCIENTIST_HOME:-}" ]; then',
|
|
1115
1208
|
` export DEEPSCIENTIST_HOME="${home}"`,
|
|
1116
1209
|
'fi',
|
|
@@ -1119,6 +1212,18 @@ function buildGlobalWrapperScript({ installDir, home, commandName }) {
|
|
|
1119
1212
|
].join('\n');
|
|
1120
1213
|
}
|
|
1121
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
|
+
|
|
1122
1227
|
function writeExecutableScript(targetPath, content) {
|
|
1123
1228
|
ensureDir(path.dirname(targetPath));
|
|
1124
1229
|
fs.writeFileSync(targetPath, content, { encoding: 'utf8', mode: 0o755 });
|
|
@@ -1155,6 +1260,94 @@ function candidateWrapperPathsForCommand(commandName) {
|
|
|
1155
1260
|
return candidates;
|
|
1156
1261
|
}
|
|
1157
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
|
+
|
|
1158
1351
|
function rewriteLauncherWrappersIfPointingAtSource({ sourceHome, targetHome }) {
|
|
1159
1352
|
if (process.platform === 'win32') {
|
|
1160
1353
|
return [];
|
|
@@ -2074,6 +2267,9 @@ function normalizePythonCliArgs(args, home) {
|
|
|
2074
2267
|
if (arg === '--here') {
|
|
2075
2268
|
continue;
|
|
2076
2269
|
}
|
|
2270
|
+
if (arg === '--yolo') {
|
|
2271
|
+
continue;
|
|
2272
|
+
}
|
|
2077
2273
|
normalized.push(arg);
|
|
2078
2274
|
}
|
|
2079
2275
|
return ['--home', home, ...normalized];
|
|
@@ -2588,19 +2784,45 @@ function spawnDetachedNode(args, options = {}) {
|
|
|
2588
2784
|
async function performSelfUpdate(home, options = {}) {
|
|
2589
2785
|
const status = checkForUpdates(home, { force: true });
|
|
2590
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
|
+
});
|
|
2591
2800
|
return {
|
|
2592
2801
|
ok: true,
|
|
2593
2802
|
updated: false,
|
|
2594
2803
|
status,
|
|
2595
|
-
message
|
|
2804
|
+
message,
|
|
2596
2805
|
};
|
|
2597
2806
|
}
|
|
2598
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
|
+
});
|
|
2599
2821
|
return {
|
|
2600
2822
|
ok: false,
|
|
2601
2823
|
updated: false,
|
|
2602
2824
|
status,
|
|
2603
|
-
message
|
|
2825
|
+
message,
|
|
2604
2826
|
};
|
|
2605
2827
|
}
|
|
2606
2828
|
|
|
@@ -2663,6 +2885,11 @@ async function performSelfUpdate(home, options = {}) {
|
|
|
2663
2885
|
};
|
|
2664
2886
|
}
|
|
2665
2887
|
|
|
2888
|
+
repairLegacyPathWrappers({
|
|
2889
|
+
home,
|
|
2890
|
+
launcherPath: resolveLauncherPath(),
|
|
2891
|
+
});
|
|
2892
|
+
|
|
2666
2893
|
const restartDaemon =
|
|
2667
2894
|
options.restartDaemon === true
|
|
2668
2895
|
|| (options.restartDaemon !== false && Boolean(daemonState?.pid || daemonState?.daemon_id));
|
|
@@ -2765,6 +2992,22 @@ async function startBackgroundUpdateWorker(home, options = {}) {
|
|
|
2765
2992
|
};
|
|
2766
2993
|
}
|
|
2767
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
|
+
}
|
|
2768
3011
|
mergeUpdateState(home, {
|
|
2769
3012
|
current_version: status.current_version,
|
|
2770
3013
|
latest_version: status.latest_version,
|
|
@@ -2856,7 +3099,7 @@ function readConfiguredUiAddressFromFile(home, fallbackHost, fallbackPort) {
|
|
|
2856
3099
|
}
|
|
2857
3100
|
}
|
|
2858
3101
|
|
|
2859
|
-
async function startDaemon(home, runtimePython, host, port, proxy = null) {
|
|
3102
|
+
async function startDaemon(home, runtimePython, host, port, proxy = null, envOverrides = {}) {
|
|
2860
3103
|
const browserUrl = browserUiUrl(host, port);
|
|
2861
3104
|
const daemonBindUrl = bindUiUrl(host, port);
|
|
2862
3105
|
const state = readDaemonState(home);
|
|
@@ -2880,10 +3123,10 @@ async function startDaemon(home, runtimePython, host, port, proxy = null) {
|
|
|
2880
3123
|
removeDaemonState(home);
|
|
2881
3124
|
}
|
|
2882
3125
|
|
|
2883
|
-
const bootstrapState = readCodexBootstrapState(home, runtimePython);
|
|
3126
|
+
const bootstrapState = readCodexBootstrapState(home, runtimePython, envOverrides);
|
|
2884
3127
|
if (!bootstrapState.codex_ready) {
|
|
2885
3128
|
console.log('Codex is not marked ready yet. Running startup probe...');
|
|
2886
|
-
const probe = probeCodexBootstrap(home, runtimePython);
|
|
3129
|
+
const probe = probeCodexBootstrap(home, runtimePython, envOverrides);
|
|
2887
3130
|
if (!probe || probe.ok !== true) {
|
|
2888
3131
|
throw createCodexPreflightError(home, probe);
|
|
2889
3132
|
}
|
|
@@ -2915,6 +3158,7 @@ async function startDaemon(home, runtimePython, host, port, proxy = null) {
|
|
|
2915
3158
|
stdio: ['ignore', out, out],
|
|
2916
3159
|
env: {
|
|
2917
3160
|
...process.env,
|
|
3161
|
+
...envOverrides,
|
|
2918
3162
|
DEEPSCIENTIST_REPO_ROOT: repoRoot,
|
|
2919
3163
|
DEEPSCIENTIST_NODE_BINARY: process.execPath,
|
|
2920
3164
|
DEEPSCIENTIST_LAUNCHER_PATH: path.join(repoRoot, 'bin', 'ds.js'),
|
|
@@ -3276,6 +3520,10 @@ async function launcherMain(rawArgs) {
|
|
|
3276
3520
|
const home = options.home || resolveHome(rawArgs);
|
|
3277
3521
|
applyLauncherProxy(options.proxy);
|
|
3278
3522
|
ensureDir(home);
|
|
3523
|
+
repairLegacyPathWrappers({
|
|
3524
|
+
home,
|
|
3525
|
+
launcherPath: resolveLauncherPath(),
|
|
3526
|
+
});
|
|
3279
3527
|
|
|
3280
3528
|
if (options.stop) {
|
|
3281
3529
|
await stopDaemon(home);
|
|
@@ -3309,6 +3557,7 @@ async function launcherMain(rawArgs) {
|
|
|
3309
3557
|
|
|
3310
3558
|
const pythonRuntime = ensurePythonRuntime(home);
|
|
3311
3559
|
const runtimePython = pythonRuntime.runtimePython;
|
|
3560
|
+
const codexOverrideEnv = buildCodexOverrideEnv({ yolo: options.yolo });
|
|
3312
3561
|
ensureInitialized(home, runtimePython);
|
|
3313
3562
|
if (await maybeHandleStartupUpdate(home, rawArgs, options)) {
|
|
3314
3563
|
return true;
|
|
@@ -3331,7 +3580,7 @@ async function launcherMain(rawArgs) {
|
|
|
3331
3580
|
step(4, 4, 'Starting local daemon and UI surfaces');
|
|
3332
3581
|
let started;
|
|
3333
3582
|
try {
|
|
3334
|
-
started = await startDaemon(home, runtimePython, host, port, options.proxy);
|
|
3583
|
+
started = await startDaemon(home, runtimePython, host, port, options.proxy, codexOverrideEnv);
|
|
3335
3584
|
} catch (error) {
|
|
3336
3585
|
if (handleCodexPreflightFailure(error)) return true;
|
|
3337
3586
|
throw error;
|
|
@@ -3346,6 +3595,7 @@ async function launcherMain(rawArgs) {
|
|
|
3346
3595
|
daemonOnly: options.daemonOnly,
|
|
3347
3596
|
home,
|
|
3348
3597
|
pythonSelection: pythonRuntime.runtimeProbe,
|
|
3598
|
+
yolo: options.yolo,
|
|
3349
3599
|
});
|
|
3350
3600
|
|
|
3351
3601
|
if (options.daemonOnly) {
|
|
@@ -3381,14 +3631,15 @@ async function main() {
|
|
|
3381
3631
|
const home = resolveHome(args);
|
|
3382
3632
|
const pythonRuntime = ensurePythonRuntime(home);
|
|
3383
3633
|
const runtimePython = pythonRuntime.runtimePython;
|
|
3634
|
+
const codexOverrideEnv = buildCodexOverrideEnv({ yolo: args.includes('--yolo') });
|
|
3384
3635
|
if (positional.value === 'run' || positional.value === 'daemon') {
|
|
3385
3636
|
maybePrintOptionalLatexNotice(home);
|
|
3386
3637
|
}
|
|
3387
3638
|
if (positional.value === 'run' || positional.value === 'daemon') {
|
|
3388
|
-
const bootstrapState = readCodexBootstrapState(home, runtimePython);
|
|
3639
|
+
const bootstrapState = readCodexBootstrapState(home, runtimePython, codexOverrideEnv);
|
|
3389
3640
|
if (!bootstrapState.codex_ready) {
|
|
3390
3641
|
try {
|
|
3391
|
-
const probe = probeCodexBootstrap(home, runtimePython);
|
|
3642
|
+
const probe = probeCodexBootstrap(home, runtimePython, codexOverrideEnv);
|
|
3392
3643
|
if (!probe || probe.ok !== true) {
|
|
3393
3644
|
throw createCodexPreflightError(home, probe);
|
|
3394
3645
|
}
|
|
@@ -3398,7 +3649,10 @@ async function main() {
|
|
|
3398
3649
|
}
|
|
3399
3650
|
}
|
|
3400
3651
|
}
|
|
3401
|
-
const result = runPythonCli(runtimePython, normalizePythonCliArgs(args, home), {
|
|
3652
|
+
const result = runPythonCli(runtimePython, normalizePythonCliArgs(args, home), {
|
|
3653
|
+
allowFailure: true,
|
|
3654
|
+
env: codexOverrideEnv,
|
|
3655
|
+
});
|
|
3402
3656
|
process.exit(result.status ?? 0);
|
|
3403
3657
|
return;
|
|
3404
3658
|
}
|
|
@@ -3419,6 +3673,8 @@ module.exports = {
|
|
|
3419
3673
|
parseLauncherArgs,
|
|
3420
3674
|
normalizeProxyUrl,
|
|
3421
3675
|
parseMigrateArgs,
|
|
3676
|
+
parseLegacyWrapperCandidate,
|
|
3677
|
+
repairLegacyPathWrappers,
|
|
3422
3678
|
useEditableProjectInstall,
|
|
3423
3679
|
compareVersions,
|
|
3424
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.
|
|
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
|
-
##
|
|
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
|
-
##
|
|
277
|
+
## 7. UI expectation
|
|
241
278
|
|
|
242
279
|
In `/projects/{id}` Studio trace:
|
|
243
280
|
|