hrygo/heluo-forge--packages-forge-devops ↗★ 7
@heluo/forge-devops
Enterprise DevOps host plugin for Heluo Forge: policy-gated reads, fixed argv adapters and offline-testable delivery flow
インストール
npx -p @deepseek-ai/dsh dsh plugin --profile web add 'github:hrygo/heluo-forge#a2786f5e1152fb52c08cebeccaad7dd13dcbcb09&path:packages/forge-devops'ドキュメント
README 全文を読む ↗配置(配置页优先,环境变量兜底)
一句话:插件自己找 dop;只有找不到时才需要你指定位置。 四个配置项逐字段取第一个有值的层——配置页 > 环境变量 > 自动发现,页面对 dop 入口标出来源,覆盖关系也标出来(配置压过环境变量时挂「覆盖环境变量」),不静默替换。
配置页(设置 → 企业 DevOps)
进入路径两次点击:首页 → 左下「设置」→ 侧栏「企业 DevOps」。
页面上只有两项:dop 入口与超时。地址与事实来源不出现在页面上(怎么设见下一节)。
页面是状态而不是必填表单:命中自动发现时,两张入口卡默认只读,显示命中的可执行文件与来源(配置 / 环境变量 / 自动发现 / 未找到);用户正常情况下只读不填,只有未命中时才落进「填入路径」。
| 想做的事 | 操作 | 结果 |
|---|---|---|
| 覆盖为手动指定 | 点「改为手动指定」,粘贴 dop 可执行文件的完整地址(资源管理器里右键文件 →「复制文件地址」) | 保存时逐字段校验:文件存在、是普通文件(POSIX 还要执行位)。Windows 上不按扩展名拦截:.exe、无后缀 shim、.cmd / .ps1 都能存(见「能保存 ≠ 一定能跑起来」) |
| 回落到自动发现 | 点「重置为自动发现」,或把输入框清空,再点「保存」 | 该键从配置里删除,回落下一层(入口:环境变量 → 自动发现;超时:环境变量 → 缺省 20000);清空即回落,不必卸载重装 |
| 重新扫描 | 点「重新自动发现」 | 发现只在装配期跑一次;只有这个动作会重扫,工具调用永不触发扫描 |
| 保存 | 页脚「保存」 | 只提交页面上改动过的项;写入活动 profile 的补丁层(forge-devops 条目的 config: 段),页面没展示的键在补丁层里逐字保留;期间被别的窗口改过则提示「配置已被其它窗口改动 · 刷新后重试」,不覆盖对方改动 |
| 查看其它候选 | 展开「自动发现命中 · 另有 N 个候选」 | 多份安装时按 PATH 优先静默取首个,其余候选可展开查看,不自动选用 |
保存成功后读面立即按新配置重建(无需重启);写进 profile 补丁的值重启后仍然有效。发现结果不回写配置:换机器或改 PATH 后点「重新自动发现」即可跟随,页面不会把自动发现的等值写盘。当前 profile 没有挂载配置面(settings / config-editor)时,页面降级为只读并给出环境变量出口,而不是渲染一个存不进去的表单。
企业研发(设置 → 企业研发,r15 新增)
本包在设置页还有第二个分区:id devops-readiness、order 29。它只汇总本机可见性,页面顶部固定声明「本页只汇总本机可见性,不代表业务授权」。六行各读各的源,一行失败只影响自己:
| 行 | 事实来源 | 状态 |
|---|---|---|
| 企业身份 | GET /api/forge-iam/view 的 state | 已登录 / 未登录 / 登录中 / 过期 / 不可达 / 未知;未装该插件即「未安装」 |
| 公共参数 | 无 | 恒「未知」——尚无可核验的公共维护权限与接口 |
| 本机配置 | devops 与 gitee 快照里 origin === 'config' 的键名 | 列出键名,不列值 |
| DevOps | 本包快照的 ready 与 dopBin 的来源 | 已配置 / 未配置 / 未安装(不写"通过") |
| Gitee | gitee 快照的 ready | 已配置 / 未配置 / 未安装 |
| 业务写权限 | 无 | 恒「未知」——本页不判断授权 |
只有 DevOps 行可以检查:「检查 DevOps」打 GET /api/forge-devops/cli?refresh=1(唯一会重新扫描的动作,?refresh=1 在客户端只拼一次)。检查态六种:未检查 / 检查中 / 通过 / 失败 / 未知 / 已过期,并带基准短号与时间;子原因是 NO_CLI(未配置)、ENTRY_NOT_EXECUTABLE(不可执行)、ENDPOINT_UNREACHABLE(目标不可达)、POLICY_DENIED(只读被拒)。Gitee 行恒「未执行」并写明未获批准的只读探测本页不发起请求。检查不写配置。
保存回执与来源页脚(r15)
devops 分区保存后显示三行互不覆盖的回执:保存(已保存 / 未保存)、应用(运行时已应用 / 未应用 / 未知)、检查(未检查 / 上次检查时间)。应用这一行读 POST 成功体里的 applied:saveCliConfig 写成功后重算读面,只有运行时合并态里真的出现了新值才回 {ok:true};重建抛错或读面立不起来则降级并回 {ok:false, reason:'CLI_REBUILD_FAILED'}——此时"已保存"仍成立,但页面不会假装生效。页脚一行「分区由 @heluo/forge-devops 提供 · 读取于 」,版本与时刻都来自服务端快照(plugin / readAt),浏览器半不读 package.json。
配置项(配置页 / 环境变量 / 后端推导)
四个键名与代码同源(CLI_FIELDS,camelCase),页面标签、环境变量与工具失败文案指向同一句指引「设置 → 企业 DevOps」。四项按设置方式分三档:
- 2 项可在配置页设置:
dopBin、timeoutMs。 - 1 项仅环境变量与配置文件:
dopEndpoint——页面不渲染它,要设就写环境变量或活动 profile 补丁层的config:段。 - 1 项由后端推导:
sourceType——dopBin解析到可执行文件才推成enterprise(裸命令名dop这类默认值不算就绪),否则mock;显式配置或环境变量仍优先。
保存只写页面上的两项,其余键在补丁层里逐字保留(不展示的键不会被清空)。
| 配置项(camelCase) | 配置页 | 环境变量 | 缺省 | 说明 |
|---|---|---|---|---|
dopBin | dop 可执行文件 | FORGE_DEVOPS_DOP_BIN | 自动发现;三层都没有则未就绪 | 完整地址,或已在 PATH 内的可执行文件名(如 dop);判定只看「存在且是普通文件」,Windows 上不限扩展名 |
dopEndpoint | —(仅环境变量 / 配置文件) | FORGE_DEVOPS_DOP_ENDPOINT | 留空即不配置 | 绝对 http(s) 地址,地址里不能带用户名密码;凭据不进地址、不进配置页 |
sourceType | —(后端推导) | FORGE_DEVOPS_SOURCE_TYPE | 推导 | mock(本地模拟)/ enterprise(企业实测):dopBin 从配置 / 环境变量 / 自动发现解析到可执行文件才算 enterprise;报告按此分记事实来源 |
timeoutMs | 超时(毫秒) | FORGE_DEVOPS_TIMEOUT_MS | 20000 | 单次调用上限,取值 1000–600000 |
字段规则的唯一真源是 src/runtime-config.mjs 的 validateConfigField:环境变量层与宿主 loader 的配置校验直接调用它。浏览器半(client.js)不能 import 服务端模块,所以页面只对两项可编辑字段内联了一份子集校验(入口路径只判长度上界 4096,超时只判区间;不做任何后缀判断),存在性、是否目录与 POSIX 执行位一律由服务端在保存时判定(形态判定全仓只有一份,在 src/entry-form.mjs);两面的关系不是靠注释保证,而是由 test/client-rule-parity.test.mjs 的跨面矩阵用例守着——两项逐行对齐,页面没展示的两项断言"页面恒放过、服务端仍拒"(页面收窄不等于服务端放宽;R2-1 就是副本少了上界、失焦放行、保存才 422)。任一解析到的键非法即整包未就绪(CLI_CONFIG_INVALID),不回落下一层——填错的意图若被静默换成别的路径,用户会以为"我配置的那个在生效";页面上两项逐字段报错(找不到这个文件 / 这是目录 / 不是可直接执行的文件 / 路径过长(>4096)/ 超时越界),服务端 422 若点到页面上没有的键,原因落在页脚,不会为一个不存在的输入框聚焦。
自动发现规则
发现是只读的、有界的文件系统探测,零子进程,只在装配期与页面「重新自动发现」时跑:
- 名字:Windows 上按优先级试 6 个候选名——
dop.exe→dop(裸名)→dop.cmd→dop.ps1→dop.bat→dop.com(大小写不敏感);macOS / Linux 认无后缀的dop,并要求执行位。名字表的下标就是优先级:同一位置或不同目录同时存在原生.exe与脚本形态时,found[0]恒为.exe。 - 位置:
PATH的每一项;再加少量候选目录(Windows:%ProgramFiles%\{tool}、%ProgramFiles(x86)%\{tool}、%ProgramFiles%\heluo、%LOCALAPPDATA%\Programs\{tool}、%USERPROFILE%\.{tool}\bin;POSIX:/usr/local/bin、/opt/{tool}/bin)。不递归遍历。 - 预算:最多 200 个目录、250ms 截止(是上限而不是目标,正常机器只碰几个目录)。
- 不按扩展名拒收:只要存在且是普通文件(POSIX 另需执行位)就进候选,
rejected恒为空数组。于是候选里可能出现dop.cmd这类存得下但启动不了的入口,能不能真正跑起来交给运行期提示(见下一节),发现阶段不替用户预先否掉。真实文件名与路径在候选里照原样显示,不从显示值里删后缀。 - 只读、只纳入真实存在的文件:不执行文件、不解析其内容、不写任何东西;发现结果也不回写配置。
能保存 ≠ 一定能跑起来(Windows 包装脚本)
保存与发现都不再按扩展名拦截,但启动方式一点没松:唯一出口仍是 execFile + shell: false + 固定 argv(src/cli-runner.mjs),不引入 shell、不拼接命令行字符串。于是 Windows 上有两类「存得下、跑不起来」的入口:
- npm 生成的无后缀 shim(npm 的全局安装目录,Windows 上通常是
%APPDATA%\npm\dop;也可能是 Git Bash 版本):启动通常报ENOENT; .cmd/.ps1/.bat包装脚本:启动通常报EINVAL。
两者原因相同:这份调用方式要求直接 exec 一个可执行体,而脚本本身要靠 cmd.exe / PowerShell 解释——这是启动方式的限制,与路径写法无关,改后缀、补引号、换目录都不解决。所以第一次真正调用这条 CLI 时,失败信封里给的是可行动的提示:把配置改指该 CLI 的原生可执行文件(Windows 上即 .exe),或改用提供原生二进制的安装方式。该提示不含盘符、绝对路径与 endpoint(它要进工具输出与日志);贴地址前建议先在资源管理器里看一眼后缀。
ready 只表示「入口已解析」,不编码「已验证可运行」:页面上两项都绿的时候,仍可能在第一次调用时起不来。区分方法看失败信封——detail.spawnFailed: true 表示进程根本没起来(不是业务失败),读调用按失败记录且不重放。
找不到时
fail closed 语义不变,但文案改成人话:只读工具仍以 NO_READER 失败(原因码不加码),detail.reason 给细因(CLI_NOT_FOUND / CLI_CONFIG_INVALID)、detail.searched 给已查类别(配置 / 环境变量 / PATH / 候选目录)、detail.next 给页面入口;流程面仍可达,但只产出 blocked 卡且零子进程调用。整条信封不含盘符、绝对路径与平台地址——它要进工具输出与日志。
配置页(设置 → 企业 DevOps)
进入路径两次点击:首页 → 左下「设置」→ 侧栏「企业 DevOps」。
页面上只有两项:dop 入口与超时。地址与事实来源不出现在页面上(怎么设见下一节)。
页面是状态而不是必填表单:命中自动发现时,两张入口卡默认只读,显示命中的可执行文件与来源(配置 / 环境变量 / 自动发现 / 未找到);用户正常情况下只读不填,只有未命中时才落进「填入路径」。
| 想做的事 | 操作 | 结果 |
|---|---|---|
| 覆盖为手动指定 | 点「改为手动指定」,粘贴 dop 可执行文件的完整地址(资源管理器里右键文件 →「复制文件地址」) | 保存时逐字段校验:文件存在、是普通文件(POSIX 还要执行位)。Windows 上不按扩展名拦截:.exe、无后缀 shim、.cmd / .ps1 都能存(见「能保存 ≠ 一定能跑起来」) |
| 回落到自动发现 | 点「重置为自动发现」,或把输入框清空,再点「保存」 | 该键从配置里删除,回落下一层(入口:环境变量 → 自动发现;超时:环境变量 → 缺省 20000);清空即回落,不必卸载重装 |
| 重新扫描 | 点「重新自动发现」 | 发现只在装配期跑一次;只有这个动作会重扫,工具调用永不触发扫描 |
| 保存 | 页脚「保存」 | 只提交页面上改动过的项;写入活动 profile 的补丁层(forge-devops 条目的 config: 段),页面没展示的键在补丁层里逐字保留;期间被别的窗口改过则提示「配置已被其它窗口改动 · 刷新后重试」,不覆盖对方改动 |
| 查看其它候选 | 展开「自动发现命中 · 另有 N 个候选」 | 多份安装时按 PATH 优先静默取首个,其余候选可展开查看,不自动选用 |
保存成功后读面立即按新配置重建(无需重启);写进 profile 补丁的值重启后仍然有效。发现结果不回写配置:换机器或改 PATH 后点「重新自动发现」即可跟随,页面不会把自动发现的等值写盘。当前 profile 没有挂载配置面(settings / config-editor)时,页面降级为只读并给出环境变量出口,而不是渲染一个存不进去的表单。
配置项(配置页 / 环境变量 / 后端推导)
四个键名与代码同源(CLI_FIELDS,camelCase),页面标签、环境变量与工具失败文案指向同一句指引「设置 → 企业 DevOps」。四项按设置方式分三档:
- 2 项可在配置页设置:
dopBin、timeoutMs。 - 1 项仅环境变量与配置文件:
dopEndpoint——页面不渲染它,要设就写环境变量或活动 profile 补丁层的config:段。 - 1 项由后端推导:
sourceType——dopBin解析到可执行文件才推成enterprise(裸命令名dop这类默认值不算就绪),否则mock;显式配置或环境变量仍优先。
保存只写页面上的两项,其余键在补丁层里逐字保留(不展示的键不会被清空)。
| 配置项(camelCase) | 配置页 | 环境变量 | 缺省 | 说明 |
|---|---|---|---|---|
dopBin | dop 可执行文件 | FORGE_DEVOPS_DOP_BIN | 自动发现;三层都没有则未就绪 | 完整地址,或已在 PATH 内的可执行文件名(如 dop);判定只看「存在且是普通文件」,Windows 上不限扩展名 |
dopEndpoint | —(仅环境变量 / 配置文件) | FORGE_DEVOPS_DOP_ENDPOINT | 留空即不配置 | 绝对 http(s) 地址,地址里不能带用户名密码;凭据不进地址、不进配置页 |
sourceType | —(后端推导) | FORGE_DEVOPS_SOURCE_TYPE | 推导 | mock(本地模拟)/ enterprise(企业实测):dopBin 从配置 / 环境变量 / 自动发现解析到可执行文件才算 enterprise;报告按此分记事实来源 |
timeoutMs | 超时(毫秒) | FORGE_DEVOPS_TIMEOUT_MS | 20000 | 单次调用上限,取值 1000–600000 |
字段规则的唯一真源是 src/runtime-config.mjs 的 validateConfigField:环境变量层与宿主 loader 的配置校验直接调用它。浏览器半(client.js)不能 import 服务端模块,所以页面只对两项可编辑字段内联了一份子集校验(入口路径只判长度上界 4096,超时只判区间;不做任何后缀判断),存在性、是否目录与 POSIX 执行位一律由服务端在保存时判定(形态判定全仓只有一份,在 src/entry-form.mjs);两面的关系不是靠注释保证,而是由 test/client-rule-parity.test.mjs 的跨面矩阵用例守着——两项逐行对齐,页面没展示的两项断言"页面恒放过、服务端仍拒"(页面收窄不等于服务端放宽;R2-1 就是副本少了上界、失焦放行、保存才 422)。任一解析到的键非法即整包未就绪(CLI_CONFIG_INVALID),不回落下一层——填错的意图若被静默换成别的路径,用户会以为"我配置的那个在生效";页面上两项逐字段报错(找不到这个文件 / 这是目录 / 不是可直接执行的文件 / 路径过长(>4096)/ 超时越界),服务端 422 若点到页面上没有的键,原因落在页脚,不会为一个不存在的输入框聚焦。