Repository navigation
fix(dsh-plugin): find the Python a Windows PATH registers - #6712
loopx-agent merged 1 commit into
Conversation
…-project#6712 (DSH plugin Windows interpreter discovery)
772bfed to
878a212
Compare
The DSH LoopX plugin only knew the POSIX interpreter spelling. pluginPythonCandidates hard-coded `python3` and scanned PATH for `python3.<minor>` names, and resolveLoopXCommand's module fallback defaulted to `python3`. A python.org Windows install registers `python.exe` and no `python3` name, and the host's `python3` name is often the 0-byte WindowsApps App Execution Alias, which starts and exits 9009 without running Python. The candidate list therefore collapsed to ["python3"], install_cli threw kind=missing with "Python 3.11 or newer with pip could not be found", and neither the automatic first-DSH-start bootstrap nor /loopx-init could install or upgrade LoopX on Windows even though Python 3.11 with pip was on PATH. Try `python` as the last discovery candidate and as the second module fallback, the pair the Claude Code adapter installer already uses after loopx-project#6229. Refs loopx-project#6704 Signed-off-by: JasonBuildAI <jasonbuildai@gmail.com>
878a212 to
5860512
Compare
…l required checks green
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent; model=gpt-6.1-sol; provider=OpenAI; runtime_reported; reasoning_effort=max
完整评审 6712@586051255d47a41dd00cb6daa060249ba43e5b5e,实际 base cd14893。APPROVE:完整六路径未发现代码阻断;native Windows与完整DSH UI未由本机执行认证,merge/release授权另行保留。
动机
只安装python.org Python、系统命令叫python的Windows用户,需要直接完成已有LoopX插件初始化。
以前python可正常运行但python3别名不可用时,初始化报告缺少CLI并要求人工修环境;现在最后自动尝试python,读回CLI版本并完成原有skills安装。
正常构建打包产物在真实runFile、仅python可用的隔离PATH下完成初始化与skills读回,第二次保持幂等;相同base失败,坏的显式PYTHON_BIN仍失败。
不添加py -3、全局PATH别名或新安装器,不修改权限/Goal准入,不宣称本机执行了native Windows或新发布/完整DSH交互验收。
原issue #6704描述python.org Windows的python.exe可用而python3别名退出9009;这个平台事实来自原issue和作者证据,不冒称本机Windows观察。本次独立复核的是当前源码、正常tarball及真实子进程里的相同发现缺口。
改动思路
在既有插件发现与CLI IO边界末尾加入python,保留显式配置和较早候选;无需全局别名、并行安装器或通用launcher框架。
本PR修复已有初始化入口的bare-python缺口,正常打包产物已走真实子进程与skills读回;native Windows和新发布/DSH UI激活未由本机证据认证。
没有改成强制用户配置PYTHON_BIN,也不要求创建额外alias;原意图和授权已齐全时,合理路径是自动尝试已有支持解释器。最强反对理由是裸命令名可能在所有平台扩宽发现范围,因此必须放在原优先项之后,并绝不能吞掉显式配置错误。当前两个owner均保留这个顺序与既有版本检查。
发现解释器和发现已装CLI不是同一工作:前者还枚举数字版本名并验证Python,后者先看managed launcher和console,再尝试模块。只修一处会留下另一处初始化/后续调用失败;为两处短循环提取通用launcher框架反而增加维护面。既有Claude安装器_python_cmd也已用python3→python,说明复用既有解释器边界比新增host策略合适。
| 入口 | 当前选择顺序 | 不会发生的额外效果 |
|---|---|---|
| 自动Python发现 | python3、原数字降序版本、最后python | 不改全局PATH/alias |
| 自动CLI模块恢复 | managed/console优先,之后python3 -m、python -m | 不产生新的Goal权限 |
| 显式PYTHON_BIN/LOOPX_BIN | 仅原显式目标 | 错误时不静默换成别的解释器 |
这张表解释源码分支;下面真实打包探针验证初始化与失败读回,不把表本身作为执行证据。
具体改动
完整6路径、+132/-17已读:生产代码只动managed-runtime.ts候选和cli.ts模块fallback,三份既有测试扩展,README披露新末尾候选。单个贡献提交有DCO,没有新依赖、锁文件改动、持久化状态、CLI参数或配置开关。
pluginPythonCandidates保留显式PYTHON_BIN短路、原PATH数字版本扫描与去重,自动数组末尾加python。原先能用python3或数字版本的机器仍先选它们。resolveLoopXCommand保留显式LOOPX_BIN、managed launcher、console及原最低CLI版本;仅在自动模块fallback中按python3→python有限尝试。PYTHON_BIN存在时仍只有该目标;现有runFile的abort、timeout、错误分类与shell参数引用不变。- 原
initializeLoopX仍负责managed runtime、版本确认、安装及skills读回,没有另造第二安装流程。当前正常打包产物用真实runFile连到实际Python/LoopX模块,首次安装skills后第二次读回skillsChanged=false,表明成功不仅是mock返回版本字符串。
规范 packages/dsh-loopx-plugin/README.md,spec_revision: cd14893。先读该base的运行前提/managed isolation和原issue #6704,再审本PR新说明。Runtime-prerequisites implemented:支持的Python能进入原初始化;Managed-runtime-isolation implemented:managed launcher和显式配置仍权威,不修改全局环境。未把新README反过来当独立规范,也未为本修复新增py -3或全平台launcher的要求。
对主干的风险
当前frozen环境 218passed/13files,三个tsconfig的typecheck通过。将当前三份测试作为独立回归输入作用于immutablebase生产源码,得到 5failed/54passed,失败精确对应新增bare候选/初始化/模块fallback;当前全套218通过。这不是只比较两个聚合数字,更没有复制作者的Windows结果充当本机测试。
正常npm pack构建产物33个成员与对应build逐字一致,实际解包模块而非源码替身执行:隔离PATH仅python可用、python3不可用时,base在install_cli/missing失败,head返回实际CLI版本并读回skills;第二次保持幂等。给head显式坏PYTHON_BIN=python3则仍失败,不能偷偷用可用python。该不可用别名在POSIX退出49,仅模拟Windows问题的前提,不谎称运行9009或native Windows。真实子进程未mock,fresh pip下载/完整DSH UI activation未执行;标准package/runtime canary另已覆盖正常产品模块。
语义与 CI 对齐
这是一项已披露的自动发现默认扩展,不能叫新feature默认关闭。较早候选、显式优先、最低版本和类型错误保持;没有新枚举/持久化事实或共享控制面owner。README讲依赖与fallback,不增加模型指令或机器工作义务,安装/发现Python本身也不授予执行Goal的权限。advisory先于原生完整semantic;其不扫描package TS的限制已明确,typecheck及真实入口承担本次相应验证。
最初宿主fallback pnpm11.25自动准备曾改写本次review工作树的lock,首次原生canary的六个插件phase在runDepsStatusCheck、进入测试前失败;原输出保留,没有把通用“sandbox”诊断当真实权限故障或归咎产品。本次已保存自己生成的差异,将仅此lock恢复为精确HEAD,并按仓库CI约定使用 Node24/pnpm10.33、frozen lock。无TTY准备先失败一次后以CI=true完成,随后完整同组原生canary重新执行 4direct+16selected、0fail、0manual hold;不是只挑一次绿的单元测试。限定PATH只作用于该验证进程,宿主默认工具和共享CLI未升级,最终tracked tree干净、lock SHA与HEAD一致。
未查询、触发或等待远程CI。上述修复的是本地资格环境,不能声称产品“修复pnpm11”或真实Windows所有安装情况;原versioned-only模块fallback缺口也未借这次引入新支持承诺。
我的整体评价
long_horizon=improved、user_experience=improved:用户已有合格Python时能完成原初始化,重复进入稳定读回;少一次不必要的alias/路径手工准备,新增交互轮数为零。坏的明确选择仍给原错误,owner可修配置,不以自动fallback抹掉意图。
future-facing检查保留两个有不同IO职责的现有短循环,复用既有初始化和错误/版本owner,没有值得在本PR添加的框架或平行状态。当前六路径与一个可复现安装缺口相称;正常打包真实入口和显式失败对照足以批准此有界修复。native Windows、全DSH UI、fresh pip、新发布与合并权限仍各自保留。
English verdict: APPROVE - 5860512: the full six-file change adds bare python as the last automatic candidate in the existing discovery and module resolver, preserving explicit overrides, earlier precedence and version/error contracts. Frozen218 tests/typecheck, five matching baseline regression failures, a normal33-member package with real init/skills readback and explicit-bad-override refusal, plus the qualified4+16 native canary support the repair. Initial pnpm11 environment failures remain recorded; native Windows/fullDSH UI/fresh pip were not executed, and no merge or release is authorized.
Goal And Delivered Outcome
Outcome basis / optional anchor: issue [Bug]: DSH LoopX plugin cannot bootstrap on Windows - interpreter discovery only knows python3 #6704, reproduced on a native Windows host; the same interpreter-discovery defect class was already fixed for the Claude Code adapter in fix(claude-goal-mode): bake a launcher that actually runs Python into the Claude adapter #6229.
Goal/source and gap: the DSH LoopX plugin could not bootstrap LoopX on Windows.
pluginPythonCandidates(packages/dsh-loopx-plugin/src/managed-runtime.ts) hard-coded the POSIX spellingpython3and only discoveredpython3.<minor>names onPATH, andresolveLoopXCommand(packages/dsh-loopx-plugin/src/cli.ts) defaulted its documented-m loopx.climodule fallback topython3as well. A python.org Windows install registerspython.exeand nopython3name, and the host'spython3name is commonly the 0-byteWindowsAppsApp Execution Alias, which starts and exits 9009 without running Python. Every Windows DSH user who installs the plugin without a compatibleloopxconsole script already onPATH(the case the plugin exists for) therefore lost the documented one-step bootstrap: the automatic first-DSH-start initialization loggedstage=install_cli; kind=missing,/loopx-initansweredPython 3.11 or newer with pip could not be found, and the plugin never became ready, while Python 3.11 with pip was onPATH.Observable before and after, with the validation row that proves it: on native Windows with the real runner and the real
PATH,initializeLoopXwent fromFAILED stage=install_cli kind=missing message=Python 3.11 or newer with pip could not be foundto a completed bootstrap that installs the CLI and the DSH skills (validation rowsreal_entrypointandregression_parity).Issue/task and intended base: Fixes [Bug]: DSH LoopX plugin cannot bootstrap on Windows - interpreter discovery only knows python3 #6704; intended base
mainofloopx-project/loopx.Author Declaration
Implemented against
packages/dsh-loopx-plugin/README.md("Requirements are ... Python 3.11+ withpip... The initializer honors an explicitPYTHON_BIN; otherwise it triespython3, then discoverspython3.<minor>executables on the suppliedPATH", revision586051255d47a41dd00cb6daa060249ba43e5b5e), and the merged precedentloopx/claude_goal_mode/scripts/install.py_python_cmd()from fix(claude-goal-mode): bake a launcher that actually runs Python into the Claude adapter #6229.pipon WindowspluginPythonCandidates,resolveInstallPythontests/python-discovery.spec.ts> discovers a versioned Windows interpreter and ignores a bare-name alias stub;tests/init-command.spec.ts> finds the interpreter a python.org Windows PATH registers-m loopx.climodule fallback works on WindowsresolveLoopXCommandtests/cli.spec.ts> tries the python name a python.org Windows PATH registers for the module fallbackPYTHON_BINstays authoritative, with no fallbackconfiguredPluginPython,pythonNamestests/init-command.spec.ts> does not fall back from an explicit Python that cannot run pippython3keeps precedence where the name existstests/python-discovery.spec.ts> discovers unlisted minors in numeric order without executable suffix lookalikes(green at the tested revision; thetests/init-command.spec.tssibling that also exercises this is red on this Windows host for the disclosed POSIX fixture-path reason)npm run typecheckandnpm run smoke:peer-range. Deliberately left out: nopy -3launcher support, no CI lane change, no change to the LoopX version floor, and no rework of the pre-existing Windows-host failures in this suite.Scope And Continuation
resolveLoopXCommandbuilds its module fallback from bare names only, so a host that registers just the versionedpython3.12(and nopython3/python) still has no-m loopx.clifallback even though the candidate scan would have discovered that name; (2) nopy -3launcher support; (3).github/workflows/dsh-plugin.ymlstill runspnpm testand the init/runtime smokes on Linux only (if: runner.os == 'Linux'), which is why a Linux-only unit test could not have caught this.Validation
staticpassednpm run typecheck(tsc host + client + tests) at the tested revision, clean.unitpassedvitest runof the whole plugin suite on native Windows, two runs at the tested revision: 188 passed / 8 failed / 196 total across 13 files and 187 passed / 9 failed / 196. Pre-change baseline on the same host and toolchain, two runs: 182 passed / 14 failed and 183 passed / 13 failed. Every difference between those paired runs is the timing-flakytests/cli.spec.ts > waits for child close after timeout termination(expect(...).toBeGreaterThanOrEqual(350), observed at 337, 340, 347 and 412 ms), which flips independently of this change. The 5 tests that moved from failing to passing are exactly the regression tests added or updated here, and no failing test name was added; one pre-existing integration test changes failure mode instead of state (see Coverage and gaps).regression_paritypassedsrc/cli.tsandsrc/managed-runtime.tsrestored to the parent revision and nothing else changed,tests/init-command.spec.ts > finds the interpreter a python.org Windows PATH registersfails withLoopXInitError: Python 3.11 or newer with pip could not be found,tests/cli.spec.ts > tries the python name a python.org Windows PATH registers for the module fallbackfails withLoopXCliError: LoopX CLI 1.2.4 or newer is unavailable, and the three added/updatedtests/python-discovery.spec.tsassertions fail too. For> discovers a versioned Windows interpreter and ignores a bare-name alias stubthe parent revision receives["python3","python3.12.exe"], so the missing barepythonis what this fix adds there; that test's versioned-name discovery and alias-stub halves were already green on the parent and act as a future-regression guard (the expected list does track the fixturePATH), not as evidence for this fix. All pass at the tested revision.real_entrypointpassedrunFilerunner, realPATH: before the changepluginPythonCandidatesreturned["python3"]andinitializeLoopXreturnedFAILED stage=install_cli kind=missing; after the change it returns["python3","python"], probespython3rc=9009 (the alias) andpythonrc=0 for both the version and thepipprobe, and the whole bootstrap completes:initializeLoopX OK: {"cliVersion":"loopx 1.4.2","cliInstalled":true,"skillsInstalled":true,"skillsChanged":true,"hostSurface":"deepseek-harness-native"}. (An earlier attempt on the same host hit the plugin's 120 spipbound because the proxy served the 8.5 MB wheel at about 43 kB/s; the completion above is the same call against pip's warm cache, and the resolved version string is host- and cache-dependent.)integrationpasseddsh-plugin (ubuntu-latest)anddsh-plugin (windows-latest)lanes pass at the tested revision as well as at the previous head, together with theSign-off(DCO) and mergifySummarychecks. The plugin's profile/runtime smokes are Linux-only, and the registry install/remove smoke cannot complete on this host: the machine's npm proxy is configured for a loopback URL and refuses the smoke's local plugin registry, and the local pnpm is 9.15.0 rather than the qualified 10.33.0.real_backendnot_applicabletests/admission-closeout.integration.spec.tsresolves its interpreter withpluginPythonCandidates({ env: process.env }), so on this host it previously failed in about 0.2 s withThe real LoopX integration test requires Python 3.11+and now finds the realpythonand runs until its own 90 s bound. It fails on this host either way, that file runs only on the Linux CI lane, and the changed production path is not the cause. Untested path: a host that registers neitherpythonnorpython3(for example only thepylauncher);py -3support was deliberately not added.Frontend / Visual Evidence
Type of Change
LoopX Area
Technical Direction
Shared-authority RFC fixture impact
Boundary Checklist
.loopx/,.codex/goals/, and liveACTIVE_GOAL_STATE.md).python3 scripts/check_rfc_bilingual.py --base origin/main --head HEADpasses, or no paired RFC changed.none.Signed-off-bytrailer (git commit -s).